mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-24 03:29:57 -07:00
FuriHal: UART refactoring (#3211)
* FuriHal: UART refactoring * ApiSymbols: add furi_record_destroy * FuriHal: cleanup serial API, add logging configuration in RTC * FuriHal: hide private part in _i header. Toolbox: cleanup value index. SystemSettings: logging device and baudrate. * FuriHal: RTC logging method documentation * Synchronize API Symbols * Furi: mark HEAP_PRINT_DEBUG as broken * FuriHal: furi_hal_serial, add custom IRQ func * Fix PR review issues * FuriHal: UART add reception DMA (#3220) * FuriHal: add DMA serial rx mode * usb_uart_bridge: switch to working with DMA * Sync api symbol versions * FuriHal: update serial docs and api * FuriHal: Selial added similar API for simple reception mode as with DMA * FuriHal: Update API target H18 * API: ver API H7 * FuriHal: Serial error processing * FuriHal: fix furi_hal_serial set baudrate * Sync api symbols * FuriHal: cleanup serial isr and various flag handling procedures * FuriHal: cleanup and simplify serial API * Debug: update UART Echo serial related flags * FuriHal: update serial API symbols naming * FuriHalSerial: various improvements and PR review fixes * FuriHal: proper ISR function signatures --------- Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com> Co-authored-by: hedger <hedger@users.noreply.github.com> Co-authored-by: SkorP <skorpionm@yandex.ru> Co-authored-by: Skorpionm <85568270+Skorpionm@users.noreply.github.com>
This commit is contained in:
@@ -33,7 +33,7 @@ void furi_hal_init() {
|
||||
furi_hal_mpu_init();
|
||||
furi_hal_clock_init();
|
||||
furi_hal_random_init();
|
||||
furi_hal_console_init();
|
||||
furi_hal_serial_control_init();
|
||||
furi_hal_rtc_init();
|
||||
furi_hal_interrupt_init();
|
||||
furi_hal_flash_init();
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
#include <furi_hal_console.h>
|
||||
#include <furi_hal_uart.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stm32wbxx_ll_gpio.h>
|
||||
#include <stm32wbxx_ll_usart.h>
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define TAG "FuriHalConsole"
|
||||
|
||||
#ifdef HEAP_PRINT_DEBUG
|
||||
#define CONSOLE_BAUDRATE 1843200
|
||||
#else
|
||||
#define CONSOLE_BAUDRATE 230400
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
bool alive;
|
||||
FuriHalConsoleTxCallback tx_callback;
|
||||
void* tx_callback_context;
|
||||
} FuriHalConsole;
|
||||
|
||||
FuriHalConsole furi_hal_console = {
|
||||
.alive = false,
|
||||
.tx_callback = NULL,
|
||||
.tx_callback_context = NULL,
|
||||
};
|
||||
|
||||
void furi_hal_console_init() {
|
||||
furi_hal_uart_init(FuriHalUartIdUSART1, CONSOLE_BAUDRATE);
|
||||
furi_hal_console.alive = true;
|
||||
}
|
||||
|
||||
void furi_hal_console_enable() {
|
||||
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, NULL, NULL);
|
||||
while(!LL_USART_IsActiveFlag_TC(USART1))
|
||||
;
|
||||
furi_hal_uart_set_br(FuriHalUartIdUSART1, CONSOLE_BAUDRATE);
|
||||
furi_hal_console.alive = true;
|
||||
}
|
||||
|
||||
void furi_hal_console_disable() {
|
||||
while(!LL_USART_IsActiveFlag_TC(USART1))
|
||||
;
|
||||
furi_hal_console.alive = false;
|
||||
}
|
||||
|
||||
void furi_hal_console_set_tx_callback(FuriHalConsoleTxCallback callback, void* context) {
|
||||
FURI_CRITICAL_ENTER();
|
||||
furi_hal_console.tx_callback = callback;
|
||||
furi_hal_console.tx_callback_context = context;
|
||||
FURI_CRITICAL_EXIT();
|
||||
}
|
||||
|
||||
void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size) {
|
||||
if(!furi_hal_console.alive) return;
|
||||
|
||||
FURI_CRITICAL_ENTER();
|
||||
// Transmit data
|
||||
|
||||
if(furi_hal_console.tx_callback) {
|
||||
furi_hal_console.tx_callback(buffer, buffer_size, furi_hal_console.tx_callback_context);
|
||||
}
|
||||
|
||||
furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)buffer, buffer_size);
|
||||
// Wait for TC flag to be raised for last char
|
||||
while(!LL_USART_IsActiveFlag_TC(USART1))
|
||||
;
|
||||
FURI_CRITICAL_EXIT();
|
||||
}
|
||||
|
||||
void furi_hal_console_tx_with_new_line(const uint8_t* buffer, size_t buffer_size) {
|
||||
if(!furi_hal_console.alive) return;
|
||||
|
||||
FURI_CRITICAL_ENTER();
|
||||
// Transmit data
|
||||
furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)buffer, buffer_size);
|
||||
// Transmit new line symbols
|
||||
furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)"\r\n", 2);
|
||||
// Wait for TC flag to be raised for last char
|
||||
while(!LL_USART_IsActiveFlag_TC(USART1))
|
||||
;
|
||||
FURI_CRITICAL_EXIT();
|
||||
}
|
||||
|
||||
void furi_hal_console_printf(const char format[], ...) {
|
||||
FuriString* string;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
string = furi_string_alloc_vprintf(format, args);
|
||||
va_end(args);
|
||||
furi_hal_console_tx((const uint8_t*)furi_string_get_cstr(string), furi_string_size(string));
|
||||
furi_string_free(string);
|
||||
}
|
||||
|
||||
void furi_hal_console_puts(const char* data) {
|
||||
furi_hal_console_tx((const uint8_t*)data, strlen(data));
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*FuriHalConsoleTxCallback)(const uint8_t* buffer, size_t size, void* context);
|
||||
|
||||
void furi_hal_console_init();
|
||||
|
||||
void furi_hal_console_enable();
|
||||
|
||||
void furi_hal_console_disable();
|
||||
|
||||
void furi_hal_console_set_tx_callback(FuriHalConsoleTxCallback callback, void* context);
|
||||
|
||||
void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size);
|
||||
|
||||
void furi_hal_console_tx_with_new_line(const uint8_t* buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
* Printf-like plain uart interface
|
||||
* @warning Will not work in ISR context
|
||||
* @param format
|
||||
* @param ...
|
||||
*/
|
||||
void furi_hal_console_printf(const char format[], ...) _ATTRIBUTE((__format__(__printf__, 1, 2)));
|
||||
|
||||
void furi_hal_console_puts(const char* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -59,6 +59,12 @@ const IRQn_Type furi_hal_interrupt_irqn[FuriHalInterruptIdMax] = {
|
||||
// LPTIMx
|
||||
[FuriHalInterruptIdLpTim1] = LPTIM1_IRQn,
|
||||
[FuriHalInterruptIdLpTim2] = LPTIM2_IRQn,
|
||||
|
||||
// UARTx
|
||||
[FuriHalInterruptIdUart1] = USART1_IRQn,
|
||||
|
||||
// LPUARTx
|
||||
[FuriHalInterruptIdLpUart1] = LPUART1_IRQn,
|
||||
};
|
||||
|
||||
__attribute__((always_inline)) static inline void
|
||||
@@ -329,3 +335,11 @@ void LPTIM1_IRQHandler() {
|
||||
void LPTIM2_IRQHandler() {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdLpTim2);
|
||||
}
|
||||
|
||||
void USART1_IRQHandler(void) {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdUart1);
|
||||
}
|
||||
|
||||
void LPUART1_IRQHandler(void) {
|
||||
furi_hal_interrupt_call(FuriHalInterruptIdLpUart1);
|
||||
}
|
||||
@@ -49,6 +49,12 @@ typedef enum {
|
||||
FuriHalInterruptIdLpTim1,
|
||||
FuriHalInterruptIdLpTim2,
|
||||
|
||||
//UARTx
|
||||
FuriHalInterruptIdUart1,
|
||||
|
||||
//LPUARTx
|
||||
FuriHalInterruptIdLpUart1,
|
||||
|
||||
// Service value
|
||||
FuriHalInterruptIdMax,
|
||||
} FuriHalInterruptId;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include <furi_hal_os.h>
|
||||
#include <furi_hal_clock.h>
|
||||
#include <furi_hal_console.h>
|
||||
#include <furi_hal_power.h>
|
||||
#include <furi_hal_gpio.h>
|
||||
#include <furi_hal_resources.h>
|
||||
@@ -208,8 +207,8 @@ void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) {
|
||||
|
||||
void vApplicationStackOverflowHook(TaskHandle_t xTask, char* pcTaskName) {
|
||||
UNUSED(xTask);
|
||||
furi_hal_console_puts("\r\n\r\n stack overflow in ");
|
||||
furi_hal_console_puts(pcTaskName);
|
||||
furi_hal_console_puts("\r\n\r\n");
|
||||
furi_log_puts("\r\n\r\n stack overflow in ");
|
||||
furi_log_puts(pcTaskName);
|
||||
furi_log_puts("\r\n\r\n");
|
||||
furi_crash("StackOverflow");
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <furi_hal_bt.h>
|
||||
#include <furi_hal_vibro.h>
|
||||
#include <furi_hal_resources.h>
|
||||
#include <furi_hal_uart.h>
|
||||
#include <furi_hal_serial_control.h>
|
||||
#include <furi_hal_rtc.h>
|
||||
#include <furi_hal_debug.h>
|
||||
|
||||
@@ -178,14 +178,12 @@ static inline void furi_hal_power_light_sleep() {
|
||||
|
||||
static inline void furi_hal_power_suspend_aux_periphs() {
|
||||
// Disable USART
|
||||
furi_hal_uart_suspend(FuriHalUartIdUSART1);
|
||||
furi_hal_uart_suspend(FuriHalUartIdLPUART1);
|
||||
furi_hal_serial_control_suspend();
|
||||
}
|
||||
|
||||
static inline void furi_hal_power_resume_aux_periphs() {
|
||||
// Re-enable USART
|
||||
furi_hal_uart_resume(FuriHalUartIdUSART1);
|
||||
furi_hal_uart_resume(FuriHalUartIdLPUART1);
|
||||
furi_hal_serial_control_resume();
|
||||
}
|
||||
|
||||
static inline void furi_hal_power_deep_sleep() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <furi_hal_rtc.h>
|
||||
#include <furi_hal_light.h>
|
||||
#include <furi_hal_debug.h>
|
||||
#include <furi_hal_serial_control.h>
|
||||
|
||||
#include <stm32wbxx_ll_pwr.h>
|
||||
#include <stm32wbxx_ll_bus.h>
|
||||
@@ -34,7 +35,9 @@ typedef struct {
|
||||
FuriHalRtcLocaleUnits locale_units : 1;
|
||||
FuriHalRtcLocaleTimeFormat locale_timeformat : 1;
|
||||
FuriHalRtcLocaleDateFormat locale_dateformat : 2;
|
||||
uint8_t reserved : 6;
|
||||
FuriHalRtcLogDevice log_device : 2;
|
||||
FuriHalRtcLogBaudRate log_baud_rate : 3;
|
||||
uint8_t reserved : 1;
|
||||
} SystemReg;
|
||||
|
||||
_Static_assert(sizeof(SystemReg) == 4, "SystemReg size mismatch");
|
||||
@@ -51,6 +54,24 @@ static const uint8_t furi_hal_rtc_days_per_month[2][FURI_HAL_RTC_MONTHS_COUNT] =
|
||||
|
||||
static const uint16_t furi_hal_rtc_days_per_year[] = {365, 366};
|
||||
|
||||
static const FuriHalSerialId furi_hal_rtc_log_devices[] = {
|
||||
[FuriHalRtcLogDeviceUsart] = FuriHalSerialIdUsart,
|
||||
[FuriHalRtcLogDeviceLpuart] = FuriHalSerialIdLpuart,
|
||||
[FuriHalRtcLogDeviceReserved] = FuriHalSerialIdMax,
|
||||
[FuriHalRtcLogDeviceNone] = FuriHalSerialIdMax,
|
||||
};
|
||||
|
||||
static const uint32_t furi_hal_rtc_log_baud_rates[] = {
|
||||
[FuriHalRtcLogBaudRate230400] = 230400,
|
||||
[FuriHalRtcLogBaudRate9600] = 9600,
|
||||
[FuriHalRtcLogBaudRate38400] = 38400,
|
||||
[FuriHalRtcLogBaudRate57600] = 57600,
|
||||
[FuriHalRtcLogBaudRate115200] = 115200,
|
||||
[FuriHalRtcLogBaudRate460800] = 460800,
|
||||
[FuriHalRtcLogBaudRate921600] = 921600,
|
||||
[FuriHalRtcLogBaudRate1843200] = 1843200,
|
||||
};
|
||||
|
||||
static void furi_hal_rtc_reset() {
|
||||
LL_RCC_ForceBackupDomainReset();
|
||||
LL_RCC_ReleaseBackupDomainReset();
|
||||
@@ -153,6 +174,9 @@ void furi_hal_rtc_init() {
|
||||
LL_RTC_Init(RTC, &RTC_InitStruct);
|
||||
|
||||
furi_log_set_level(furi_hal_rtc_get_log_level());
|
||||
furi_hal_serial_control_set_logging_config(
|
||||
furi_hal_rtc_log_devices[furi_hal_rtc_get_log_device()],
|
||||
furi_hal_rtc_log_baud_rates[furi_hal_rtc_get_log_baud_rate()]);
|
||||
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
@@ -199,6 +223,40 @@ uint8_t furi_hal_rtc_get_log_level() {
|
||||
return data->log_level;
|
||||
}
|
||||
|
||||
void furi_hal_rtc_set_log_device(FuriHalRtcLogDevice device) {
|
||||
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
|
||||
SystemReg* data = (SystemReg*)&data_reg;
|
||||
data->log_device = device;
|
||||
furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
|
||||
|
||||
furi_hal_serial_control_set_logging_config(
|
||||
furi_hal_rtc_log_devices[furi_hal_rtc_get_log_device()],
|
||||
furi_hal_rtc_log_baud_rates[furi_hal_rtc_get_log_baud_rate()]);
|
||||
}
|
||||
|
||||
FuriHalRtcLogDevice furi_hal_rtc_get_log_device() {
|
||||
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
|
||||
SystemReg* data = (SystemReg*)&data_reg;
|
||||
return data->log_device;
|
||||
}
|
||||
|
||||
void furi_hal_rtc_set_log_baud_rate(FuriHalRtcLogBaudRate baud_rate) {
|
||||
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
|
||||
SystemReg* data = (SystemReg*)&data_reg;
|
||||
data->log_baud_rate = baud_rate;
|
||||
furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
|
||||
|
||||
furi_hal_serial_control_set_logging_config(
|
||||
furi_hal_rtc_log_devices[furi_hal_rtc_get_log_device()],
|
||||
furi_hal_rtc_log_baud_rates[furi_hal_rtc_get_log_baud_rate()]);
|
||||
}
|
||||
|
||||
FuriHalRtcLogBaudRate furi_hal_rtc_get_log_baud_rate() {
|
||||
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
|
||||
SystemReg* data = (SystemReg*)&data_reg;
|
||||
return data->log_baud_rate;
|
||||
}
|
||||
|
||||
void furi_hal_rtc_set_flag(FuriHalRtcFlag flag) {
|
||||
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
|
||||
SystemReg* data = (SystemReg*)&data_reg;
|
||||
|
||||
341
targets/f7/furi_hal/furi_hal_rtc.h
Normal file
341
targets/f7/furi_hal/furi_hal_rtc.h
Normal file
@@ -0,0 +1,341 @@
|
||||
/**
|
||||
* @file furi_hal_rtc.h
|
||||
* Furi Hal RTC API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
// Time
|
||||
uint8_t hour; /**< Hour in 24H format: 0-23 */
|
||||
uint8_t minute; /**< Minute: 0-59 */
|
||||
uint8_t second; /**< Second: 0-59 */
|
||||
// Date
|
||||
uint8_t day; /**< Current day: 1-31 */
|
||||
uint8_t month; /**< Current month: 1-12 */
|
||||
uint16_t year; /**< Current year: 2000-2099 */
|
||||
uint8_t weekday; /**< Current weekday: 1-7 */
|
||||
} FuriHalRtcDateTime;
|
||||
|
||||
typedef enum {
|
||||
FuriHalRtcFlagDebug = (1 << 0),
|
||||
FuriHalRtcFlagStorageFormatInternal = (1 << 1),
|
||||
FuriHalRtcFlagLock = (1 << 2),
|
||||
FuriHalRtcFlagC2Update = (1 << 3),
|
||||
FuriHalRtcFlagHandOrient = (1 << 4),
|
||||
FuriHalRtcFlagLegacySleep = (1 << 5),
|
||||
FuriHalRtcFlagStealthMode = (1 << 6),
|
||||
FuriHalRtcFlagDetailedFilename = (1 << 7),
|
||||
} FuriHalRtcFlag;
|
||||
|
||||
typedef enum {
|
||||
FuriHalRtcBootModeNormal = 0, /**< Normal boot mode, default value */
|
||||
FuriHalRtcBootModeDfu, /**< Boot to DFU (MCU bootloader by ST) */
|
||||
FuriHalRtcBootModePreUpdate, /**< Boot to Update, pre update */
|
||||
FuriHalRtcBootModeUpdate, /**< Boot to Update, main */
|
||||
FuriHalRtcBootModePostUpdate, /**< Boot to Update, post update */
|
||||
} FuriHalRtcBootMode;
|
||||
|
||||
typedef enum {
|
||||
FuriHalRtcHeapTrackModeNone = 0, /**< Disable allocation tracking */
|
||||
FuriHalRtcHeapTrackModeMain, /**< Enable allocation tracking for main application thread */
|
||||
FuriHalRtcHeapTrackModeTree, /**< Enable allocation tracking for main and children application threads */
|
||||
FuriHalRtcHeapTrackModeAll, /**< Enable allocation tracking for all threads */
|
||||
} FuriHalRtcHeapTrackMode;
|
||||
|
||||
typedef enum {
|
||||
FuriHalRtcRegisterHeader, /**< RTC structure header */
|
||||
FuriHalRtcRegisterSystem, /**< Various system bits */
|
||||
FuriHalRtcRegisterVersion, /**< Pointer to Version */
|
||||
FuriHalRtcRegisterLfsFingerprint, /**< LFS geometry fingerprint */
|
||||
FuriHalRtcRegisterFaultData, /**< Pointer to last fault message */
|
||||
FuriHalRtcRegisterPinFails, /**< Failed pins count */
|
||||
/* Index of FS directory entry corresponding to FW update to be applied */
|
||||
FuriHalRtcRegisterUpdateFolderFSIndex,
|
||||
|
||||
FuriHalRtcRegisterMAX, /**< Service value, do not use */
|
||||
} FuriHalRtcRegister;
|
||||
|
||||
typedef enum {
|
||||
FuriHalRtcLocaleUnitsMetric = 0x0, /**< Metric measurement units */
|
||||
FuriHalRtcLocaleUnitsImperial = 0x1, /**< Imperial measurement units */
|
||||
} FuriHalRtcLocaleUnits;
|
||||
|
||||
typedef enum {
|
||||
FuriHalRtcLocaleTimeFormat24h = 0x0, /**< 24-hour format */
|
||||
FuriHalRtcLocaleTimeFormat12h = 0x1, /**< 12-hour format */
|
||||
} FuriHalRtcLocaleTimeFormat;
|
||||
|
||||
typedef enum {
|
||||
FuriHalRtcLocaleDateFormatDMY = 0x0, /**< Day/Month/Year */
|
||||
FuriHalRtcLocaleDateFormatMDY = 0x1, /**< Month/Day/Year */
|
||||
FuriHalRtcLocaleDateFormatYMD = 0x2, /**< Year/Month/Day */
|
||||
} FuriHalRtcLocaleDateFormat;
|
||||
|
||||
typedef enum {
|
||||
FuriHalRtcLogDeviceUsart = 0x0, /**< Default: USART */
|
||||
FuriHalRtcLogDeviceLpuart = 0x1, /**< Default: LPUART */
|
||||
FuriHalRtcLogDeviceReserved = 0x2, /**< Reserved for future use */
|
||||
FuriHalRtcLogDeviceNone = 0x3, /**< None, disable serial logging */
|
||||
} FuriHalRtcLogDevice;
|
||||
|
||||
typedef enum {
|
||||
FuriHalRtcLogBaudRate230400 = 0x0, /**< 230400 baud */
|
||||
FuriHalRtcLogBaudRate9600 = 0x1, /**< 9600 baud */
|
||||
FuriHalRtcLogBaudRate38400 = 0x2, /**< 38400 baud */
|
||||
FuriHalRtcLogBaudRate57600 = 0x3, /**< 57600 baud */
|
||||
FuriHalRtcLogBaudRate115200 = 0x4, /**< 115200 baud */
|
||||
FuriHalRtcLogBaudRate460800 = 0x5, /**< 460800 baud */
|
||||
FuriHalRtcLogBaudRate921600 = 0x6, /**< 921600 baud */
|
||||
FuriHalRtcLogBaudRate1843200 = 0x7, /**< 1843200 baud */
|
||||
} FuriHalRtcLogBaudRate;
|
||||
|
||||
/** Early initialization */
|
||||
void furi_hal_rtc_init_early(void);
|
||||
|
||||
/** Early de-initialization */
|
||||
void furi_hal_rtc_deinit_early(void);
|
||||
|
||||
/** Initialize RTC subsystem */
|
||||
void furi_hal_rtc_init(void);
|
||||
|
||||
/** Force sync shadow registers */
|
||||
void furi_hal_rtc_sync_shadow(void);
|
||||
|
||||
/** Reset ALL RTC registers content */
|
||||
void furi_hal_rtc_reset_registers();
|
||||
|
||||
/** Get RTC register content
|
||||
*
|
||||
* @param[in] reg The register identifier
|
||||
*
|
||||
* @return content of the register
|
||||
*/
|
||||
uint32_t furi_hal_rtc_get_register(FuriHalRtcRegister reg);
|
||||
|
||||
/** Set register content
|
||||
*
|
||||
* @param[in] reg The register identifier
|
||||
* @param[in] value The value to store into register
|
||||
*/
|
||||
void furi_hal_rtc_set_register(FuriHalRtcRegister reg, uint32_t value);
|
||||
|
||||
/** Set Log Level value
|
||||
*
|
||||
* @param[in] level The level to store
|
||||
*/
|
||||
void furi_hal_rtc_set_log_level(uint8_t level);
|
||||
|
||||
/** Get Log Level value
|
||||
*
|
||||
* @return The Log Level value
|
||||
*/
|
||||
uint8_t furi_hal_rtc_get_log_level(void);
|
||||
|
||||
/** Set logging device
|
||||
*
|
||||
* @param[in] device The device
|
||||
*/
|
||||
void furi_hal_rtc_set_log_device(FuriHalRtcLogDevice device);
|
||||
|
||||
/** Get logging device
|
||||
*
|
||||
* @return The furi hal rtc log device.
|
||||
*/
|
||||
FuriHalRtcLogDevice furi_hal_rtc_get_log_device(void);
|
||||
|
||||
/** Set logging baud rate
|
||||
*
|
||||
* @param[in] baud_rate The baud rate
|
||||
*/
|
||||
void furi_hal_rtc_set_log_baud_rate(FuriHalRtcLogBaudRate baud_rate);
|
||||
|
||||
/** Get logging baud rate
|
||||
*
|
||||
* @return The furi hal rtc log baud rate.
|
||||
*/
|
||||
FuriHalRtcLogBaudRate furi_hal_rtc_get_log_baud_rate(void);
|
||||
|
||||
/** Set RTC Flag
|
||||
*
|
||||
* @param[in] flag The flag to set
|
||||
*/
|
||||
void furi_hal_rtc_set_flag(FuriHalRtcFlag flag);
|
||||
|
||||
/** Reset RTC Flag
|
||||
*
|
||||
* @param[in] flag The flag to reset
|
||||
*/
|
||||
void furi_hal_rtc_reset_flag(FuriHalRtcFlag flag);
|
||||
|
||||
/** Check if RTC Flag is set
|
||||
*
|
||||
* @param[in] flag The flag to check
|
||||
*
|
||||
* @return true if set
|
||||
*/
|
||||
bool furi_hal_rtc_is_flag_set(FuriHalRtcFlag flag);
|
||||
|
||||
/** Set RTC boot mode
|
||||
*
|
||||
* @param[in] mode The mode to set
|
||||
*/
|
||||
void furi_hal_rtc_set_boot_mode(FuriHalRtcBootMode mode);
|
||||
|
||||
/** Get RTC boot mode
|
||||
*
|
||||
* @return The RTC boot mode.
|
||||
*/
|
||||
FuriHalRtcBootMode furi_hal_rtc_get_boot_mode(void);
|
||||
|
||||
/** Set Heap Track mode
|
||||
*
|
||||
* @param[in] mode The mode to set
|
||||
*/
|
||||
void furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackMode mode);
|
||||
|
||||
/** Get RTC Heap Track mode
|
||||
*
|
||||
* @return The RTC heap track mode.
|
||||
*/
|
||||
FuriHalRtcHeapTrackMode furi_hal_rtc_get_heap_track_mode(void);
|
||||
|
||||
/** Set locale units
|
||||
*
|
||||
* @param[in] mode The RTC Locale Units
|
||||
*/
|
||||
void furi_hal_rtc_set_locale_units(FuriHalRtcLocaleUnits value);
|
||||
|
||||
/** Get RTC Locale Units
|
||||
*
|
||||
* @return The RTC Locale Units.
|
||||
*/
|
||||
FuriHalRtcLocaleUnits furi_hal_rtc_get_locale_units(void);
|
||||
|
||||
/** Set RTC Locale Time Format
|
||||
*
|
||||
* @param[in] value The RTC Locale Time Format
|
||||
*/
|
||||
void furi_hal_rtc_set_locale_timeformat(FuriHalRtcLocaleTimeFormat value);
|
||||
|
||||
/** Get RTC Locale Time Format
|
||||
*
|
||||
* @return The RTC Locale Time Format.
|
||||
*/
|
||||
FuriHalRtcLocaleTimeFormat furi_hal_rtc_get_locale_timeformat(void);
|
||||
|
||||
/** Set RTC Locale Date Format
|
||||
*
|
||||
* @param[in] value The RTC Locale Date Format
|
||||
*/
|
||||
void furi_hal_rtc_set_locale_dateformat(FuriHalRtcLocaleDateFormat value);
|
||||
|
||||
/** Get RTC Locale Date Format
|
||||
*
|
||||
* @return The RTC Locale Date Format
|
||||
*/
|
||||
FuriHalRtcLocaleDateFormat furi_hal_rtc_get_locale_dateformat(void);
|
||||
|
||||
/** Set RTC Date Time
|
||||
*
|
||||
* @param datetime The date time to set
|
||||
*/
|
||||
void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime);
|
||||
|
||||
/** Get RTC Date Time
|
||||
*
|
||||
* @param datetime The datetime
|
||||
*/
|
||||
void furi_hal_rtc_get_datetime(FuriHalRtcDateTime* datetime);
|
||||
|
||||
/** Validate Date Time
|
||||
*
|
||||
* @param datetime The datetime to validate
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool furi_hal_rtc_validate_datetime(FuriHalRtcDateTime* datetime);
|
||||
|
||||
/** Set RTC Fault Data
|
||||
*
|
||||
* @param[in] value The value
|
||||
*/
|
||||
void furi_hal_rtc_set_fault_data(uint32_t value);
|
||||
|
||||
/** Get RTC Fault Data
|
||||
*
|
||||
* @return RTC Fault Data value
|
||||
*/
|
||||
uint32_t furi_hal_rtc_get_fault_data(void);
|
||||
|
||||
/** Set Pin Fails count
|
||||
*
|
||||
* @param[in] value The Pin Fails count
|
||||
*/
|
||||
void furi_hal_rtc_set_pin_fails(uint32_t value);
|
||||
|
||||
/** Get Pin Fails count
|
||||
*
|
||||
* @return Pin Fails Count
|
||||
*/
|
||||
uint32_t furi_hal_rtc_get_pin_fails(void);
|
||||
|
||||
/** Get UNIX Timestamp
|
||||
*
|
||||
* @return Unix Timestamp in seconds from UNIX epoch start
|
||||
*/
|
||||
uint32_t furi_hal_rtc_get_timestamp(void);
|
||||
|
||||
/** Convert DateTime to UNIX timestamp
|
||||
*
|
||||
* @warning Mind timezone when perform conversion
|
||||
*
|
||||
* @param datetime The datetime (UTC)
|
||||
*
|
||||
* @return UNIX Timestamp in seconds from UNIX epoch start
|
||||
*/
|
||||
uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime);
|
||||
|
||||
/** Convert UNIX timestamp to DateTime
|
||||
*
|
||||
* @warning Mind timezone when perform conversion
|
||||
*
|
||||
* @param[in] timestamp UNIX Timestamp in seconds from UNIX epoch start
|
||||
* @param[out] datetime The datetime (UTC)
|
||||
*/
|
||||
void furi_hal_rtc_timestamp_to_datetime(uint32_t timestamp, FuriHalRtcDateTime* datetime);
|
||||
|
||||
/** Gets the number of days in the year according to the Gregorian calendar.
|
||||
*
|
||||
* @param year Input year.
|
||||
*
|
||||
* @return number of days in `year`.
|
||||
*/
|
||||
uint16_t furi_hal_rtc_get_days_per_year(uint16_t year);
|
||||
|
||||
/** Check if a year a leap year in the Gregorian calendar.
|
||||
*
|
||||
* @param year Input year.
|
||||
*
|
||||
* @return true if `year` is a leap year.
|
||||
*/
|
||||
bool furi_hal_rtc_is_leap_year(uint16_t year);
|
||||
|
||||
/** Get the number of days in the month.
|
||||
*
|
||||
* @param leap_year true to calculate based on leap years
|
||||
* @param month month to check, where 1 = January
|
||||
* @return the number of days in the month
|
||||
*/
|
||||
uint8_t furi_hal_rtc_get_days_per_month(bool leap_year, uint8_t month);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
838
targets/f7/furi_hal/furi_hal_serial.c
Normal file
838
targets/f7/furi_hal/furi_hal_serial.c
Normal file
@@ -0,0 +1,838 @@
|
||||
#include <furi_hal_serial.h>
|
||||
#include "furi_hal_serial_types_i.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stm32wbxx_ll_lpuart.h>
|
||||
#include <stm32wbxx_ll_usart.h>
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <stm32wbxx_ll_dma.h>
|
||||
#include <furi_hal_resources.h>
|
||||
#include <furi_hal_interrupt.h>
|
||||
#include <furi_hal_bus.h>
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define FURI_HAL_SERIAL_USART_OVERSAMPLING LL_USART_OVERSAMPLING_16
|
||||
|
||||
#define FURI_HAL_SERIAL_USART_DMA_INSTANCE (DMA1)
|
||||
#define FURI_HAL_SERIAL_USART_DMA_CHANNEL (LL_DMA_CHANNEL_6)
|
||||
|
||||
#define FURI_HAL_SERIAL_LPUART_DMA_INSTANCE (DMA1)
|
||||
#define FURI_HAL_SERIAL_LPUART_DMA_CHANNEL (LL_DMA_CHANNEL_7)
|
||||
|
||||
typedef struct {
|
||||
uint8_t* buffer_rx_ptr;
|
||||
size_t buffer_rx_index_write;
|
||||
size_t buffer_rx_index_read;
|
||||
bool enabled;
|
||||
FuriHalSerialHandle* handle;
|
||||
FuriHalSerialAsyncRxCallback rx_byte_callback;
|
||||
FuriHalSerialDmaRxCallback rx_dma_callback;
|
||||
void* context;
|
||||
} FuriHalSerial;
|
||||
|
||||
static FuriHalSerial furi_hal_serial[FuriHalSerialIdMax] = {0};
|
||||
|
||||
static size_t furi_hal_serial_dma_bytes_available(FuriHalSerialId ch);
|
||||
|
||||
static void furi_hal_serial_async_rx_configure(
|
||||
FuriHalSerialHandle* handle,
|
||||
FuriHalSerialAsyncRxCallback callback,
|
||||
void* context);
|
||||
|
||||
static void furi_hal_serial_usart_irq_callback(void* context) {
|
||||
UNUSED(context);
|
||||
|
||||
FuriHalSerialRxEvent event = 0;
|
||||
// Notification flags
|
||||
if(USART1->ISR & USART_ISR_RXNE_RXFNE) {
|
||||
event |= FuriHalSerialRxEventData;
|
||||
}
|
||||
if(USART1->ISR & USART_ISR_IDLE) {
|
||||
USART1->ICR = USART_ICR_IDLECF;
|
||||
event |= FuriHalSerialRxEventIdle;
|
||||
}
|
||||
// Error flags
|
||||
if(USART1->ISR & USART_ISR_ORE) {
|
||||
USART1->ICR = USART_ICR_ORECF;
|
||||
event |= FuriHalSerialRxEventOverrunError;
|
||||
}
|
||||
if(USART1->ISR & USART_ISR_NE) {
|
||||
USART1->ICR = USART_ICR_NECF;
|
||||
event |= FuriHalSerialRxEventNoiseError;
|
||||
}
|
||||
if(USART1->ISR & USART_ISR_FE) {
|
||||
USART1->ICR = USART_ICR_FECF;
|
||||
event |= FuriHalSerialRxEventFrameError;
|
||||
}
|
||||
if(USART1->ISR & USART_ISR_PE) {
|
||||
USART1->ICR = USART_ICR_PECF;
|
||||
event |= FuriHalSerialRxEventFrameError;
|
||||
}
|
||||
|
||||
if(furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr == NULL) {
|
||||
if(furi_hal_serial[FuriHalSerialIdUsart].rx_byte_callback) {
|
||||
furi_hal_serial[FuriHalSerialIdUsart].rx_byte_callback(
|
||||
furi_hal_serial[FuriHalSerialIdUsart].handle,
|
||||
event,
|
||||
furi_hal_serial[FuriHalSerialIdUsart].context);
|
||||
}
|
||||
} else {
|
||||
if(furi_hal_serial[FuriHalSerialIdUsart].rx_dma_callback) {
|
||||
furi_hal_serial[FuriHalSerialIdUsart].rx_dma_callback(
|
||||
furi_hal_serial[FuriHalSerialIdUsart].handle,
|
||||
event,
|
||||
furi_hal_serial_dma_bytes_available(FuriHalSerialIdUsart),
|
||||
furi_hal_serial[FuriHalSerialIdUsart].context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void furi_hal_serial_usart_dma_rx_isr(void* context) {
|
||||
UNUSED(context);
|
||||
#if FURI_HAL_SERIAL_USART_DMA_CHANNEL == LL_DMA_CHANNEL_6
|
||||
if(LL_DMA_IsActiveFlag_HT6(FURI_HAL_SERIAL_USART_DMA_INSTANCE)) {
|
||||
LL_DMA_ClearFlag_HT6(FURI_HAL_SERIAL_USART_DMA_INSTANCE);
|
||||
furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_index_write =
|
||||
FURI_HAL_SERIAL_DMA_BUFFER_SIZE -
|
||||
LL_DMA_GetDataLength(
|
||||
FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
|
||||
if((furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_index_read >
|
||||
furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_index_write) ||
|
||||
(furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_index_read <
|
||||
FURI_HAL_SERIAL_DMA_BUFFER_SIZE / 4)) {
|
||||
if(furi_hal_serial[FuriHalSerialIdUsart].rx_dma_callback) {
|
||||
furi_hal_serial[FuriHalSerialIdUsart].rx_dma_callback(
|
||||
furi_hal_serial[FuriHalSerialIdUsart].handle,
|
||||
FuriHalSerialRxEventData,
|
||||
furi_hal_serial_dma_bytes_available(FuriHalSerialIdUsart),
|
||||
furi_hal_serial[FuriHalSerialIdUsart].context);
|
||||
}
|
||||
}
|
||||
|
||||
} else if(LL_DMA_IsActiveFlag_TC6(FURI_HAL_SERIAL_USART_DMA_INSTANCE)) {
|
||||
LL_DMA_ClearFlag_TC6(FURI_HAL_SERIAL_USART_DMA_INSTANCE);
|
||||
|
||||
if(furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_index_read <
|
||||
FURI_HAL_SERIAL_DMA_BUFFER_SIZE * 3 / 4) {
|
||||
if(furi_hal_serial[FuriHalSerialIdUsart].rx_dma_callback) {
|
||||
furi_hal_serial[FuriHalSerialIdUsart].rx_dma_callback(
|
||||
furi_hal_serial[FuriHalSerialIdUsart].handle,
|
||||
FuriHalSerialRxEventData,
|
||||
furi_hal_serial_dma_bytes_available(FuriHalSerialIdUsart),
|
||||
furi_hal_serial[FuriHalSerialIdUsart].context);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error Update this code. Would you kindly?
|
||||
#endif
|
||||
}
|
||||
|
||||
static void furi_hal_serial_usart_init_dma_rx(void) {
|
||||
/* USART1_RX_DMA Init */
|
||||
furi_check(furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr == NULL);
|
||||
furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_index_write = 0;
|
||||
furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_index_read = 0;
|
||||
furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr = malloc(FURI_HAL_SERIAL_DMA_BUFFER_SIZE);
|
||||
LL_DMA_SetMemoryAddress(
|
||||
FURI_HAL_SERIAL_USART_DMA_INSTANCE,
|
||||
FURI_HAL_SERIAL_USART_DMA_CHANNEL,
|
||||
(uint32_t)furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr);
|
||||
LL_DMA_SetPeriphAddress(
|
||||
FURI_HAL_SERIAL_USART_DMA_INSTANCE,
|
||||
FURI_HAL_SERIAL_USART_DMA_CHANNEL,
|
||||
(uint32_t) & (USART1->RDR));
|
||||
|
||||
LL_DMA_ConfigTransfer(
|
||||
FURI_HAL_SERIAL_USART_DMA_INSTANCE,
|
||||
FURI_HAL_SERIAL_USART_DMA_CHANNEL,
|
||||
LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
|
||||
LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE |
|
||||
LL_DMA_PRIORITY_HIGH);
|
||||
LL_DMA_SetDataLength(
|
||||
FURI_HAL_SERIAL_USART_DMA_INSTANCE,
|
||||
FURI_HAL_SERIAL_USART_DMA_CHANNEL,
|
||||
FURI_HAL_SERIAL_DMA_BUFFER_SIZE);
|
||||
LL_DMA_SetPeriphRequest(
|
||||
FURI_HAL_SERIAL_USART_DMA_INSTANCE,
|
||||
FURI_HAL_SERIAL_USART_DMA_CHANNEL,
|
||||
LL_DMAMUX_REQ_USART1_RX);
|
||||
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch6, furi_hal_serial_usart_dma_rx_isr, NULL);
|
||||
|
||||
#if FURI_HAL_SERIAL_USART_DMA_CHANNEL == LL_DMA_CHANNEL_6
|
||||
if(LL_DMA_IsActiveFlag_HT6(FURI_HAL_SERIAL_USART_DMA_INSTANCE))
|
||||
LL_DMA_ClearFlag_HT6(FURI_HAL_SERIAL_USART_DMA_INSTANCE);
|
||||
if(LL_DMA_IsActiveFlag_TC6(FURI_HAL_SERIAL_USART_DMA_INSTANCE))
|
||||
LL_DMA_ClearFlag_TC6(FURI_HAL_SERIAL_USART_DMA_INSTANCE);
|
||||
if(LL_DMA_IsActiveFlag_TE6(FURI_HAL_SERIAL_USART_DMA_INSTANCE))
|
||||
LL_DMA_ClearFlag_TE6(FURI_HAL_SERIAL_USART_DMA_INSTANCE);
|
||||
#else
|
||||
#error Update this code. Would you kindly?
|
||||
#endif
|
||||
|
||||
LL_DMA_EnableIT_TC(FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
|
||||
LL_DMA_EnableIT_HT(FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
|
||||
|
||||
LL_DMA_EnableChannel(FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
|
||||
LL_USART_EnableDMAReq_RX(USART1);
|
||||
|
||||
LL_USART_EnableIT_IDLE(USART1);
|
||||
}
|
||||
|
||||
static void furi_hal_serial_usart_deinit_dma_rx(void) {
|
||||
if(furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr != NULL) {
|
||||
LL_DMA_DisableChannel(
|
||||
FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
|
||||
LL_USART_DisableDMAReq_RX(USART1);
|
||||
|
||||
LL_USART_DisableIT_IDLE(USART1);
|
||||
LL_DMA_DisableIT_TC(FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
|
||||
LL_DMA_DisableIT_HT(FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
|
||||
|
||||
LL_DMA_ClearFlag_TC6(FURI_HAL_SERIAL_USART_DMA_INSTANCE);
|
||||
LL_DMA_ClearFlag_HT6(FURI_HAL_SERIAL_USART_DMA_INSTANCE);
|
||||
|
||||
LL_DMA_DeInit(FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch6, NULL, NULL);
|
||||
free(furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr);
|
||||
furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void furi_hal_serial_usart_init(FuriHalSerialHandle* handle, uint32_t baud) {
|
||||
furi_hal_bus_enable(FuriHalBusUSART1);
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
|
||||
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_usart_tx,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullUp,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn7USART1);
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_usart_rx,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullUp,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn7USART1);
|
||||
|
||||
LL_USART_InitTypeDef USART_InitStruct;
|
||||
USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
|
||||
USART_InitStruct.BaudRate = baud;
|
||||
USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
|
||||
USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
|
||||
USART_InitStruct.Parity = LL_USART_PARITY_NONE;
|
||||
USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
|
||||
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
|
||||
USART_InitStruct.OverSampling = FURI_HAL_SERIAL_USART_OVERSAMPLING;
|
||||
LL_USART_Init(USART1, &USART_InitStruct);
|
||||
LL_USART_EnableFIFO(USART1);
|
||||
LL_USART_ConfigAsyncMode(USART1);
|
||||
|
||||
LL_USART_Enable(USART1);
|
||||
|
||||
while(!LL_USART_IsActiveFlag_TEACK(USART1) || !LL_USART_IsActiveFlag_REACK(USART1))
|
||||
;
|
||||
|
||||
furi_hal_serial_set_br(handle, baud);
|
||||
LL_USART_DisableIT_ERROR(USART1);
|
||||
furi_hal_serial[handle->id].enabled = true;
|
||||
}
|
||||
|
||||
static void furi_hal_serial_lpuart_irq_callback(void* context) {
|
||||
UNUSED(context);
|
||||
|
||||
FuriHalSerialRxEvent event = 0;
|
||||
// Notification flags
|
||||
if(LPUART1->ISR & USART_ISR_RXNE_RXFNE) {
|
||||
event |= FuriHalSerialRxEventData;
|
||||
}
|
||||
if(LPUART1->ISR & USART_ISR_IDLE) {
|
||||
LPUART1->ICR = USART_ICR_IDLECF;
|
||||
event |= FuriHalSerialRxEventIdle;
|
||||
}
|
||||
// Error flags
|
||||
if(LPUART1->ISR & USART_ISR_ORE) {
|
||||
LPUART1->ICR = USART_ICR_ORECF;
|
||||
event |= FuriHalSerialRxEventOverrunError;
|
||||
}
|
||||
if(LPUART1->ISR & USART_ISR_NE) {
|
||||
LPUART1->ICR = USART_ICR_NECF;
|
||||
event |= FuriHalSerialRxEventNoiseError;
|
||||
}
|
||||
if(LPUART1->ISR & USART_ISR_FE) {
|
||||
LPUART1->ICR = USART_ICR_FECF;
|
||||
event |= FuriHalSerialRxEventFrameError;
|
||||
}
|
||||
if(LPUART1->ISR & USART_ISR_PE) {
|
||||
LPUART1->ICR = USART_ICR_PECF;
|
||||
event |= FuriHalSerialRxEventFrameError;
|
||||
}
|
||||
|
||||
if(furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr == NULL) {
|
||||
if(furi_hal_serial[FuriHalSerialIdLpuart].rx_byte_callback) {
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].rx_byte_callback(
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].handle,
|
||||
event,
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].context);
|
||||
}
|
||||
} else {
|
||||
if(furi_hal_serial[FuriHalSerialIdLpuart].rx_dma_callback) {
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].rx_dma_callback(
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].handle,
|
||||
event,
|
||||
furi_hal_serial_dma_bytes_available(FuriHalSerialIdLpuart),
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void furi_hal_serial_lpuart_dma_rx_isr(void* context) {
|
||||
UNUSED(context);
|
||||
#if FURI_HAL_SERIAL_LPUART_DMA_CHANNEL == LL_DMA_CHANNEL_7
|
||||
if(LL_DMA_IsActiveFlag_HT7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE)) {
|
||||
LL_DMA_ClearFlag_HT7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE);
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_index_write =
|
||||
FURI_HAL_SERIAL_DMA_BUFFER_SIZE -
|
||||
LL_DMA_GetDataLength(
|
||||
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
|
||||
if((furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_index_read >
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_index_write) ||
|
||||
(furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_index_read <
|
||||
FURI_HAL_SERIAL_DMA_BUFFER_SIZE / 4)) {
|
||||
if(furi_hal_serial[FuriHalSerialIdLpuart].rx_dma_callback) {
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].rx_dma_callback(
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].handle,
|
||||
FuriHalSerialRxEventData,
|
||||
furi_hal_serial_dma_bytes_available(FuriHalSerialIdLpuart),
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].context);
|
||||
}
|
||||
}
|
||||
|
||||
} else if(LL_DMA_IsActiveFlag_TC7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE)) {
|
||||
LL_DMA_ClearFlag_TC7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE);
|
||||
|
||||
if(furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_index_read <
|
||||
FURI_HAL_SERIAL_DMA_BUFFER_SIZE * 3 / 4) {
|
||||
if(furi_hal_serial[FuriHalSerialIdLpuart].rx_dma_callback) {
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].rx_dma_callback(
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].handle,
|
||||
FuriHalSerialRxEventData,
|
||||
furi_hal_serial_dma_bytes_available(FuriHalSerialIdLpuart),
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].context);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error Update this code. Would you kindly?
|
||||
#endif
|
||||
}
|
||||
|
||||
static void furi_hal_serial_lpuart_init_dma_rx(void) {
|
||||
/* LPUART1_RX_DMA Init */
|
||||
furi_check(furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr == NULL);
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_index_write = 0;
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_index_read = 0;
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr = malloc(FURI_HAL_SERIAL_DMA_BUFFER_SIZE);
|
||||
LL_DMA_SetMemoryAddress(
|
||||
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE,
|
||||
FURI_HAL_SERIAL_LPUART_DMA_CHANNEL,
|
||||
(uint32_t)furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr);
|
||||
LL_DMA_SetPeriphAddress(
|
||||
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE,
|
||||
FURI_HAL_SERIAL_LPUART_DMA_CHANNEL,
|
||||
(uint32_t) & (LPUART1->RDR));
|
||||
|
||||
LL_DMA_ConfigTransfer(
|
||||
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE,
|
||||
FURI_HAL_SERIAL_LPUART_DMA_CHANNEL,
|
||||
LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
|
||||
LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE |
|
||||
LL_DMA_PRIORITY_HIGH);
|
||||
LL_DMA_SetDataLength(
|
||||
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE,
|
||||
FURI_HAL_SERIAL_LPUART_DMA_CHANNEL,
|
||||
FURI_HAL_SERIAL_DMA_BUFFER_SIZE);
|
||||
LL_DMA_SetPeriphRequest(
|
||||
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE,
|
||||
FURI_HAL_SERIAL_LPUART_DMA_CHANNEL,
|
||||
LL_DMAMUX_REQ_LPUART1_RX);
|
||||
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch7, furi_hal_serial_lpuart_dma_rx_isr, NULL);
|
||||
|
||||
#if FURI_HAL_SERIAL_LPUART_DMA_CHANNEL == LL_DMA_CHANNEL_7
|
||||
if(LL_DMA_IsActiveFlag_HT7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE))
|
||||
LL_DMA_ClearFlag_HT7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE);
|
||||
if(LL_DMA_IsActiveFlag_TC7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE))
|
||||
LL_DMA_ClearFlag_TC7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE);
|
||||
if(LL_DMA_IsActiveFlag_TE7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE))
|
||||
LL_DMA_ClearFlag_TE7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE);
|
||||
#else
|
||||
#error Update this code. Would you kindly?
|
||||
#endif
|
||||
|
||||
LL_DMA_EnableIT_TC(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
|
||||
LL_DMA_EnableIT_HT(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
|
||||
|
||||
LL_DMA_EnableChannel(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
|
||||
LL_USART_EnableDMAReq_RX(LPUART1);
|
||||
|
||||
LL_USART_EnableIT_IDLE(LPUART1);
|
||||
}
|
||||
|
||||
static void furi_hal_serial_lpuart_deinit_dma_rx(void) {
|
||||
if(furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr != NULL) {
|
||||
LL_DMA_DisableChannel(
|
||||
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
|
||||
LL_USART_DisableDMAReq_RX(LPUART1);
|
||||
|
||||
LL_USART_DisableIT_IDLE(LPUART1);
|
||||
LL_DMA_DisableIT_TC(
|
||||
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
|
||||
LL_DMA_DisableIT_HT(
|
||||
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
|
||||
|
||||
LL_DMA_ClearFlag_TC7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE);
|
||||
LL_DMA_ClearFlag_HT7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE);
|
||||
|
||||
LL_DMA_DeInit(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch7, NULL, NULL);
|
||||
free(furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr);
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void furi_hal_serial_lpuart_init(FuriHalSerialHandle* handle, uint32_t baud) {
|
||||
furi_hal_bus_enable(FuriHalBusLPUART1);
|
||||
LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1);
|
||||
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_ext_pc0,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullUp,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn8LPUART1);
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_ext_pc1,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullUp,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn8LPUART1);
|
||||
|
||||
LL_LPUART_InitTypeDef LPUART_InitStruct;
|
||||
LPUART_InitStruct.PrescalerValue = LL_LPUART_PRESCALER_DIV1;
|
||||
LPUART_InitStruct.BaudRate = baud;
|
||||
LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;
|
||||
LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;
|
||||
LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;
|
||||
LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;
|
||||
LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;
|
||||
LL_LPUART_Init(LPUART1, &LPUART_InitStruct);
|
||||
LL_LPUART_EnableFIFO(LPUART1);
|
||||
|
||||
LL_LPUART_Enable(LPUART1);
|
||||
|
||||
while(!LL_LPUART_IsActiveFlag_TEACK(LPUART1) || !LL_LPUART_IsActiveFlag_REACK(LPUART1))
|
||||
;
|
||||
|
||||
furi_hal_serial_set_br(handle, baud);
|
||||
LL_LPUART_DisableIT_ERROR(LPUART1);
|
||||
furi_hal_serial[handle->id].enabled = true;
|
||||
}
|
||||
|
||||
void furi_hal_serial_init(FuriHalSerialHandle* handle, uint32_t baud) {
|
||||
furi_check(handle);
|
||||
if(handle->id == FuriHalSerialIdLpuart) {
|
||||
furi_hal_serial_lpuart_init(handle, baud);
|
||||
} else if(handle->id == FuriHalSerialIdUsart) {
|
||||
furi_hal_serial_usart_init(handle, baud);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t furi_hal_serial_get_prescaler(FuriHalSerialHandle* handle, uint32_t baud) {
|
||||
uint32_t uartclk = LL_RCC_GetUSARTClockFreq(LL_RCC_USART1_CLKSOURCE);
|
||||
uint32_t divisor = (uartclk / baud);
|
||||
uint32_t prescaler = 0;
|
||||
if(handle->id == FuriHalSerialIdUsart) {
|
||||
if(FURI_HAL_SERIAL_USART_OVERSAMPLING == LL_USART_OVERSAMPLING_16) {
|
||||
divisor = (divisor / 16) >> 12;
|
||||
} else {
|
||||
divisor = (divisor / 8) >> 12;
|
||||
}
|
||||
if(divisor < 1) {
|
||||
prescaler = LL_USART_PRESCALER_DIV1;
|
||||
} else if(divisor < 2) {
|
||||
prescaler = LL_USART_PRESCALER_DIV2;
|
||||
} else if(divisor < 4) {
|
||||
prescaler = LL_USART_PRESCALER_DIV4;
|
||||
} else if(divisor < 6) {
|
||||
prescaler = LL_USART_PRESCALER_DIV6;
|
||||
} else if(divisor < 8) {
|
||||
prescaler = LL_USART_PRESCALER_DIV8;
|
||||
} else if(divisor < 10) {
|
||||
prescaler = LL_USART_PRESCALER_DIV10;
|
||||
} else if(divisor < 12) {
|
||||
prescaler = LL_USART_PRESCALER_DIV12;
|
||||
} else if(divisor < 16) {
|
||||
prescaler = LL_USART_PRESCALER_DIV16;
|
||||
} else if(divisor < 32) {
|
||||
prescaler = LL_USART_PRESCALER_DIV32;
|
||||
} else if(divisor < 64) {
|
||||
prescaler = LL_USART_PRESCALER_DIV64;
|
||||
} else if(divisor < 128) {
|
||||
prescaler = LL_USART_PRESCALER_DIV128;
|
||||
} else {
|
||||
prescaler = LL_USART_PRESCALER_DIV256;
|
||||
}
|
||||
} else if(handle->id == FuriHalSerialIdLpuart) {
|
||||
divisor >>= 12;
|
||||
if(divisor < 1) {
|
||||
prescaler = LL_LPUART_PRESCALER_DIV1;
|
||||
} else if(divisor < 2) {
|
||||
prescaler = LL_LPUART_PRESCALER_DIV2;
|
||||
} else if(divisor < 4) {
|
||||
prescaler = LL_LPUART_PRESCALER_DIV4;
|
||||
} else if(divisor < 6) {
|
||||
prescaler = LL_LPUART_PRESCALER_DIV6;
|
||||
} else if(divisor < 8) {
|
||||
prescaler = LL_LPUART_PRESCALER_DIV8;
|
||||
} else if(divisor < 10) {
|
||||
prescaler = LL_LPUART_PRESCALER_DIV10;
|
||||
} else if(divisor < 12) {
|
||||
prescaler = LL_LPUART_PRESCALER_DIV12;
|
||||
} else if(divisor < 16) {
|
||||
prescaler = LL_LPUART_PRESCALER_DIV16;
|
||||
} else if(divisor < 32) {
|
||||
prescaler = LL_LPUART_PRESCALER_DIV32;
|
||||
} else if(divisor < 64) {
|
||||
prescaler = LL_LPUART_PRESCALER_DIV64;
|
||||
} else if(divisor < 128) {
|
||||
prescaler = LL_LPUART_PRESCALER_DIV128;
|
||||
} else {
|
||||
prescaler = LL_LPUART_PRESCALER_DIV256;
|
||||
}
|
||||
}
|
||||
|
||||
return prescaler;
|
||||
}
|
||||
|
||||
void furi_hal_serial_set_br(FuriHalSerialHandle* handle, uint32_t baud) {
|
||||
furi_check(handle);
|
||||
uint32_t prescaler = furi_hal_serial_get_prescaler(handle, baud);
|
||||
if(handle->id == FuriHalSerialIdUsart) {
|
||||
if(LL_USART_IsEnabled(USART1)) {
|
||||
// Wait for transfer complete flag
|
||||
while(!LL_USART_IsActiveFlag_TC(USART1))
|
||||
;
|
||||
LL_USART_Disable(USART1);
|
||||
uint32_t uartclk = LL_RCC_GetUSARTClockFreq(LL_RCC_USART1_CLKSOURCE);
|
||||
LL_USART_SetPrescaler(USART1, prescaler);
|
||||
LL_USART_SetBaudRate(
|
||||
USART1, uartclk, prescaler, FURI_HAL_SERIAL_USART_OVERSAMPLING, baud);
|
||||
LL_USART_Enable(USART1);
|
||||
}
|
||||
} else if(handle->id == FuriHalSerialIdLpuart) {
|
||||
if(LL_LPUART_IsEnabled(LPUART1)) {
|
||||
// Wait for transfer complete flag
|
||||
while(!LL_LPUART_IsActiveFlag_TC(LPUART1))
|
||||
;
|
||||
LL_LPUART_Disable(LPUART1);
|
||||
uint32_t uartclk = LL_RCC_GetLPUARTClockFreq(LL_RCC_LPUART1_CLKSOURCE);
|
||||
LL_LPUART_SetPrescaler(LPUART1, prescaler);
|
||||
LL_LPUART_SetBaudRate(LPUART1, uartclk, prescaler, baud);
|
||||
LL_LPUART_Enable(LPUART1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_serial_deinit(FuriHalSerialHandle* handle) {
|
||||
furi_check(handle);
|
||||
furi_hal_serial_async_rx_configure(handle, NULL, NULL);
|
||||
if(handle->id == FuriHalSerialIdUsart) {
|
||||
if(furi_hal_bus_is_enabled(FuriHalBusUSART1)) {
|
||||
furi_hal_bus_disable(FuriHalBusUSART1);
|
||||
}
|
||||
if(LL_USART_IsEnabled(USART1)) {
|
||||
LL_USART_Disable(USART1);
|
||||
}
|
||||
furi_hal_serial_usart_deinit_dma_rx();
|
||||
furi_hal_gpio_init(&gpio_usart_tx, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_usart_rx, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
} else if(handle->id == FuriHalSerialIdLpuart) {
|
||||
if(furi_hal_bus_is_enabled(FuriHalBusLPUART1)) {
|
||||
furi_hal_bus_disable(FuriHalBusLPUART1);
|
||||
}
|
||||
if(LL_LPUART_IsEnabled(LPUART1)) {
|
||||
LL_LPUART_Disable(LPUART1);
|
||||
}
|
||||
furi_hal_serial_lpuart_deinit_dma_rx();
|
||||
furi_hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
} else {
|
||||
furi_crash();
|
||||
}
|
||||
furi_hal_serial[handle->id].enabled = false;
|
||||
}
|
||||
|
||||
void furi_hal_serial_suspend(FuriHalSerialHandle* handle) {
|
||||
furi_check(handle);
|
||||
if(handle->id == FuriHalSerialIdLpuart && LL_LPUART_IsEnabled(LPUART1)) {
|
||||
LL_LPUART_Disable(LPUART1);
|
||||
} else if(handle->id == FuriHalSerialIdUsart && LL_USART_IsEnabled(USART1)) {
|
||||
LL_USART_Disable(USART1);
|
||||
}
|
||||
furi_hal_serial[handle->id].enabled = false;
|
||||
}
|
||||
|
||||
void furi_hal_serial_resume(FuriHalSerialHandle* handle) {
|
||||
furi_check(handle);
|
||||
if(!furi_hal_serial[handle->id].enabled) {
|
||||
if(handle->id == FuriHalSerialIdLpuart) {
|
||||
LL_LPUART_Enable(LPUART1);
|
||||
} else if(handle->id == FuriHalSerialIdUsart) {
|
||||
LL_USART_Enable(USART1);
|
||||
}
|
||||
furi_hal_serial[handle->id].enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_serial_tx(FuriHalSerialHandle* handle, const uint8_t* buffer, size_t buffer_size) {
|
||||
furi_check(handle);
|
||||
if(handle->id == FuriHalSerialIdUsart) {
|
||||
if(LL_USART_IsEnabled(USART1) == 0) return;
|
||||
|
||||
while(buffer_size > 0) {
|
||||
while(!LL_USART_IsActiveFlag_TXE(USART1))
|
||||
;
|
||||
|
||||
LL_USART_TransmitData8(USART1, *buffer);
|
||||
buffer++;
|
||||
buffer_size--;
|
||||
}
|
||||
|
||||
} else if(handle->id == FuriHalSerialIdLpuart) {
|
||||
if(LL_LPUART_IsEnabled(LPUART1) == 0) return;
|
||||
|
||||
while(buffer_size > 0) {
|
||||
while(!LL_LPUART_IsActiveFlag_TXE(LPUART1))
|
||||
;
|
||||
|
||||
LL_LPUART_TransmitData8(LPUART1, *buffer);
|
||||
|
||||
buffer++;
|
||||
buffer_size--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_serial_tx_wait_complete(FuriHalSerialHandle* handle) {
|
||||
furi_check(handle);
|
||||
if(handle->id == FuriHalSerialIdUsart) {
|
||||
if(LL_USART_IsEnabled(USART1) == 0) return;
|
||||
|
||||
while(!LL_USART_IsActiveFlag_TC(USART1))
|
||||
;
|
||||
} else if(handle->id == FuriHalSerialIdLpuart) {
|
||||
if(LL_LPUART_IsEnabled(LPUART1) == 0) return;
|
||||
|
||||
while(!LL_LPUART_IsActiveFlag_TC(LPUART1))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static void furi_hal_serial_event_init(FuriHalSerialHandle* handle, bool report_errors) {
|
||||
if(handle->id == FuriHalSerialIdUsart) {
|
||||
LL_USART_EnableIT_IDLE(USART1);
|
||||
} else if(handle->id == FuriHalSerialIdLpuart) {
|
||||
LL_LPUART_EnableIT_IDLE(LPUART1);
|
||||
}
|
||||
|
||||
if(report_errors) {
|
||||
if(handle->id == FuriHalSerialIdUsart) {
|
||||
LL_USART_EnableIT_ERROR(USART1);
|
||||
} else if(handle->id == FuriHalSerialIdLpuart) {
|
||||
LL_LPUART_EnableIT_ERROR(LPUART1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void furi_hal_serial_event_deinit(FuriHalSerialHandle* handle) {
|
||||
if(handle->id == FuriHalSerialIdUsart) {
|
||||
if(LL_USART_IsEnabledIT_IDLE(USART1)) LL_USART_DisableIT_IDLE(USART1);
|
||||
if(LL_USART_IsEnabledIT_ERROR(USART1)) LL_USART_DisableIT_ERROR(USART1);
|
||||
} else if(handle->id == FuriHalSerialIdLpuart) {
|
||||
if(LL_LPUART_IsEnabledIT_IDLE(LPUART1)) LL_LPUART_DisableIT_IDLE(LPUART1);
|
||||
if(LL_LPUART_IsEnabledIT_ERROR(LPUART1)) LL_LPUART_DisableIT_ERROR(LPUART1);
|
||||
}
|
||||
}
|
||||
|
||||
static void furi_hal_serial_async_rx_configure(
|
||||
FuriHalSerialHandle* handle,
|
||||
FuriHalSerialAsyncRxCallback callback,
|
||||
void* context) {
|
||||
if(handle->id == FuriHalSerialIdUsart) {
|
||||
if(callback) {
|
||||
furi_hal_serial_usart_deinit_dma_rx();
|
||||
furi_hal_interrupt_set_isr(
|
||||
FuriHalInterruptIdUart1, furi_hal_serial_usart_irq_callback, NULL);
|
||||
LL_USART_EnableIT_RXNE_RXFNE(USART1);
|
||||
} else {
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdUart1, NULL, NULL);
|
||||
furi_hal_serial_usart_deinit_dma_rx();
|
||||
LL_USART_DisableIT_RXNE_RXFNE(USART1);
|
||||
}
|
||||
} else if(handle->id == FuriHalSerialIdLpuart) {
|
||||
if(callback) {
|
||||
furi_hal_serial_lpuart_deinit_dma_rx();
|
||||
furi_hal_interrupt_set_isr(
|
||||
FuriHalInterruptIdLpUart1, furi_hal_serial_lpuart_irq_callback, NULL);
|
||||
LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1);
|
||||
} else {
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdLpUart1, NULL, NULL);
|
||||
furi_hal_serial_lpuart_deinit_dma_rx();
|
||||
LL_LPUART_DisableIT_RXNE_RXFNE(LPUART1);
|
||||
}
|
||||
}
|
||||
furi_hal_serial[handle->id].rx_byte_callback = callback;
|
||||
furi_hal_serial[handle->id].handle = handle;
|
||||
furi_hal_serial[handle->id].rx_dma_callback = NULL;
|
||||
furi_hal_serial[handle->id].context = context;
|
||||
}
|
||||
|
||||
void furi_hal_serial_async_rx_start(
|
||||
FuriHalSerialHandle* handle,
|
||||
FuriHalSerialAsyncRxCallback callback,
|
||||
void* context,
|
||||
bool report_errors) {
|
||||
furi_check(handle);
|
||||
furi_check(callback);
|
||||
|
||||
furi_hal_serial_event_init(handle, report_errors);
|
||||
furi_hal_serial_async_rx_configure(handle, callback, context);
|
||||
|
||||
// Assign different functions to different UARTs
|
||||
furi_check(
|
||||
furi_hal_serial[FuriHalSerialIdUsart].rx_byte_callback !=
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].rx_byte_callback);
|
||||
}
|
||||
|
||||
void furi_hal_serial_async_rx_stop(FuriHalSerialHandle* handle) {
|
||||
furi_check(handle);
|
||||
furi_hal_serial_event_deinit(handle);
|
||||
furi_hal_serial_async_rx_configure(handle, NULL, NULL);
|
||||
}
|
||||
|
||||
uint8_t furi_hal_serial_async_rx(FuriHalSerialHandle* handle) {
|
||||
furi_check(FURI_IS_IRQ_MODE());
|
||||
furi_assert(handle->id < FuriHalSerialIdMax);
|
||||
|
||||
if(handle->id == FuriHalSerialIdUsart) {
|
||||
return LL_USART_ReceiveData8(USART1);
|
||||
}
|
||||
return LL_LPUART_ReceiveData8(LPUART1);
|
||||
}
|
||||
|
||||
static size_t furi_hal_serial_dma_bytes_available(FuriHalSerialId ch) {
|
||||
size_t dma_remain = 0;
|
||||
if(ch == FuriHalSerialIdUsart) {
|
||||
dma_remain = LL_DMA_GetDataLength(
|
||||
FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
|
||||
} else if(ch == FuriHalSerialIdLpuart) {
|
||||
dma_remain = LL_DMA_GetDataLength(
|
||||
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
|
||||
} else {
|
||||
furi_crash();
|
||||
}
|
||||
|
||||
furi_hal_serial[ch].buffer_rx_index_write = FURI_HAL_SERIAL_DMA_BUFFER_SIZE - dma_remain;
|
||||
if(furi_hal_serial[ch].buffer_rx_index_write >= furi_hal_serial[ch].buffer_rx_index_read) {
|
||||
return furi_hal_serial[ch].buffer_rx_index_write -
|
||||
furi_hal_serial[ch].buffer_rx_index_read;
|
||||
} else {
|
||||
return FURI_HAL_SERIAL_DMA_BUFFER_SIZE - furi_hal_serial[ch].buffer_rx_index_read +
|
||||
furi_hal_serial[ch].buffer_rx_index_write;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t furi_hal_serial_dma_rx_read_byte(FuriHalSerialHandle* handle) {
|
||||
uint8_t data = 0;
|
||||
data =
|
||||
furi_hal_serial[handle->id].buffer_rx_ptr[furi_hal_serial[handle->id].buffer_rx_index_read];
|
||||
furi_hal_serial[handle->id].buffer_rx_index_read++;
|
||||
if(furi_hal_serial[handle->id].buffer_rx_index_read >= FURI_HAL_SERIAL_DMA_BUFFER_SIZE) {
|
||||
furi_hal_serial[handle->id].buffer_rx_index_read = 0;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
size_t furi_hal_serial_dma_rx(FuriHalSerialHandle* handle, uint8_t* data, size_t len) {
|
||||
furi_check(FURI_IS_IRQ_MODE());
|
||||
furi_assert(furi_hal_serial[handle->id].buffer_rx_ptr != NULL);
|
||||
size_t i = 0;
|
||||
size_t available = furi_hal_serial_dma_bytes_available(handle->id);
|
||||
if(available < len) {
|
||||
len = available;
|
||||
}
|
||||
for(i = 0; i < len; i++) {
|
||||
data[i] = furi_hal_serial_dma_rx_read_byte(handle);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static void furi_hal_serial_dma_configure(
|
||||
FuriHalSerialHandle* handle,
|
||||
FuriHalSerialDmaRxCallback callback,
|
||||
void* context) {
|
||||
furi_check(handle);
|
||||
|
||||
if(handle->id == FuriHalSerialIdUsart) {
|
||||
if(callback) {
|
||||
furi_hal_serial_usart_init_dma_rx();
|
||||
furi_hal_interrupt_set_isr(
|
||||
FuriHalInterruptIdUart1, furi_hal_serial_usart_irq_callback, NULL);
|
||||
} else {
|
||||
LL_USART_DisableIT_RXNE_RXFNE(USART1);
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdUart1, NULL, NULL);
|
||||
furi_hal_serial_usart_deinit_dma_rx();
|
||||
}
|
||||
} else if(handle->id == FuriHalSerialIdLpuart) {
|
||||
if(callback) {
|
||||
furi_hal_serial_lpuart_init_dma_rx();
|
||||
furi_hal_interrupt_set_isr(
|
||||
FuriHalInterruptIdLpUart1, furi_hal_serial_lpuart_irq_callback, NULL);
|
||||
} else {
|
||||
LL_LPUART_DisableIT_RXNE_RXFNE(LPUART1);
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdLpUart1, NULL, NULL);
|
||||
furi_hal_serial_lpuart_deinit_dma_rx();
|
||||
}
|
||||
}
|
||||
furi_hal_serial[handle->id].rx_byte_callback = NULL;
|
||||
furi_hal_serial[handle->id].handle = handle;
|
||||
furi_hal_serial[handle->id].rx_dma_callback = callback;
|
||||
furi_hal_serial[handle->id].context = context;
|
||||
}
|
||||
|
||||
void furi_hal_serial_dma_rx_start(
|
||||
FuriHalSerialHandle* handle,
|
||||
FuriHalSerialDmaRxCallback callback,
|
||||
void* context,
|
||||
bool report_errors) {
|
||||
furi_check(handle);
|
||||
furi_check(callback);
|
||||
|
||||
furi_hal_serial_event_init(handle, report_errors);
|
||||
furi_hal_serial_dma_configure(handle, callback, context);
|
||||
|
||||
// Assign different functions to different UARTs
|
||||
furi_check(
|
||||
furi_hal_serial[FuriHalSerialIdUsart].rx_dma_callback !=
|
||||
furi_hal_serial[FuriHalSerialIdLpuart].rx_dma_callback);
|
||||
}
|
||||
|
||||
void furi_hal_serial_dma_rx_stop(FuriHalSerialHandle* handle) {
|
||||
furi_check(handle);
|
||||
furi_hal_serial_event_deinit(handle);
|
||||
furi_hal_serial_dma_configure(handle, NULL, NULL);
|
||||
}
|
||||
189
targets/f7/furi_hal/furi_hal_serial.h
Normal file
189
targets/f7/furi_hal/furi_hal_serial.h
Normal file
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* @file furi_hal_serial.h
|
||||
*
|
||||
* Serial HAL API
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "furi_hal_serial_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Initialize Serial
|
||||
*
|
||||
* Configures GPIO, configures and enables transceiver.
|
||||
*
|
||||
* @param handle Serial handle
|
||||
* @param baud baud rate
|
||||
*/
|
||||
void furi_hal_serial_init(FuriHalSerialHandle* handle, uint32_t baud);
|
||||
|
||||
/** De-initialize Serial
|
||||
*
|
||||
* Configures GPIO to analog, clears callback and callback context, disables
|
||||
* hardware
|
||||
*
|
||||
* @param handle Serial handle
|
||||
*/
|
||||
void furi_hal_serial_deinit(FuriHalSerialHandle* handle);
|
||||
|
||||
/** Suspend operation
|
||||
*
|
||||
* Suspend hardware, settings and callbacks are preserved
|
||||
*
|
||||
* @param handle Serial handle
|
||||
*/
|
||||
void furi_hal_serial_suspend(FuriHalSerialHandle* handle);
|
||||
|
||||
/** Resume operation
|
||||
*
|
||||
* Resumes hardware from suspended state
|
||||
*
|
||||
* @param handle Serial handle
|
||||
*/
|
||||
void furi_hal_serial_resume(FuriHalSerialHandle* handle);
|
||||
|
||||
/** Changes baud rate
|
||||
*
|
||||
* @param handle Serial handle
|
||||
* @param baud baud rate
|
||||
*/
|
||||
void furi_hal_serial_set_br(FuriHalSerialHandle* handle, uint32_t baud);
|
||||
|
||||
/** Transmits data in semi-blocking mode
|
||||
*
|
||||
* Fills transmission pipe with data, returns as soon as all bytes from buffer
|
||||
* are in the pipe.
|
||||
*
|
||||
* Real transmission will be completed later. Use
|
||||
* `furi_hal_serial_tx_wait_complete` to wait for completion if you need it.
|
||||
*
|
||||
* @param handle Serial handle
|
||||
* @param buffer data
|
||||
* @param buffer_size data size (in bytes)
|
||||
*/
|
||||
void furi_hal_serial_tx(FuriHalSerialHandle* handle, const uint8_t* buffer, size_t buffer_size);
|
||||
|
||||
/** Wait until transmission is completed
|
||||
*
|
||||
* Ensures that all data has been sent.
|
||||
*
|
||||
* @param handle Serial handle
|
||||
*/
|
||||
void furi_hal_serial_tx_wait_complete(FuriHalSerialHandle* handle);
|
||||
|
||||
/** Serial RX events */
|
||||
typedef enum {
|
||||
FuriHalSerialRxEventData = (1 << 0), /**< Data: new data available */
|
||||
FuriHalSerialRxEventIdle = (1 << 1), /**< Idle: bus idle detected */
|
||||
FuriHalSerialRxEventFrameError = (1 << 2), /**< Framing Error: incorrect frame detected */
|
||||
FuriHalSerialRxEventNoiseError = (1 << 3), /**< Noise Error: noise on the line detected */
|
||||
FuriHalSerialRxEventOverrunError = (1 << 4), /**< Overrun Error: no space for received data */
|
||||
} FuriHalSerialRxEvent;
|
||||
|
||||
/** Receive callback
|
||||
*
|
||||
* @warning Callback will be called in interrupt context, ensure thread
|
||||
* safety on your side.
|
||||
* @param handle Serial handle
|
||||
* @param event FuriHalSerialRxEvent
|
||||
* @param context Callback context provided earlier
|
||||
*/
|
||||
typedef void (*FuriHalSerialAsyncRxCallback)(
|
||||
FuriHalSerialHandle* handle,
|
||||
FuriHalSerialRxEvent event,
|
||||
void* context);
|
||||
|
||||
/** Start and sets Serial Receive callback
|
||||
*
|
||||
* @warning Callback will be called in interrupt context, ensure thread
|
||||
* safety on your side
|
||||
*
|
||||
* @param handle Serial handle
|
||||
* @param callback callback pointer
|
||||
* @param context callback context
|
||||
* @param[in] report_errors report RX error
|
||||
*/
|
||||
void furi_hal_serial_async_rx_start(
|
||||
FuriHalSerialHandle* handle,
|
||||
FuriHalSerialAsyncRxCallback callback,
|
||||
void* context,
|
||||
bool report_errors);
|
||||
|
||||
/** Stop Serial Receive
|
||||
*
|
||||
* @param handle Serial handle
|
||||
*/
|
||||
void furi_hal_serial_async_rx_stop(FuriHalSerialHandle* handle);
|
||||
|
||||
/** Get data Serial receive
|
||||
*
|
||||
* @warning This function must be called only from the callback
|
||||
* FuriHalSerialAsyncRxCallback
|
||||
*
|
||||
* @param handle Serial handle
|
||||
*
|
||||
* @return data
|
||||
*/
|
||||
uint8_t furi_hal_serial_async_rx(FuriHalSerialHandle* handle);
|
||||
|
||||
/* DMA based Serial API */
|
||||
|
||||
#define FURI_HAL_SERIAL_DMA_BUFFER_SIZE (256u)
|
||||
|
||||
/** Receive DMA callback
|
||||
*
|
||||
* @warning DMA Callback will be called in interrupt context, ensure thread
|
||||
* safety on your side.
|
||||
*
|
||||
* @param handle Serial handle
|
||||
* @param event FuriHalSerialDmaRxEvent
|
||||
* @param data_len Received data
|
||||
* @param context Callback context provided earlier
|
||||
*/
|
||||
typedef void (*FuriHalSerialDmaRxCallback)(
|
||||
FuriHalSerialHandle* handle,
|
||||
FuriHalSerialRxEvent event,
|
||||
size_t data_len,
|
||||
void* context);
|
||||
|
||||
/** Start and sets Serial event callback receive DMA
|
||||
*
|
||||
* @param handle Serial handle
|
||||
* @param callback callback pointer
|
||||
* @param context callback context
|
||||
* @param[in] report_errors report RX error
|
||||
*/
|
||||
void furi_hal_serial_dma_rx_start(
|
||||
FuriHalSerialHandle* handle,
|
||||
FuriHalSerialDmaRxCallback callback,
|
||||
void* context,
|
||||
bool report_errors);
|
||||
|
||||
/** Stop Serial receive DMA
|
||||
*
|
||||
* @param handle Serial handle
|
||||
*/
|
||||
void furi_hal_serial_dma_rx_stop(FuriHalSerialHandle* handle);
|
||||
|
||||
/** Get data Serial receive DMA
|
||||
*
|
||||
* @warning This function must be called only from the callback
|
||||
* FuriHalSerialDmaRxCallback
|
||||
*
|
||||
* @param handle Serial handle
|
||||
* @param data pointer to data buffer
|
||||
* @param len get data size (in bytes)
|
||||
*
|
||||
* @return size actual data receive (in bytes)
|
||||
*/
|
||||
size_t furi_hal_serial_dma_rx(FuriHalSerialHandle* handle, uint8_t* data, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
233
targets/f7/furi_hal/furi_hal_serial_control.c
Normal file
233
targets/f7/furi_hal/furi_hal_serial_control.c
Normal file
@@ -0,0 +1,233 @@
|
||||
#include "furi_hal_serial_control.h"
|
||||
#include "furi_hal_serial_types_i.h"
|
||||
#include "furi_hal_serial.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <toolbox/api_lock.h>
|
||||
|
||||
#define TAG "FuriHalSerialControl"
|
||||
|
||||
typedef enum {
|
||||
FuriHalSerialControlMessageTypeStop,
|
||||
FuriHalSerialControlMessageTypeSuspend,
|
||||
FuriHalSerialControlMessageTypeResume,
|
||||
FuriHalSerialControlMessageTypeAcquire,
|
||||
FuriHalSerialControlMessageTypeRelease,
|
||||
FuriHalSerialControlMessageTypeLogging,
|
||||
} FuriHalSerialControlMessageType;
|
||||
|
||||
typedef struct {
|
||||
FuriHalSerialControlMessageType type;
|
||||
FuriApiLock api_lock;
|
||||
void* input;
|
||||
void* output;
|
||||
} FuriHalSerialControlMessage;
|
||||
|
||||
typedef struct {
|
||||
const FuriHalSerialId id;
|
||||
const uint32_t baud_rate;
|
||||
} FuriHalSerialControlMessageInputLogging;
|
||||
|
||||
typedef struct {
|
||||
FuriHalSerialHandle handles[FuriHalSerialIdMax];
|
||||
FuriMessageQueue* queue;
|
||||
FuriThread* thread;
|
||||
|
||||
// Logging
|
||||
FuriHalSerialId log_config_serial_id;
|
||||
uint32_t log_config_serial_baud_rate;
|
||||
FuriLogHandler log_handler;
|
||||
FuriHalSerialHandle* log_serial;
|
||||
} FuriHalSerialControl;
|
||||
|
||||
FuriHalSerialControl* furi_hal_serial_control = NULL;
|
||||
|
||||
static void furi_hal_serial_control_log_callback(const uint8_t* data, size_t size, void* context) {
|
||||
FuriHalSerialHandle* handle = context;
|
||||
furi_hal_serial_tx(handle, data, size);
|
||||
}
|
||||
|
||||
static void furi_hal_serial_control_log_set_handle(FuriHalSerialHandle* handle) {
|
||||
if(furi_hal_serial_control->log_serial) {
|
||||
furi_log_remove_handler(furi_hal_serial_control->log_handler);
|
||||
furi_hal_serial_deinit(furi_hal_serial_control->log_serial);
|
||||
furi_hal_serial_control->log_serial = NULL;
|
||||
}
|
||||
|
||||
if(handle) {
|
||||
furi_hal_serial_control->log_serial = handle;
|
||||
furi_hal_serial_init(
|
||||
furi_hal_serial_control->log_serial,
|
||||
furi_hal_serial_control->log_config_serial_baud_rate);
|
||||
furi_hal_serial_control->log_handler.callback = furi_hal_serial_control_log_callback;
|
||||
furi_hal_serial_control->log_handler.context = furi_hal_serial_control->log_serial;
|
||||
furi_log_add_handler(furi_hal_serial_control->log_handler);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t furi_hal_serial_control_thread(void* args) {
|
||||
UNUSED(args);
|
||||
|
||||
bool should_continue = true;
|
||||
while(should_continue || furi_message_queue_get_count(furi_hal_serial_control->queue) > 0) {
|
||||
FuriHalSerialControlMessage message = {0};
|
||||
FuriStatus status =
|
||||
furi_message_queue_get(furi_hal_serial_control->queue, &message, FuriWaitForever);
|
||||
furi_check(status == FuriStatusOk);
|
||||
|
||||
if(message.type == FuriHalSerialControlMessageTypeStop) {
|
||||
should_continue = false;
|
||||
} else if(message.type == FuriHalSerialControlMessageTypeSuspend) {
|
||||
for(size_t i = 0; i < FuriHalSerialIdMax; i++) {
|
||||
furi_hal_serial_tx_wait_complete(&furi_hal_serial_control->handles[i]);
|
||||
furi_hal_serial_suspend(&furi_hal_serial_control->handles[i]);
|
||||
}
|
||||
api_lock_unlock(message.api_lock);
|
||||
} else if(message.type == FuriHalSerialControlMessageTypeResume) {
|
||||
for(size_t i = 0; i < FuriHalSerialIdMax; i++) {
|
||||
furi_hal_serial_resume(&furi_hal_serial_control->handles[i]);
|
||||
}
|
||||
api_lock_unlock(message.api_lock);
|
||||
} else if(message.type == FuriHalSerialControlMessageTypeAcquire) {
|
||||
FuriHalSerialId serial_id = *(FuriHalSerialId*)message.input;
|
||||
if(furi_hal_serial_control->handles[serial_id].in_use) {
|
||||
*(FuriHalSerialHandle**)message.output = NULL;
|
||||
} else {
|
||||
// Logging
|
||||
if(furi_hal_serial_control->log_config_serial_id == serial_id) {
|
||||
furi_hal_serial_control_log_set_handle(NULL);
|
||||
}
|
||||
// Return handle
|
||||
furi_hal_serial_control->handles[serial_id].in_use = true;
|
||||
*(FuriHalSerialHandle**)message.output =
|
||||
&furi_hal_serial_control->handles[serial_id];
|
||||
}
|
||||
api_lock_unlock(message.api_lock);
|
||||
} else if(message.type == FuriHalSerialControlMessageTypeRelease) {
|
||||
FuriHalSerialHandle* handle = *(FuriHalSerialHandle**)message.input;
|
||||
furi_assert(handle->in_use);
|
||||
furi_hal_serial_deinit(handle);
|
||||
handle->in_use = false;
|
||||
|
||||
// Return back logging
|
||||
if(furi_hal_serial_control->log_config_serial_id == handle->id) {
|
||||
furi_hal_serial_control_log_set_handle(handle);
|
||||
}
|
||||
api_lock_unlock(message.api_lock);
|
||||
} else if(message.type == FuriHalSerialControlMessageTypeLogging) {
|
||||
// Set new configuration
|
||||
FuriHalSerialControlMessageInputLogging* message_input = message.input;
|
||||
furi_hal_serial_control->log_config_serial_id = message_input->id;
|
||||
furi_hal_serial_control->log_config_serial_baud_rate = message_input->baud_rate;
|
||||
// Apply new configuration
|
||||
FuriHalSerialHandle* handle = NULL;
|
||||
if(furi_hal_serial_control->log_config_serial_id < FuriHalSerialIdMax) {
|
||||
handle = &furi_hal_serial_control
|
||||
->handles[furi_hal_serial_control->log_config_serial_id];
|
||||
}
|
||||
furi_hal_serial_control_log_set_handle(handle);
|
||||
api_lock_unlock(message.api_lock);
|
||||
} else {
|
||||
furi_crash("Invalid parameter");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void furi_hal_serial_control_init(void) {
|
||||
furi_check(furi_hal_serial_control == NULL);
|
||||
// Allocate resources
|
||||
furi_hal_serial_control = malloc(sizeof(FuriHalSerialControl));
|
||||
furi_hal_serial_control->handles[FuriHalSerialIdUsart].id = FuriHalSerialIdUsart;
|
||||
furi_hal_serial_control->handles[FuriHalSerialIdLpuart].id = FuriHalSerialIdLpuart;
|
||||
furi_hal_serial_control->queue =
|
||||
furi_message_queue_alloc(8, sizeof(FuriHalSerialControlMessage));
|
||||
furi_hal_serial_control->thread =
|
||||
furi_thread_alloc_ex("SerialControlDriver", 512, furi_hal_serial_control_thread, NULL);
|
||||
furi_thread_mark_as_service(furi_hal_serial_control->thread);
|
||||
furi_thread_set_priority(furi_hal_serial_control->thread, FuriThreadPriorityHighest);
|
||||
furi_hal_serial_control->log_config_serial_id = FuriHalSerialIdMax;
|
||||
// Start control plane thread
|
||||
furi_thread_start(furi_hal_serial_control->thread);
|
||||
}
|
||||
|
||||
void furi_hal_serial_control_deinit(void) {
|
||||
furi_check(furi_hal_serial_control);
|
||||
// Stop control plane thread
|
||||
FuriHalSerialControlMessage message;
|
||||
message.type = FuriHalSerialControlMessageTypeStop;
|
||||
furi_message_queue_put(furi_hal_serial_control->queue, &message, FuriWaitForever);
|
||||
furi_thread_join(furi_hal_serial_control->thread);
|
||||
// Release resources
|
||||
furi_thread_free(furi_hal_serial_control->thread);
|
||||
furi_message_queue_free(furi_hal_serial_control->queue);
|
||||
free(furi_hal_serial_control);
|
||||
}
|
||||
|
||||
void furi_hal_serial_control_suspend(void) {
|
||||
furi_check(furi_hal_serial_control);
|
||||
|
||||
FuriHalSerialControlMessage message;
|
||||
message.type = FuriHalSerialControlMessageTypeSuspend;
|
||||
message.api_lock = api_lock_alloc_locked();
|
||||
furi_message_queue_put(furi_hal_serial_control->queue, &message, FuriWaitForever);
|
||||
api_lock_wait_unlock_and_free(message.api_lock);
|
||||
}
|
||||
|
||||
void furi_hal_serial_control_resume(void) {
|
||||
furi_check(furi_hal_serial_control);
|
||||
|
||||
FuriHalSerialControlMessage message;
|
||||
message.type = FuriHalSerialControlMessageTypeResume;
|
||||
message.api_lock = api_lock_alloc_locked();
|
||||
furi_message_queue_put(furi_hal_serial_control->queue, &message, FuriWaitForever);
|
||||
api_lock_wait_unlock_and_free(message.api_lock);
|
||||
}
|
||||
|
||||
FuriHalSerialHandle* furi_hal_serial_control_acquire(FuriHalSerialId serial_id) {
|
||||
furi_check(furi_hal_serial_control);
|
||||
|
||||
FuriHalSerialHandle* output = NULL;
|
||||
|
||||
FuriHalSerialControlMessage message;
|
||||
message.type = FuriHalSerialControlMessageTypeAcquire;
|
||||
message.api_lock = api_lock_alloc_locked();
|
||||
message.input = &serial_id;
|
||||
message.output = &output;
|
||||
furi_message_queue_put(furi_hal_serial_control->queue, &message, FuriWaitForever);
|
||||
api_lock_wait_unlock_and_free(message.api_lock);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void furi_hal_serial_control_release(FuriHalSerialHandle* handle) {
|
||||
furi_check(furi_hal_serial_control);
|
||||
furi_check(handle);
|
||||
|
||||
FuriHalSerialControlMessage message;
|
||||
message.type = FuriHalSerialControlMessageTypeRelease;
|
||||
message.api_lock = api_lock_alloc_locked();
|
||||
message.input = &handle;
|
||||
furi_message_queue_put(furi_hal_serial_control->queue, &message, FuriWaitForever);
|
||||
api_lock_wait_unlock_and_free(message.api_lock);
|
||||
}
|
||||
|
||||
void furi_hal_serial_control_set_logging_config(FuriHalSerialId serial_id, uint32_t baud_rate) {
|
||||
furi_check(serial_id <= FuriHalSerialIdMax);
|
||||
furi_check(baud_rate >= 9600 && baud_rate <= 4000000);
|
||||
|
||||
// Very special case of updater, where RTC initialized before kernel start
|
||||
if(!furi_hal_serial_control) return;
|
||||
|
||||
FuriHalSerialControlMessageInputLogging message_input = {
|
||||
.id = serial_id,
|
||||
.baud_rate = baud_rate,
|
||||
};
|
||||
FuriHalSerialControlMessage message;
|
||||
message.type = FuriHalSerialControlMessageTypeLogging;
|
||||
message.api_lock = api_lock_alloc_locked();
|
||||
message.input = &message_input;
|
||||
furi_message_queue_put(furi_hal_serial_control->queue, &message, FuriWaitForever);
|
||||
api_lock_wait_unlock_and_free(message.api_lock);
|
||||
}
|
||||
46
targets/f7/furi_hal/furi_hal_serial_control.h
Normal file
46
targets/f7/furi_hal/furi_hal_serial_control.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include "furi_hal_serial_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Initialize Serial Control */
|
||||
void furi_hal_serial_control_init(void);
|
||||
|
||||
/** De-Initialize Serial Control */
|
||||
void furi_hal_serial_control_deinit(void);
|
||||
|
||||
/** Suspend All Serial Interfaces */
|
||||
void furi_hal_serial_control_suspend(void);
|
||||
|
||||
/** Resume All Serial Interfaces */
|
||||
void furi_hal_serial_control_resume(void);
|
||||
|
||||
/** Acquire Serial Interface Handler
|
||||
*
|
||||
* @param[in] serial_id The serial transceiver identifier
|
||||
*
|
||||
* @return The Serial Interface Handle or null if interfaces is in use
|
||||
*/
|
||||
FuriHalSerialHandle* furi_hal_serial_control_acquire(FuriHalSerialId serial_id);
|
||||
|
||||
/** Release Serial Interface Handler
|
||||
*
|
||||
* @param handle The handle
|
||||
*/
|
||||
void furi_hal_serial_control_release(FuriHalSerialHandle* handle);
|
||||
|
||||
/** Acquire Serial Interface Handler
|
||||
*
|
||||
* @param[in] serial_id The serial transceiver identifier. Use FuriHalSerialIdMax to disable logging.
|
||||
* @param[in] baud_rate The baud rate
|
||||
*
|
||||
* @return The Serial Interface Handle or null if interfaces is in use
|
||||
*/
|
||||
void furi_hal_serial_control_set_logging_config(FuriHalSerialId serial_id, uint32_t baud_rate);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
15
targets/f7/furi_hal/furi_hal_serial_types.h
Normal file
15
targets/f7/furi_hal/furi_hal_serial_types.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
/**
|
||||
* UART channels
|
||||
*/
|
||||
typedef enum {
|
||||
FuriHalSerialIdUsart,
|
||||
FuriHalSerialIdLpuart,
|
||||
|
||||
FuriHalSerialIdMax,
|
||||
} FuriHalSerialId;
|
||||
|
||||
typedef struct FuriHalSerialHandle FuriHalSerialHandle;
|
||||
8
targets/f7/furi_hal/furi_hal_serial_types_i.h
Normal file
8
targets/f7/furi_hal/furi_hal_serial_types_i.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi_hal_serial_types.h>
|
||||
|
||||
struct FuriHalSerialHandle {
|
||||
FuriHalSerialId id;
|
||||
bool in_use;
|
||||
};
|
||||
@@ -1,244 +0,0 @@
|
||||
#include <furi_hal_uart.h>
|
||||
#include <stdbool.h>
|
||||
#include <stm32wbxx_ll_lpuart.h>
|
||||
#include <stm32wbxx_ll_usart.h>
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <furi_hal_resources.h>
|
||||
#include <furi_hal_bus.h>
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
static bool furi_hal_usart_prev_enabled[2];
|
||||
|
||||
static void (*irq_cb[2])(uint8_t ev, uint8_t data, void* context);
|
||||
static void* irq_ctx[2];
|
||||
|
||||
static void furi_hal_usart_init(uint32_t baud) {
|
||||
furi_hal_bus_enable(FuriHalBusUSART1);
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
|
||||
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_usart_tx,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullUp,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn7USART1);
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_usart_rx,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullUp,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn7USART1);
|
||||
|
||||
LL_USART_InitTypeDef USART_InitStruct;
|
||||
USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
|
||||
USART_InitStruct.BaudRate = baud;
|
||||
USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
|
||||
USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
|
||||
USART_InitStruct.Parity = LL_USART_PARITY_NONE;
|
||||
USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
|
||||
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
|
||||
USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
|
||||
LL_USART_Init(USART1, &USART_InitStruct);
|
||||
LL_USART_EnableFIFO(USART1);
|
||||
LL_USART_ConfigAsyncMode(USART1);
|
||||
|
||||
LL_USART_Enable(USART1);
|
||||
|
||||
while(!LL_USART_IsActiveFlag_TEACK(USART1) || !LL_USART_IsActiveFlag_REACK(USART1))
|
||||
;
|
||||
|
||||
LL_USART_DisableIT_ERROR(USART1);
|
||||
|
||||
NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
|
||||
}
|
||||
|
||||
static void furi_hal_lpuart_init(uint32_t baud) {
|
||||
furi_hal_bus_enable(FuriHalBusLPUART1);
|
||||
LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1);
|
||||
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_ext_pc0,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullUp,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn8LPUART1);
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_ext_pc1,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullUp,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn8LPUART1);
|
||||
|
||||
LL_LPUART_InitTypeDef LPUART_InitStruct;
|
||||
LPUART_InitStruct.PrescalerValue = LL_LPUART_PRESCALER_DIV1;
|
||||
LPUART_InitStruct.BaudRate = 115200;
|
||||
LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;
|
||||
LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;
|
||||
LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;
|
||||
LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;
|
||||
LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;
|
||||
LL_LPUART_Init(LPUART1, &LPUART_InitStruct);
|
||||
LL_LPUART_EnableFIFO(LPUART1);
|
||||
|
||||
LL_LPUART_Enable(LPUART1);
|
||||
|
||||
while(!LL_LPUART_IsActiveFlag_TEACK(LPUART1) || !LL_LPUART_IsActiveFlag_REACK(LPUART1))
|
||||
;
|
||||
|
||||
furi_hal_uart_set_br(FuriHalUartIdLPUART1, baud);
|
||||
LL_LPUART_DisableIT_ERROR(LPUART1);
|
||||
|
||||
NVIC_SetPriority(LPUART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
|
||||
}
|
||||
|
||||
void furi_hal_uart_init(FuriHalUartId ch, uint32_t baud) {
|
||||
if(ch == FuriHalUartIdLPUART1) {
|
||||
furi_hal_lpuart_init(baud);
|
||||
} else if(ch == FuriHalUartIdUSART1) {
|
||||
furi_hal_usart_init(baud);
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud) {
|
||||
if(ch == FuriHalUartIdUSART1) {
|
||||
if(LL_USART_IsEnabled(USART1)) {
|
||||
// Wait for transfer complete flag
|
||||
while(!LL_USART_IsActiveFlag_TC(USART1))
|
||||
;
|
||||
LL_USART_Disable(USART1);
|
||||
uint32_t uartclk = LL_RCC_GetUSARTClockFreq(LL_RCC_USART1_CLKSOURCE);
|
||||
LL_USART_SetBaudRate(
|
||||
USART1, uartclk, LL_USART_PRESCALER_DIV1, LL_USART_OVERSAMPLING_16, baud);
|
||||
LL_USART_Enable(USART1);
|
||||
}
|
||||
} else if(ch == FuriHalUartIdLPUART1) {
|
||||
if(LL_LPUART_IsEnabled(LPUART1)) {
|
||||
// Wait for transfer complete flag
|
||||
while(!LL_LPUART_IsActiveFlag_TC(LPUART1))
|
||||
;
|
||||
LL_LPUART_Disable(LPUART1);
|
||||
uint32_t uartclk = LL_RCC_GetLPUARTClockFreq(LL_RCC_LPUART1_CLKSOURCE);
|
||||
if(uartclk / baud > 4095) {
|
||||
LL_LPUART_SetPrescaler(LPUART1, LL_LPUART_PRESCALER_DIV32);
|
||||
LL_LPUART_SetBaudRate(LPUART1, uartclk, LL_LPUART_PRESCALER_DIV32, baud);
|
||||
} else {
|
||||
LL_LPUART_SetPrescaler(LPUART1, LL_LPUART_PRESCALER_DIV1);
|
||||
LL_LPUART_SetBaudRate(LPUART1, uartclk, LL_LPUART_PRESCALER_DIV1, baud);
|
||||
}
|
||||
LL_LPUART_Enable(LPUART1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_uart_deinit(FuriHalUartId ch) {
|
||||
furi_hal_uart_set_irq_cb(ch, NULL, NULL);
|
||||
if(ch == FuriHalUartIdUSART1) {
|
||||
if(furi_hal_bus_is_enabled(FuriHalBusUSART1)) {
|
||||
furi_hal_bus_disable(FuriHalBusUSART1);
|
||||
}
|
||||
furi_hal_gpio_init(&gpio_usart_tx, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_usart_rx, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
} else if(ch == FuriHalUartIdLPUART1) {
|
||||
if(furi_hal_bus_is_enabled(FuriHalBusLPUART1)) {
|
||||
furi_hal_bus_disable(FuriHalBusLPUART1);
|
||||
}
|
||||
furi_hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_uart_suspend(FuriHalUartId channel) {
|
||||
if(channel == FuriHalUartIdLPUART1 && LL_LPUART_IsEnabled(LPUART1)) {
|
||||
LL_LPUART_Disable(LPUART1);
|
||||
furi_hal_usart_prev_enabled[channel] = true;
|
||||
} else if(channel == FuriHalUartIdUSART1 && LL_USART_IsEnabled(USART1)) {
|
||||
LL_USART_Disable(USART1);
|
||||
furi_hal_usart_prev_enabled[channel] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_uart_resume(FuriHalUartId channel) {
|
||||
if(!furi_hal_usart_prev_enabled[channel]) {
|
||||
return;
|
||||
} else if(channel == FuriHalUartIdLPUART1) {
|
||||
LL_LPUART_Enable(LPUART1);
|
||||
} else if(channel == FuriHalUartIdUSART1) {
|
||||
LL_USART_Enable(USART1);
|
||||
}
|
||||
|
||||
furi_hal_usart_prev_enabled[channel] = false;
|
||||
}
|
||||
|
||||
void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size) {
|
||||
if(ch == FuriHalUartIdUSART1) {
|
||||
if(LL_USART_IsEnabled(USART1) == 0) return;
|
||||
|
||||
while(buffer_size > 0) {
|
||||
while(!LL_USART_IsActiveFlag_TXE(USART1))
|
||||
;
|
||||
|
||||
LL_USART_TransmitData8(USART1, *buffer);
|
||||
buffer++;
|
||||
buffer_size--;
|
||||
}
|
||||
|
||||
} else if(ch == FuriHalUartIdLPUART1) {
|
||||
if(LL_LPUART_IsEnabled(LPUART1) == 0) return;
|
||||
|
||||
while(buffer_size > 0) {
|
||||
while(!LL_LPUART_IsActiveFlag_TXE(LPUART1))
|
||||
;
|
||||
|
||||
LL_LPUART_TransmitData8(LPUART1, *buffer);
|
||||
|
||||
buffer++;
|
||||
buffer_size--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_uart_set_irq_cb(
|
||||
FuriHalUartId ch,
|
||||
void (*cb)(UartIrqEvent ev, uint8_t data, void* ctx),
|
||||
void* ctx) {
|
||||
if(cb == NULL) {
|
||||
if(ch == FuriHalUartIdUSART1) {
|
||||
NVIC_DisableIRQ(USART1_IRQn);
|
||||
LL_USART_DisableIT_RXNE_RXFNE(USART1);
|
||||
} else if(ch == FuriHalUartIdLPUART1) {
|
||||
NVIC_DisableIRQ(LPUART1_IRQn);
|
||||
LL_LPUART_DisableIT_RXNE_RXFNE(LPUART1);
|
||||
}
|
||||
irq_cb[ch] = cb;
|
||||
irq_ctx[ch] = ctx;
|
||||
} else {
|
||||
irq_ctx[ch] = ctx;
|
||||
irq_cb[ch] = cb;
|
||||
if(ch == FuriHalUartIdUSART1) {
|
||||
NVIC_EnableIRQ(USART1_IRQn);
|
||||
LL_USART_EnableIT_RXNE_RXFNE(USART1);
|
||||
} else if(ch == FuriHalUartIdLPUART1) {
|
||||
NVIC_EnableIRQ(LPUART1_IRQn);
|
||||
LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LPUART1_IRQHandler(void) {
|
||||
if(LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1)) {
|
||||
uint8_t data = LL_LPUART_ReceiveData8(LPUART1);
|
||||
irq_cb[FuriHalUartIdLPUART1](UartIrqEventRXNE, data, irq_ctx[FuriHalUartIdLPUART1]);
|
||||
} else if(LL_LPUART_IsActiveFlag_ORE(LPUART1)) {
|
||||
LL_LPUART_ClearFlag_ORE(LPUART1);
|
||||
}
|
||||
}
|
||||
|
||||
void USART1_IRQHandler(void) {
|
||||
if(LL_USART_IsActiveFlag_RXNE_RXFNE(USART1)) {
|
||||
uint8_t data = LL_USART_ReceiveData8(USART1);
|
||||
irq_cb[FuriHalUartIdUSART1](UartIrqEventRXNE, data, irq_ctx[FuriHalUartIdUSART1]);
|
||||
} else if(LL_USART_IsActiveFlag_ORE(USART1)) {
|
||||
LL_USART_ClearFlag_ORE(USART1);
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/**
|
||||
* @file furi_hal_uart.h
|
||||
* @version 1.0
|
||||
* @date 2021-11-19
|
||||
*
|
||||
* UART HAL api interface
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* UART channels
|
||||
*/
|
||||
typedef enum {
|
||||
FuriHalUartIdUSART1,
|
||||
FuriHalUartIdLPUART1,
|
||||
} FuriHalUartId;
|
||||
|
||||
/**
|
||||
* UART events
|
||||
*/
|
||||
typedef enum {
|
||||
UartIrqEventRXNE,
|
||||
} UartIrqEvent;
|
||||
|
||||
/**
|
||||
* Init UART
|
||||
* Configures GPIO to UART function, сonfigures UART hardware, enables UART hardware
|
||||
* @param channel UART channel
|
||||
* @param baud baudrate
|
||||
*/
|
||||
void furi_hal_uart_init(FuriHalUartId channel, uint32_t baud);
|
||||
|
||||
/**
|
||||
* Deinit UART
|
||||
* Configures GPIO to analog, clears callback and callback context, disables UART hardware
|
||||
* @param channel UART channel
|
||||
*/
|
||||
void furi_hal_uart_deinit(FuriHalUartId channel);
|
||||
|
||||
/**
|
||||
* Suspend UART operation
|
||||
* Disables UART hardware, settings and callbacks are preserved
|
||||
* @param channel UART channel
|
||||
*/
|
||||
void furi_hal_uart_suspend(FuriHalUartId channel);
|
||||
|
||||
/**
|
||||
* Resume UART operation
|
||||
* Resumes UART hardware from suspended state
|
||||
* @param channel UART channel
|
||||
*/
|
||||
void furi_hal_uart_resume(FuriHalUartId channel);
|
||||
|
||||
/**
|
||||
* Changes UART baudrate
|
||||
* @param channel UART channel
|
||||
* @param baud baudrate
|
||||
*/
|
||||
void furi_hal_uart_set_br(FuriHalUartId channel, uint32_t baud);
|
||||
|
||||
/**
|
||||
* Transmits data
|
||||
* @param channel UART channel
|
||||
* @param buffer data
|
||||
* @param buffer_size data size (in bytes)
|
||||
*/
|
||||
void furi_hal_uart_tx(FuriHalUartId channel, uint8_t* buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
* Sets UART event callback
|
||||
* @param channel UART channel
|
||||
* @param callback callback pointer
|
||||
* @param context callback context
|
||||
*/
|
||||
void furi_hal_uart_set_irq_cb(
|
||||
FuriHalUartId channel,
|
||||
void (*callback)(UartIrqEvent event, uint8_t data, void* context),
|
||||
void* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user