[FL-1984] USB-UART improvements and fixes (#785)
* [FL-1984] USB-UART fixes * FuriHal: fix SOF wait on CDC0 * FuriHal: fixed stuck in UART IRQ with ORE event Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									fae8d8f23c
								
							
						
					
					
						commit
						732b9546fc
					
				| @ -12,6 +12,14 @@ | ||||
| #include <gui/modules/variable-item-list.h> | ||||
| #include "views/gpio_test.h" | ||||
| 
 | ||||
| #define GPIO_SCENE_START_CUSTOM_EVENT_OTG_OFF (0UL) | ||||
| #define GPIO_SCENE_START_CUSTOM_EVENT_OTG_ON (1UL) | ||||
| #define GPIO_SCENE_START_CUSTOM_EVENT_TEST (2UL) | ||||
| #define GPIO_SCENE_START_CUSTOM_EVENT_USB_UART (3UL) | ||||
| 
 | ||||
| #define GPIO_SCENE_USB_UART_CUSTOM_EVENT_ENABLE (4UL) | ||||
| #define GPIO_SCENE_USB_UART_CUSTOM_EVENT_DISABLE (5UL) | ||||
| 
 | ||||
| struct GpioApp { | ||||
|     Gui* gui; | ||||
|     ViewDispatcher* view_dispatcher; | ||||
|  | ||||
| @ -1,11 +1,6 @@ | ||||
| #include "../gpio_app_i.h" | ||||
| #include "furi-hal-power.h" | ||||
| 
 | ||||
| #define GPIO_SCENE_START_CUSTOM_EVENT_OTG_OFF (0UL) | ||||
| #define GPIO_SCENE_START_CUSTOM_EVENT_OTG_ON (1UL) | ||||
| #define GPIO_SCENE_START_CUSTOM_EVENT_TEST (2UL) | ||||
| #define GPIO_SCENE_START_CUSTOM_EVENT_USB_UART (3UL) | ||||
| 
 | ||||
| enum GpioItem { | ||||
|     GpioItemOtg, | ||||
|     GpioItemTest, | ||||
|  | ||||
| @ -1,17 +1,6 @@ | ||||
| #include "../usb_uart_bridge.h" | ||||
| #include "../gpio_app_i.h" | ||||
| #include "furi-hal.h" | ||||
| #include <stream_buffer.h> | ||||
| #include <furi-hal-usb-cdc_i.h> | ||||
| #include "usb_cdc.h" | ||||
| 
 | ||||
| #define USB_PKT_LEN CDC_DATA_SZ | ||||
| #define USB_UART_RX_BUF_SIZE (USB_PKT_LEN * 3) | ||||
| #define USB_UART_TX_BUF_SIZE (USB_PKT_LEN * 3) | ||||
| 
 | ||||
| typedef enum { | ||||
|     WorkerCmdStop = (1 << 0), | ||||
| 
 | ||||
| } WorkerCommandFlags; | ||||
| 
 | ||||
| typedef enum { | ||||
|     UsbUartLineIndexVcp, | ||||
| @ -21,42 +10,7 @@ typedef enum { | ||||
|     UsbUartLineIndexDisable, | ||||
| } LineIndex; | ||||
| 
 | ||||
| typedef enum { | ||||
|     UsbUartPortUSART1 = 0, | ||||
|     UsbUartPortLPUART1 = 1, | ||||
| } PortIdx; | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint8_t vcp_ch; | ||||
|     PortIdx uart_ch; | ||||
|     uint32_t baudrate; | ||||
| } UsbUartConfig; | ||||
| 
 | ||||
| typedef struct { | ||||
|     UsbUartConfig cfg_cur; | ||||
|     UsbUartConfig cfg_set; | ||||
|     char br_text[8]; | ||||
| 
 | ||||
|     bool running; | ||||
|     osThreadId_t parent_thread; | ||||
| 
 | ||||
|     osThreadAttr_t thread_attr; | ||||
|     osThreadId_t thread; | ||||
| 
 | ||||
|     osThreadAttr_t tx_thread_attr; | ||||
|     osThreadId_t tx_thread; | ||||
| 
 | ||||
|     StreamBufferHandle_t rx_stream; | ||||
|     osSemaphoreId_t rx_done_sem; | ||||
|     osSemaphoreId_t usb_sof_sem; | ||||
| 
 | ||||
|     StreamBufferHandle_t tx_stream; | ||||
| 
 | ||||
|     uint8_t rx_buf[USB_PKT_LEN]; | ||||
|     uint8_t tx_buf[USB_PKT_LEN]; | ||||
| } UsbUartParams; | ||||
| 
 | ||||
| static UsbUartParams* usb_uart; | ||||
| static UsbUartConfig* cfg_set; | ||||
| 
 | ||||
| static const char* vcp_ch[] = {"0 (CLI)", "1"}; | ||||
| static const char* uart_ch[] = {"USART1", "LPUART1"}; | ||||
| @ -73,197 +27,14 @@ static const uint32_t baudrate_list[] = { | ||||
|     921600, | ||||
| }; | ||||
| 
 | ||||
| static void vcp_on_cdc_tx_complete(); | ||||
| static void vcp_on_cdc_rx(); | ||||
| static void vcp_state_callback(uint8_t state); | ||||
| static void vcp_on_cdc_control_line(uint8_t state); | ||||
| static void vcp_on_line_config(struct usb_cdc_line_coding* config); | ||||
| 
 | ||||
| static CdcCallbacks cdc_cb = { | ||||
|     vcp_on_cdc_tx_complete, | ||||
|     vcp_on_cdc_rx, | ||||
|     vcp_state_callback, | ||||
|     vcp_on_cdc_control_line, | ||||
|     vcp_on_line_config, | ||||
| }; | ||||
| 
 | ||||
| /* USB UART worker */ | ||||
| 
 | ||||
| static void usb_uart_tx_thread(void* context); | ||||
| 
 | ||||
| static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data) { | ||||
|     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||
| 
 | ||||
|     if(ev == UartIrqEventRXNE) { | ||||
|         size_t ret = | ||||
|             xStreamBufferSendFromISR(usb_uart->rx_stream, &data, 1, &xHigherPriorityTaskWoken); | ||||
|         furi_check(ret == 1); | ||||
|         ret = xStreamBufferBytesAvailable(usb_uart->rx_stream); | ||||
|         if(ret > USB_PKT_LEN) osSemaphoreRelease(usb_uart->rx_done_sem); | ||||
|     } else if(ev == UartIrqEventIDLE) { | ||||
|         osSemaphoreRelease(usb_uart->rx_done_sem); | ||||
|     } | ||||
| 
 | ||||
|     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); | ||||
| } | ||||
| 
 | ||||
| static void usb_uart_worker(void* context) { | ||||
|     memcpy(&usb_uart->cfg_cur, &usb_uart->cfg_set, sizeof(UsbUartConfig)); | ||||
| 
 | ||||
|     usb_uart->rx_stream = xStreamBufferCreate(USB_UART_RX_BUF_SIZE, 1); | ||||
|     usb_uart->rx_done_sem = osSemaphoreNew(1, 1, NULL); | ||||
|     usb_uart->usb_sof_sem = osSemaphoreNew(1, 1, NULL); | ||||
| 
 | ||||
|     usb_uart->tx_stream = xStreamBufferCreate(USB_UART_TX_BUF_SIZE, 1); | ||||
| 
 | ||||
|     usb_uart->tx_thread = NULL; | ||||
|     usb_uart->tx_thread_attr.name = "usb_uart_tx"; | ||||
|     usb_uart->tx_thread_attr.stack_size = 512; | ||||
| 
 | ||||
|     UsbMode usb_mode_prev = furi_hal_usb_get_config(); | ||||
|     if(usb_uart->cfg_cur.vcp_ch == 0) { | ||||
|         furi_hal_usb_set_config(UsbModeVcpSingle); | ||||
|         furi_hal_vcp_disable(); | ||||
|     } else { | ||||
|         furi_hal_usb_set_config(UsbModeVcpDual); | ||||
|     } | ||||
| 
 | ||||
|     if(usb_uart->cfg_cur.uart_ch == UsbUartPortUSART1) { | ||||
|         furi_hal_usart_init(); | ||||
|         furi_hal_usart_set_irq_cb(usb_uart_on_irq_cb); | ||||
|         if(usb_uart->cfg_cur.baudrate != 0) | ||||
|             furi_hal_usart_set_br(usb_uart->cfg_cur.baudrate); | ||||
|         else | ||||
|             vcp_on_line_config(furi_hal_cdc_get_port_settings(usb_uart->cfg_cur.vcp_ch)); | ||||
|     } else if(usb_uart->cfg_cur.uart_ch == UsbUartPortLPUART1) { | ||||
|         furi_hal_lpuart_init(); | ||||
|         furi_hal_lpuart_set_irq_cb(usb_uart_on_irq_cb); | ||||
|         if(usb_uart->cfg_cur.baudrate != 0) | ||||
|             furi_hal_lpuart_set_br(usb_uart->cfg_cur.baudrate); | ||||
|         else | ||||
|             vcp_on_line_config(furi_hal_cdc_get_port_settings(usb_uart->cfg_cur.vcp_ch)); | ||||
|     } | ||||
| 
 | ||||
|     furi_hal_cdc_set_callbacks(usb_uart->cfg_cur.vcp_ch, &cdc_cb); | ||||
|     usb_uart->tx_thread = osThreadNew(usb_uart_tx_thread, NULL, &usb_uart->tx_thread_attr); | ||||
| 
 | ||||
|     while(1) { | ||||
|         furi_check(osSemaphoreAcquire(usb_uart->rx_done_sem, osWaitForever) == osOK); | ||||
|         if(osThreadFlagsWait(WorkerCmdStop, osFlagsWaitAny, 0) == WorkerCmdStop) break; | ||||
|         size_t len = 0; | ||||
|         do { | ||||
|             len = xStreamBufferReceive(usb_uart->rx_stream, usb_uart->rx_buf, USB_PKT_LEN, 0); | ||||
|             if(len > 0) { | ||||
|                 if(osSemaphoreAcquire(usb_uart->usb_sof_sem, 100) == osOK) | ||||
|                     furi_hal_cdc_send(usb_uart->cfg_cur.vcp_ch, usb_uart->rx_buf, len); | ||||
|                 else | ||||
|                     xStreamBufferReset(usb_uart->rx_stream); | ||||
|             } | ||||
|         } while(len > 0); | ||||
|     } | ||||
| 
 | ||||
|     osThreadTerminate(usb_uart->tx_thread); | ||||
| 
 | ||||
|     if(usb_uart->cfg_cur.uart_ch == UsbUartPortUSART1) | ||||
|         furi_hal_usart_deinit(); | ||||
|     else if(usb_uart->cfg_cur.uart_ch == UsbUartPortLPUART1) | ||||
|         furi_hal_lpuart_deinit(); | ||||
| 
 | ||||
|     furi_hal_cdc_set_callbacks(usb_uart->cfg_cur.vcp_ch, NULL); | ||||
|     furi_hal_usb_set_config(usb_mode_prev); | ||||
|     if(usb_uart->cfg_cur.vcp_ch == 0) furi_hal_vcp_enable(); | ||||
| 
 | ||||
|     vStreamBufferDelete(usb_uart->rx_stream); | ||||
|     osSemaphoreDelete(usb_uart->rx_done_sem); | ||||
|     osSemaphoreDelete(usb_uart->usb_sof_sem); | ||||
| 
 | ||||
|     vStreamBufferDelete(usb_uart->tx_stream); | ||||
|     osThreadFlagsSet(usb_uart->parent_thread, WorkerCmdStop); | ||||
|     osThreadExit(); | ||||
| } | ||||
| 
 | ||||
| static void usb_uart_tx_thread(void* context) { | ||||
|     uint8_t data = 0; | ||||
|     while(1) { | ||||
|         size_t len = xStreamBufferReceive(usb_uart->tx_stream, &data, 1, osWaitForever); | ||||
|         if(len > 0) { | ||||
|             if(usb_uart->cfg_cur.uart_ch == UsbUartPortUSART1) | ||||
|                 furi_hal_usart_tx(&data, len); | ||||
|             else if(usb_uart->cfg_cur.uart_ch == UsbUartPortLPUART1) | ||||
|                 furi_hal_lpuart_tx(&data, len); | ||||
|         } | ||||
|     } | ||||
|     osThreadExit(); | ||||
| } | ||||
| 
 | ||||
| /* VCP callbacks */ | ||||
| 
 | ||||
| static void vcp_on_cdc_tx_complete() { | ||||
|     osSemaphoreRelease(usb_uart->usb_sof_sem); | ||||
| } | ||||
| 
 | ||||
| static void vcp_on_cdc_rx() { | ||||
|     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||
| 
 | ||||
|     uint16_t max_len = xStreamBufferSpacesAvailable(usb_uart->tx_stream); | ||||
|     if(max_len > 0) { | ||||
|         if(max_len > USB_PKT_LEN) max_len = USB_PKT_LEN; | ||||
|         int32_t size = furi_hal_cdc_receive(usb_uart->cfg_cur.vcp_ch, usb_uart->tx_buf, max_len); | ||||
| 
 | ||||
|         if(size > 0) { | ||||
|             size_t ret = xStreamBufferSendFromISR( | ||||
|                 usb_uart->tx_stream, usb_uart->tx_buf, size, &xHigherPriorityTaskWoken); | ||||
|             furi_check(ret == size); | ||||
|         } | ||||
|     } | ||||
|     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); | ||||
| } | ||||
| 
 | ||||
| static void vcp_state_callback(uint8_t state) { | ||||
| } | ||||
| 
 | ||||
| static void vcp_on_cdc_control_line(uint8_t state) { | ||||
| } | ||||
| 
 | ||||
| static void vcp_on_line_config(struct usb_cdc_line_coding* config) { | ||||
|     if((usb_uart->cfg_cur.baudrate == 0) && (config->dwDTERate != 0)) { | ||||
|         if(usb_uart->cfg_cur.uart_ch == UsbUartPortUSART1) | ||||
|             furi_hal_usart_set_br(config->dwDTERate); | ||||
|         else if(usb_uart->cfg_cur.uart_ch == UsbUartPortLPUART1) | ||||
|             furi_hal_lpuart_set_br(config->dwDTERate); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* USB UART app */ | ||||
| 
 | ||||
| static void usb_uart_enable() { | ||||
|     if(usb_uart->running == false) { | ||||
|         usb_uart->thread = NULL; | ||||
|         usb_uart->thread_attr.name = "usb_uart"; | ||||
|         usb_uart->thread_attr.stack_size = 1024; | ||||
|         usb_uart->parent_thread = osThreadGetId(); | ||||
|         usb_uart->running = true; | ||||
|         usb_uart->thread = osThreadNew(usb_uart_worker, NULL, &usb_uart->thread_attr); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void usb_uart_disable() { | ||||
|     if(usb_uart->running == true) { | ||||
|         osThreadFlagsSet(usb_uart->thread, WorkerCmdStop); | ||||
|         osSemaphoreRelease(usb_uart->rx_done_sem); | ||||
|         osThreadFlagsWait(WorkerCmdStop, osFlagsWaitAny, osWaitForever); | ||||
|         usb_uart->running = false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool gpio_scene_usb_uart_on_event(void* context, SceneManagerEvent event) { | ||||
|     //GpioApp* app = context;
 | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == UsbUartLineIndexEnable) { | ||||
|             usb_uart_enable(); | ||||
|         } else if(event.event == UsbUartLineIndexDisable) { | ||||
|         if(event.event == GPIO_SCENE_USB_UART_CUSTOM_EVENT_ENABLE) { | ||||
|             usb_uart_enable(cfg_set); | ||||
|         } else if(event.event == GPIO_SCENE_USB_UART_CUSTOM_EVENT_DISABLE) { | ||||
|             usb_uart_disable(); | ||||
|         } | ||||
|         consumed = true; | ||||
| @ -271,15 +42,13 @@ bool gpio_scene_usb_uart_on_event(void* context, SceneManagerEvent event) { | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| /* Scene callbacks */ | ||||
| 
 | ||||
| static void line_vcp_cb(VariableItem* item) { | ||||
|     //GpioApp* app = variable_item_get_context(item);
 | ||||
|     uint8_t index = variable_item_get_current_value_index(item); | ||||
| 
 | ||||
|     variable_item_set_current_value_text(item, vcp_ch[index]); | ||||
| 
 | ||||
|     usb_uart->cfg_set.vcp_ch = index; | ||||
|     cfg_set->vcp_ch = index; | ||||
| } | ||||
| 
 | ||||
| static void line_port_cb(VariableItem* item) { | ||||
| @ -288,34 +57,44 @@ static void line_port_cb(VariableItem* item) { | ||||
| 
 | ||||
|     variable_item_set_current_value_text(item, uart_ch[index]); | ||||
| 
 | ||||
|     usb_uart->cfg_set.uart_ch = index; | ||||
|     if(index == 0) | ||||
|         cfg_set->uart_ch = FuriHalUartIdUSART1; | ||||
|     else if(index == 1) | ||||
|         cfg_set->uart_ch = FuriHalUartIdLPUART1; | ||||
| } | ||||
| 
 | ||||
| static void line_baudrate_cb(VariableItem* item) { | ||||
|     //GpioApp* app = variable_item_get_context(item);
 | ||||
|     uint8_t index = variable_item_get_current_value_index(item); | ||||
| 
 | ||||
|     char br_text[8]; | ||||
| 
 | ||||
|     if(index > 0) { | ||||
|         snprintf(usb_uart->br_text, 7, "%lu", baudrate_list[index - 1]); | ||||
|         variable_item_set_current_value_text(item, usb_uart->br_text); | ||||
|         usb_uart->cfg_set.baudrate = baudrate_list[index - 1]; | ||||
|         snprintf(br_text, 7, "%lu", baudrate_list[index - 1]); | ||||
|         variable_item_set_current_value_text(item, br_text); | ||||
|         cfg_set->baudrate = baudrate_list[index - 1]; | ||||
|     } else { | ||||
|         variable_item_set_current_value_text(item, baudrate_mode[index]); | ||||
|         usb_uart->cfg_set.baudrate = 0; | ||||
|         cfg_set->baudrate = 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void gpio_scene_usb_uart_enter_callback(void* context, uint32_t index) { | ||||
|     furi_assert(context); | ||||
|     GpioApp* app = context; | ||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, index); | ||||
|     if(index == UsbUartLineIndexEnable) | ||||
|         view_dispatcher_send_custom_event( | ||||
|             app->view_dispatcher, GPIO_SCENE_USB_UART_CUSTOM_EVENT_ENABLE); | ||||
|     else if(index == UsbUartLineIndexDisable) | ||||
|         view_dispatcher_send_custom_event( | ||||
|             app->view_dispatcher, GPIO_SCENE_USB_UART_CUSTOM_EVENT_DISABLE); | ||||
| } | ||||
| 
 | ||||
| void gpio_scene_usb_uart_on_enter(void* context) { | ||||
|     GpioApp* app = context; | ||||
|     VariableItemList* var_item_list = app->var_item_list; | ||||
| 
 | ||||
|     usb_uart = furi_alloc(sizeof(UsbUartParams)); | ||||
|     cfg_set = furi_alloc(sizeof(UsbUartConfig)); | ||||
| 
 | ||||
|     VariableItem* item; | ||||
| 
 | ||||
| @ -348,5 +127,5 @@ void gpio_scene_usb_uart_on_exit(void* context) { | ||||
|     GpioApp* app = context; | ||||
|     usb_uart_disable(); | ||||
|     variable_item_list_clean(app->var_item_list); | ||||
|     free(usb_uart); | ||||
| } | ||||
|     free(cfg_set); | ||||
| } | ||||
|  | ||||
							
								
								
									
										246
									
								
								applications/gpio/usb_uart_bridge.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								applications/gpio/usb_uart_bridge.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,246 @@ | ||||
| #include "usb_uart_bridge.h" | ||||
| #include "furi-hal.h" | ||||
| #include <stream_buffer.h> | ||||
| #include <furi-hal-usb-cdc_i.h> | ||||
| #include "usb_cdc.h" | ||||
| 
 | ||||
| #define USB_PKT_LEN CDC_DATA_SZ | ||||
| #define USB_UART_RX_BUF_SIZE (USB_PKT_LEN * 3) | ||||
| #define USB_UART_TX_BUF_SIZE (USB_PKT_LEN * 3) | ||||
| 
 | ||||
| typedef enum { | ||||
|     WorkerEvtStop = (1 << 0), | ||||
|     WorkerEvtRxReady = (1 << 1), | ||||
| 
 | ||||
|     WorkerEvtTxStop = (1 << 2), | ||||
|     WorkerEvtTxReady = (1 << 3), | ||||
| 
 | ||||
|     WorkerEvtSof = (1 << 4), | ||||
| 
 | ||||
| } WorkerEvtFlags; | ||||
| 
 | ||||
| #define WORKER_ALL_RX_EVENTS (WorkerEvtStop | WorkerEvtRxReady) | ||||
| #define WORKER_ALL_TX_EVENTS (WorkerEvtTxStop | WorkerEvtTxReady) | ||||
| 
 | ||||
| typedef struct { | ||||
|     UsbUartConfig cfg; | ||||
| 
 | ||||
|     FuriThread* thread; | ||||
|     FuriThread* tx_thread; | ||||
| 
 | ||||
|     osEventFlagsId_t events; | ||||
| 
 | ||||
|     StreamBufferHandle_t rx_stream; | ||||
|     StreamBufferHandle_t tx_stream; | ||||
| 
 | ||||
|     uint8_t rx_buf[USB_PKT_LEN]; | ||||
|     uint8_t tx_buf[USB_PKT_LEN]; | ||||
| 
 | ||||
|     bool buf_full; | ||||
| } UsbUartParams; | ||||
| 
 | ||||
| static UsbUartParams* usb_uart; | ||||
| static bool running = false; | ||||
| 
 | ||||
| static void vcp_on_cdc_tx_complete(); | ||||
| static void vcp_on_cdc_rx(); | ||||
| static void vcp_state_callback(uint8_t state); | ||||
| static void vcp_on_cdc_control_line(uint8_t state); | ||||
| static void vcp_on_line_config(struct usb_cdc_line_coding* config); | ||||
| 
 | ||||
| static CdcCallbacks cdc_cb = { | ||||
|     vcp_on_cdc_tx_complete, | ||||
|     vcp_on_cdc_rx, | ||||
|     vcp_state_callback, | ||||
|     vcp_on_cdc_control_line, | ||||
|     vcp_on_line_config, | ||||
| }; | ||||
| 
 | ||||
| /* USB UART worker */ | ||||
| 
 | ||||
| static int32_t usb_uart_tx_thread(void* context); | ||||
| 
 | ||||
| static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data) { | ||||
|     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||
| 
 | ||||
|     if(ev == UartIrqEventRXNE) { | ||||
|         xStreamBufferSendFromISR(usb_uart->rx_stream, &data, 1, &xHigherPriorityTaskWoken); | ||||
| 
 | ||||
|         size_t ret = xStreamBufferBytesAvailable(usb_uart->rx_stream); | ||||
|         if(ret > USB_PKT_LEN) osEventFlagsSet(usb_uart->events, WorkerEvtRxReady); | ||||
|     } else if(ev == UartIrqEventIDLE) { | ||||
|         osEventFlagsSet(usb_uart->events, WorkerEvtRxReady); | ||||
|     } | ||||
| 
 | ||||
|     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); | ||||
| } | ||||
| 
 | ||||
| static int32_t usb_uart_worker(void* context) { | ||||
|     memcpy(&usb_uart->cfg, context, sizeof(UsbUartConfig)); | ||||
| 
 | ||||
|     usb_uart->rx_stream = xStreamBufferCreate(USB_UART_RX_BUF_SIZE, 1); | ||||
|     usb_uart->tx_stream = xStreamBufferCreate(USB_UART_TX_BUF_SIZE, 1); | ||||
| 
 | ||||
|     usb_uart->tx_thread = furi_thread_alloc(); | ||||
|     furi_thread_set_name(usb_uart->tx_thread, "usb_uart_tx"); | ||||
|     furi_thread_set_stack_size(usb_uart->tx_thread, 512); | ||||
|     furi_thread_set_context(usb_uart->tx_thread, NULL); | ||||
|     furi_thread_set_callback(usb_uart->tx_thread, usb_uart_tx_thread); | ||||
| 
 | ||||
|     UsbMode usb_mode_prev = furi_hal_usb_get_config(); | ||||
|     if(usb_uart->cfg.vcp_ch == 0) { | ||||
|         furi_hal_usb_set_config(UsbModeVcpSingle); | ||||
|         furi_hal_vcp_disable(); | ||||
|         osEventFlagsSet(usb_uart->events, WorkerEvtSof); | ||||
|     } else { | ||||
|         furi_hal_usb_set_config(UsbModeVcpDual); | ||||
|     } | ||||
| 
 | ||||
|     if(usb_uart->cfg.uart_ch == FuriHalUartIdUSART1) { | ||||
|         furi_hal_console_disable(); | ||||
|     } else if(usb_uart->cfg.uart_ch == FuriHalUartIdLPUART1) { | ||||
|         furi_hal_uart_init(usb_uart->cfg.uart_ch, 115200); | ||||
|         furi_hal_uart_set_irq_cb(usb_uart->cfg.uart_ch, usb_uart_on_irq_cb); | ||||
|     } | ||||
| 
 | ||||
|     furi_hal_uart_set_irq_cb(usb_uart->cfg.uart_ch, usb_uart_on_irq_cb); | ||||
|     if(usb_uart->cfg.baudrate != 0) | ||||
|         furi_hal_uart_set_br(usb_uart->cfg.uart_ch, usb_uart->cfg.baudrate); | ||||
|     else | ||||
|         vcp_on_line_config(furi_hal_cdc_get_port_settings(usb_uart->cfg.vcp_ch)); | ||||
| 
 | ||||
|     furi_hal_cdc_set_callbacks(usb_uart->cfg.vcp_ch, &cdc_cb); | ||||
| 
 | ||||
|     furi_thread_start(usb_uart->tx_thread); | ||||
| 
 | ||||
|     while(1) { | ||||
|         uint32_t events = osEventFlagsWait( | ||||
|             usb_uart->events, WORKER_ALL_RX_EVENTS, osFlagsWaitAny, osWaitForever); | ||||
|         furi_check((events & osFlagsError) == 0); | ||||
|         if(events & WorkerEvtStop) break; | ||||
|         if(events & WorkerEvtRxReady) { | ||||
|             size_t len = 0; | ||||
|             do { | ||||
|                 len = xStreamBufferReceive(usb_uart->rx_stream, usb_uart->rx_buf, USB_PKT_LEN, 0); | ||||
|                 if(len > 0) { | ||||
|                     if((osEventFlagsWait(usb_uart->events, WorkerEvtSof, osFlagsWaitAny, 100) & | ||||
|                         osFlagsError) == 0) | ||||
|                         furi_hal_cdc_send(usb_uart->cfg.vcp_ch, usb_uart->rx_buf, len); | ||||
|                     else | ||||
|                         xStreamBufferReset(usb_uart->rx_stream); | ||||
|                 } | ||||
|             } while(len > 0); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     osEventFlagsSet(usb_uart->events, WorkerEvtTxStop); | ||||
|     furi_thread_join(usb_uart->tx_thread); | ||||
|     furi_thread_free(usb_uart->tx_thread); | ||||
| 
 | ||||
|     if(usb_uart->cfg.uart_ch == FuriHalUartIdUSART1) | ||||
|         furi_hal_console_enable(); | ||||
|     else if(usb_uart->cfg.uart_ch == FuriHalUartIdLPUART1) | ||||
|         furi_hal_uart_deinit(usb_uart->cfg.uart_ch); | ||||
| 
 | ||||
|     furi_hal_cdc_set_callbacks(usb_uart->cfg.vcp_ch, NULL); | ||||
|     furi_hal_usb_set_config(usb_mode_prev); | ||||
|     if(usb_uart->cfg.vcp_ch == 0) furi_hal_vcp_enable(); | ||||
| 
 | ||||
|     vStreamBufferDelete(usb_uart->rx_stream); | ||||
|     vStreamBufferDelete(usb_uart->tx_stream); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int32_t usb_uart_tx_thread(void* context) { | ||||
|     uint8_t data[USB_PKT_LEN]; | ||||
|     while(1) { | ||||
|         uint32_t events = osEventFlagsWait( | ||||
|             usb_uart->events, WORKER_ALL_TX_EVENTS, osFlagsWaitAny, osWaitForever); | ||||
|         furi_check((events & osFlagsError) == 0); | ||||
|         if(events & WorkerEvtTxStop) break; | ||||
|         if(events & WorkerEvtTxReady) { | ||||
|             size_t len = 0; | ||||
|             do { | ||||
|                 len = xStreamBufferReceive(usb_uart->tx_stream, &data, 1, 0); | ||||
|                 if(len > 0) { | ||||
|                     furi_hal_uart_tx(usb_uart->cfg.uart_ch, data, len); | ||||
|                 } | ||||
|                 if((usb_uart->buf_full == true) && | ||||
|                    (xStreamBufferBytesAvailable(usb_uart->tx_stream) == 0)) { | ||||
|                     // Stream buffer was overflown, but now is free. Reading USB buffer to resume USB transfers
 | ||||
|                     usb_uart->buf_full = false; | ||||
|                     int32_t size = furi_hal_cdc_receive(usb_uart->cfg.vcp_ch, data, USB_PKT_LEN); | ||||
|                     if(size > 0) { | ||||
|                         furi_hal_uart_tx(usb_uart->cfg.uart_ch, data, size); | ||||
|                     } | ||||
|                 } | ||||
|             } while(len > 0); | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /* VCP callbacks */ | ||||
| 
 | ||||
| static void vcp_on_cdc_tx_complete() { | ||||
|     osEventFlagsSet(usb_uart->events, WorkerEvtSof); | ||||
| } | ||||
| 
 | ||||
| static void vcp_on_cdc_rx() { | ||||
|     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||
| 
 | ||||
|     uint16_t max_len = xStreamBufferSpacesAvailable(usb_uart->tx_stream); | ||||
|     if(max_len >= USB_PKT_LEN) { | ||||
|         //if(max_len > USB_PKT_LEN) max_len = USB_PKT_LEN;
 | ||||
|         int32_t size = furi_hal_cdc_receive(usb_uart->cfg.vcp_ch, usb_uart->tx_buf, USB_PKT_LEN); | ||||
|         if(size > 0) { | ||||
|             size_t ret = xStreamBufferSendFromISR( | ||||
|                 usb_uart->tx_stream, usb_uart->tx_buf, size, &xHigherPriorityTaskWoken); | ||||
|             furi_check(ret == size); | ||||
|         } | ||||
|     } else { | ||||
|         usb_uart->buf_full = true; | ||||
|     } | ||||
|     osEventFlagsSet(usb_uart->events, WorkerEvtTxReady); | ||||
|     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); | ||||
| } | ||||
| 
 | ||||
| static void vcp_state_callback(uint8_t state) { | ||||
| } | ||||
| 
 | ||||
| static void vcp_on_cdc_control_line(uint8_t state) { | ||||
| } | ||||
| 
 | ||||
| static void vcp_on_line_config(struct usb_cdc_line_coding* config) { | ||||
|     if((usb_uart->cfg.baudrate == 0) && (config->dwDTERate != 0)) | ||||
|         furi_hal_uart_set_br(usb_uart->cfg.uart_ch, config->dwDTERate); | ||||
| } | ||||
| 
 | ||||
| void usb_uart_enable(UsbUartConfig* cfg) { | ||||
|     if(running == false) { | ||||
|         running = true; | ||||
|         usb_uart = furi_alloc(sizeof(UsbUartParams)); | ||||
| 
 | ||||
|         usb_uart->thread = furi_thread_alloc(); | ||||
|         furi_thread_set_name(usb_uart->thread, "usb_uart"); | ||||
|         furi_thread_set_stack_size(usb_uart->thread, 1024); | ||||
|         furi_thread_set_context(usb_uart->thread, cfg); | ||||
|         furi_thread_set_callback(usb_uart->thread, usb_uart_worker); | ||||
| 
 | ||||
|         usb_uart->events = osEventFlagsNew(NULL); | ||||
| 
 | ||||
|         furi_thread_start(usb_uart->thread); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void usb_uart_disable() { | ||||
|     if(running == true) { | ||||
|         osEventFlagsSet(usb_uart->events, WorkerEvtStop); | ||||
|         furi_thread_join(usb_uart->thread); | ||||
|         furi_thread_free(usb_uart->thread); | ||||
|         osEventFlagsDelete(usb_uart->events); | ||||
|         free(usb_uart); | ||||
|         running = false; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										13
									
								
								applications/gpio/usb_uart_bridge.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								applications/gpio/usb_uart_bridge.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint8_t vcp_ch; | ||||
|     uint8_t uart_ch; | ||||
|     uint32_t baudrate; | ||||
| } UsbUartConfig; | ||||
| 
 | ||||
| void usb_uart_enable(UsbUartConfig* cfg); | ||||
| 
 | ||||
| void usb_uart_disable(); | ||||
| @ -84,6 +84,7 @@ void furi_hal_clock_init() { | ||||
|     LL_RCC_EnableRTC(); | ||||
| 
 | ||||
|     LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); | ||||
|     LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1); | ||||
|     LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_PLLSAI1); | ||||
|     LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); | ||||
|     LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); | ||||
| @ -117,6 +118,7 @@ void furi_hal_clock_init() { | ||||
|     // APB1
 | ||||
|     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB); | ||||
|     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); | ||||
|     LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1); | ||||
| 
 | ||||
|     // APB2
 | ||||
|     LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1); | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| #include <furi-hal-console.h> | ||||
| #include <furi-hal-lpuart.h> | ||||
| #include <furi-hal-uart.h> | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <stm32wbxx_ll_gpio.h> | ||||
| @ -12,98 +12,23 @@ | ||||
| 
 | ||||
| volatile bool furi_hal_console_alive = false; | ||||
| 
 | ||||
| static void (*irq_cb)(uint8_t ev, uint8_t data); | ||||
| 
 | ||||
| void furi_hal_console_init() { | ||||
|     LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; | ||||
|     GPIO_InitStruct.Pin = LL_GPIO_PIN_6|LL_GPIO_PIN_7; | ||||
|     GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; | ||||
|     GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; | ||||
|     GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; | ||||
|     GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; | ||||
|     GPIO_InitStruct.Alternate = LL_GPIO_AF_7; | ||||
|     LL_GPIO_Init(GPIOB, &GPIO_InitStruct); | ||||
| 
 | ||||
|     LL_USART_InitTypeDef USART_InitStruct = {0}; | ||||
|     USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1; | ||||
|     USART_InitStruct.BaudRate = CONSOLE_BAUDRATE; | ||||
|     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_SetTXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_2); | ||||
|     LL_USART_EnableFIFO(USART1); | ||||
|     LL_USART_ConfigAsyncMode(USART1); | ||||
| 
 | ||||
|     LL_USART_Enable(USART1); | ||||
| 
 | ||||
|     while(!LL_USART_IsActiveFlag_TEACK(USART1)) ; | ||||
| 
 | ||||
|     LL_USART_EnableIT_RXNE_RXFNE(USART1); | ||||
|     LL_USART_EnableIT_IDLE(USART1); | ||||
|     HAL_NVIC_SetPriority(USART1_IRQn, 5, 0); | ||||
| 
 | ||||
|     furi_hal_uart_init(FuriHalUartIdUSART1, CONSOLE_BAUDRATE); | ||||
|     furi_hal_console_alive = true; | ||||
| 
 | ||||
|     FURI_LOG_I("FuriHalConsole", "Init OK"); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_usart_init() { | ||||
|     furi_hal_console_alive = false; | ||||
| } | ||||
| 
 | ||||
| void furi_hal_usart_set_br(uint32_t baud) { | ||||
|     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); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void furi_hal_usart_deinit() { | ||||
| void furi_hal_console_enable() { | ||||
|     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, NULL); | ||||
|     while (!LL_USART_IsActiveFlag_TC(USART1)); | ||||
|     furi_hal_usart_set_br(CONSOLE_BAUDRATE); | ||||
|     furi_hal_uart_set_br(FuriHalUartIdUSART1, CONSOLE_BAUDRATE); | ||||
|     furi_hal_console_alive = true; | ||||
| } | ||||
| 
 | ||||
| void furi_hal_usart_tx(const uint8_t* buffer, size_t buffer_size) { | ||||
|     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--; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void furi_hal_usart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data)) { | ||||
|     irq_cb = cb; | ||||
|     if (irq_cb == NULL) | ||||
|         NVIC_DisableIRQ(USART1_IRQn); | ||||
|     else | ||||
|         NVIC_EnableIRQ(USART1_IRQn); | ||||
| } | ||||
| 
 | ||||
| void USART1_IRQHandler(void) { | ||||
|     if (LL_USART_IsActiveFlag_RXNE_RXFNE(USART1)) { | ||||
|         uint8_t data = LL_USART_ReceiveData8(USART1); | ||||
|         irq_cb(UartIrqEventRXNE, data); | ||||
|     } else if (LL_USART_IsActiveFlag_IDLE(USART1)) { | ||||
|         irq_cb(UartIrqEventIDLE, 0); | ||||
|         LL_USART_ClearFlag_IDLE(USART1); | ||||
|     } | ||||
| 
 | ||||
|     //TODO: more events
 | ||||
| void furi_hal_console_disable() { | ||||
|     while (!LL_USART_IsActiveFlag_TC(USART1)); | ||||
|     furi_hal_console_alive = false; | ||||
| } | ||||
| 
 | ||||
| void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size) { | ||||
| @ -111,7 +36,7 @@ void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size) { | ||||
|         return; | ||||
| 
 | ||||
|     // Transmit data
 | ||||
|     furi_hal_usart_tx(buffer, buffer_size); | ||||
|     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)); | ||||
| } | ||||
| @ -121,9 +46,9 @@ void furi_hal_console_tx_with_new_line(const uint8_t* buffer, size_t buffer_size | ||||
|         return; | ||||
| 
 | ||||
|     // Transmit data
 | ||||
|     furi_hal_usart_tx(buffer, buffer_size); | ||||
|     furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)buffer, buffer_size); | ||||
|     // Transmit new line symbols
 | ||||
|     furi_hal_usart_tx((const uint8_t*)"\r\n", 2); | ||||
|     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)); | ||||
| } | ||||
| @ -140,4 +65,4 @@ void furi_hal_console_printf(const char format[], ...) { | ||||
| 
 | ||||
| void furi_hal_console_puts(const char *data) { | ||||
|     furi_hal_console_tx((const uint8_t*)data, strlen(data)); | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -15,6 +15,10 @@ typedef enum { | ||||
| 
 | ||||
| void furi_hal_console_init(); | ||||
| 
 | ||||
| void furi_hal_console_enable(); | ||||
| 
 | ||||
| void furi_hal_console_disable(); | ||||
| 
 | ||||
| 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); | ||||
| @ -29,18 +33,6 @@ void furi_hal_console_printf(const char format[], ...); | ||||
| 
 | ||||
| void furi_hal_console_puts(const char* data); | ||||
| 
 | ||||
| 
 | ||||
| void furi_hal_usart_init(); | ||||
| 
 | ||||
| void furi_hal_usart_deinit(); | ||||
| 
 | ||||
| void furi_hal_usart_set_br(uint32_t baud); | ||||
| 
 | ||||
| void furi_hal_usart_tx(const uint8_t* buffer, size_t buffer_size); | ||||
| 
 | ||||
| void furi_hal_usart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data)); | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -1,105 +0,0 @@ | ||||
| #include <furi-hal-lpuart.h> | ||||
| #include <stdbool.h> | ||||
| #include <stm32wbxx_ll_gpio.h> | ||||
| #include <stm32wbxx_ll_lpuart.h> | ||||
| 
 | ||||
| #include <furi.h> | ||||
| 
 | ||||
| static void (*irq_cb)(uint8_t ev, uint8_t data); | ||||
| 
 | ||||
| void furi_hal_lpuart_init() { | ||||
|     LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; | ||||
|     GPIO_InitStruct.Pin = PC0_Pin|PC1_Pin; | ||||
|     GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; | ||||
|     GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; | ||||
|     GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; | ||||
|     GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; | ||||
|     GPIO_InitStruct.Alternate = LL_GPIO_AF_8; | ||||
|     LL_GPIO_Init(GPIOC, &GPIO_InitStruct); | ||||
| 
 | ||||
|     LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1); | ||||
|     LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1); | ||||
| 
 | ||||
|     LL_LPUART_InitTypeDef LPUART_InitStruct = {0}; | ||||
|     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_SetTXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8); | ||||
|     LL_LPUART_SetRXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8); | ||||
|     LL_LPUART_EnableFIFO(LPUART1); | ||||
| 
 | ||||
|     LL_LPUART_Enable(LPUART1); | ||||
| 
 | ||||
|     while((!(LL_LPUART_IsActiveFlag_TEACK(LPUART1))) || (!(LL_LPUART_IsActiveFlag_REACK(LPUART1)))); | ||||
| 
 | ||||
|     LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1); | ||||
|     LL_LPUART_EnableIT_IDLE(LPUART1); | ||||
|     HAL_NVIC_SetPriority(LPUART1_IRQn, 5, 0); | ||||
| 
 | ||||
|     FURI_LOG_I("FuriHalLpUart", "Init OK"); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_lpuart_set_br(uint32_t baud) { | ||||
|     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_GetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1)); | ||||
|         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_lpuart_deinit() { | ||||
|     furi_hal_lpuart_set_irq_cb(NULL); | ||||
|     LL_GPIO_SetPinMode(GPIOC, PC0_Pin, LL_GPIO_MODE_ANALOG); | ||||
|     LL_GPIO_SetPinMode(GPIOC, PC1_Pin, LL_GPIO_MODE_ANALOG); | ||||
|     LL_LPUART_Disable(LPUART1); | ||||
|     LL_APB1_GRP2_DisableClock(LL_APB1_GRP2_PERIPH_LPUART1); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_lpuart_tx(const uint8_t* buffer, size_t buffer_size) { | ||||
|     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_lpuart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data)) { | ||||
|     irq_cb = cb; | ||||
|     if (irq_cb == NULL) | ||||
|         NVIC_DisableIRQ(LPUART1_IRQn); | ||||
|     else | ||||
|         NVIC_EnableIRQ(LPUART1_IRQn); | ||||
| } | ||||
| 
 | ||||
| void LPUART1_IRQHandler(void) { | ||||
|     if (LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1)) { | ||||
|         uint8_t data = LL_LPUART_ReceiveData8(LPUART1); | ||||
|         irq_cb(UartIrqEventRXNE, data); | ||||
|     } else if (LL_LPUART_IsActiveFlag_IDLE(LPUART1)) { | ||||
|         irq_cb(UartIrqEventIDLE, 0); | ||||
|         LL_LPUART_ClearFlag_IDLE(LPUART1); | ||||
|     } | ||||
| 
 | ||||
|     //TODO: more events
 | ||||
| } | ||||
| @ -1,24 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| #include "furi-hal-console.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| void furi_hal_lpuart_init(); | ||||
| 
 | ||||
| void furi_hal_lpuart_deinit(); | ||||
| 
 | ||||
| void furi_hal_lpuart_set_br(uint32_t baud); | ||||
| 
 | ||||
| void furi_hal_lpuart_tx(const uint8_t* buffer, size_t buffer_size); | ||||
| 
 | ||||
| void furi_hal_lpuart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data)); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										201
									
								
								firmware/targets/f6/furi-hal/furi-hal-uart.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								firmware/targets/f6/furi-hal/furi-hal-uart.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,201 @@ | ||||
| #include <furi-hal-uart.h> | ||||
| #include <stdbool.h> | ||||
| #include <stm32wbxx_ll_lpuart.h> | ||||
| #include <stm32wbxx_ll_usart.h> | ||||
| #include <furi-hal-resources.h> | ||||
| 
 | ||||
| #include <furi.h> | ||||
| 
 | ||||
| static void (*irq_cb[2])(uint8_t ev, uint8_t data); | ||||
| 
 | ||||
| static void furi_hal_usart_init(uint32_t baud) { | ||||
|     hal_gpio_init_ex( | ||||
|         &gpio_usart_tx, | ||||
|         GpioModeAltFunctionPushPull, | ||||
|         GpioPullUp, | ||||
|         GpioSpeedVeryHigh, | ||||
|         GpioAltFn7USART1); | ||||
|     hal_gpio_init_ex( | ||||
|         &gpio_usart_rx, | ||||
|         GpioModeAltFunctionPushPull, | ||||
|         GpioPullUp, | ||||
|         GpioSpeedVeryHigh, | ||||
|         GpioAltFn7USART1); | ||||
| 
 | ||||
|     LL_USART_InitTypeDef USART_InitStruct = {0}; | ||||
|     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_SetTXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_2); | ||||
|     LL_USART_EnableFIFO(USART1); | ||||
|     LL_USART_ConfigAsyncMode(USART1); | ||||
| 
 | ||||
|     LL_USART_Enable(USART1); | ||||
| 
 | ||||
|     while(!LL_USART_IsActiveFlag_TEACK(USART1)); | ||||
| 
 | ||||
|     LL_USART_EnableIT_RXNE_RXFNE(USART1); | ||||
|     LL_USART_EnableIT_IDLE(USART1); | ||||
|     HAL_NVIC_SetPriority(USART1_IRQn, 5, 0); | ||||
| } | ||||
| 
 | ||||
| static void furi_hal_lpuart_init(uint32_t baud) { | ||||
|     hal_gpio_init_ex( | ||||
|         &gpio_ext_pc0, | ||||
|         GpioModeAltFunctionPushPull, | ||||
|         GpioPullUp, | ||||
|         GpioSpeedVeryHigh, | ||||
|         GpioAltFn8LPUART1); | ||||
|     hal_gpio_init_ex( | ||||
|         &gpio_ext_pc1, | ||||
|         GpioModeAltFunctionPushPull, | ||||
|         GpioPullUp, | ||||
|         GpioSpeedVeryHigh, | ||||
|         GpioAltFn8LPUART1); | ||||
| 
 | ||||
|     LL_LPUART_InitTypeDef LPUART_InitStruct = {0}; | ||||
|     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_SetTXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8); | ||||
|     LL_LPUART_SetRXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8); | ||||
|     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_EnableIT_RXNE_RXFNE(LPUART1); | ||||
|     LL_LPUART_EnableIT_IDLE(LPUART1); | ||||
|     HAL_NVIC_SetPriority(LPUART1_IRQn, 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_GetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1)); | ||||
|             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); | ||||
|     if (ch == FuriHalUartIdUSART1) { | ||||
|         LL_USART_Disable(USART1); | ||||
|         hal_gpio_init(&gpio_usart_tx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||
|         hal_gpio_init(&gpio_usart_rx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||
|     } else if (ch == FuriHalUartIdLPUART1) { | ||||
|         LL_LPUART_Disable(LPUART1); | ||||
|         hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||
|         hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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)) { | ||||
|     if (cb == NULL) { | ||||
|         if (ch == FuriHalUartIdUSART1) | ||||
|             NVIC_DisableIRQ(USART1_IRQn); | ||||
|         else if (ch == FuriHalUartIdLPUART1) | ||||
|             NVIC_DisableIRQ(LPUART1_IRQn); | ||||
|         irq_cb[ch] = cb; | ||||
|     } else { | ||||
|         irq_cb[ch] = cb; | ||||
|         if (ch == FuriHalUartIdUSART1) | ||||
|             NVIC_EnableIRQ(USART1_IRQn); | ||||
|         else if (ch == FuriHalUartIdLPUART1) | ||||
|             NVIC_EnableIRQ(LPUART1_IRQn); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void LPUART1_IRQHandler(void) { | ||||
|     if (LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1)) { | ||||
|         uint8_t data = LL_LPUART_ReceiveData8(LPUART1); | ||||
|         irq_cb[FuriHalUartIdLPUART1](UartIrqEventRXNE, data); | ||||
|     } else if (LL_LPUART_IsActiveFlag_IDLE(LPUART1)) { | ||||
|         irq_cb[FuriHalUartIdLPUART1](UartIrqEventIDLE, 0); | ||||
|         LL_LPUART_ClearFlag_IDLE(LPUART1); | ||||
|     } else if (LL_LPUART_IsActiveFlag_ORE(LPUART1)) { | ||||
|         LL_LPUART_ClearFlag_ORE(LPUART1); | ||||
|     } | ||||
|     //TODO: more events
 | ||||
| } | ||||
| 
 | ||||
| void USART1_IRQHandler(void) { | ||||
|     if (LL_USART_IsActiveFlag_RXNE_RXFNE(USART1)) { | ||||
|         uint8_t data = LL_USART_ReceiveData8(USART1); | ||||
|         irq_cb[FuriHalUartIdUSART1](UartIrqEventRXNE, data); | ||||
|     } else if (LL_USART_IsActiveFlag_IDLE(USART1)) { | ||||
|         irq_cb[FuriHalUartIdUSART1](UartIrqEventIDLE, 0); | ||||
|         LL_USART_ClearFlag_IDLE(USART1); | ||||
|     } else if (LL_USART_IsActiveFlag_ORE(USART1)) { | ||||
|         LL_USART_ClearFlag_ORE(USART1); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										29
									
								
								firmware/targets/f6/furi-hal/furi-hal-uart.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								firmware/targets/f6/furi-hal/furi-hal-uart.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| #include "furi-hal-console.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| typedef enum { | ||||
|     FuriHalUartIdUSART1, | ||||
|     FuriHalUartIdLPUART1, | ||||
| } FuriHalUartId; | ||||
| 
 | ||||
| 
 | ||||
| void furi_hal_uart_init(FuriHalUartId ch, uint32_t baud); | ||||
| 
 | ||||
| void furi_hal_uart_deinit(FuriHalUartId ch); | ||||
| 
 | ||||
| void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud); | ||||
| 
 | ||||
| void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size); | ||||
| 
 | ||||
| void furi_hal_uart_set_irq_cb(FuriHalUartId ch, void (*cb)(UartIrqEvent ev, uint8_t data)); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -7,12 +7,12 @@ | ||||
| #include "usb_cdc.h" | ||||
| 
 | ||||
| #define CDC0_RXD_EP      0x01 | ||||
| #define CDC0_TXD_EP      0x82 | ||||
| #define CDC0_NTF_EP      0x83 | ||||
| #define CDC0_TXD_EP      0x81 | ||||
| #define CDC0_NTF_EP      0x82 | ||||
| 
 | ||||
| #define CDC1_RXD_EP      0x04 | ||||
| #define CDC1_TXD_EP      0x85 | ||||
| #define CDC1_NTF_EP      0x86 | ||||
| #define CDC1_RXD_EP      0x03 | ||||
| #define CDC1_TXD_EP      0x83 | ||||
| #define CDC1_NTF_EP      0x84 | ||||
| 
 | ||||
| #define CDC_NTF_SZ      0x08 | ||||
| 
 | ||||
|  | ||||
| @ -84,6 +84,7 @@ void furi_hal_clock_init() { | ||||
|     LL_RCC_EnableRTC(); | ||||
| 
 | ||||
|     LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); | ||||
|     LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1); | ||||
|     LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_PLLSAI1); | ||||
|     LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); | ||||
|     LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); | ||||
| @ -117,6 +118,7 @@ void furi_hal_clock_init() { | ||||
|     // APB1
 | ||||
|     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB); | ||||
|     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); | ||||
|     LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1); | ||||
| 
 | ||||
|     // APB2
 | ||||
|     LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1); | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| #include <furi-hal-console.h> | ||||
| #include <furi-hal-lpuart.h> | ||||
| #include <furi-hal-uart.h> | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <stm32wbxx_ll_gpio.h> | ||||
| @ -12,98 +12,23 @@ | ||||
| 
 | ||||
| volatile bool furi_hal_console_alive = false; | ||||
| 
 | ||||
| static void (*irq_cb)(uint8_t ev, uint8_t data); | ||||
| 
 | ||||
| void furi_hal_console_init() { | ||||
|     LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; | ||||
|     GPIO_InitStruct.Pin = LL_GPIO_PIN_6|LL_GPIO_PIN_7; | ||||
|     GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; | ||||
|     GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; | ||||
|     GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; | ||||
|     GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; | ||||
|     GPIO_InitStruct.Alternate = LL_GPIO_AF_7; | ||||
|     LL_GPIO_Init(GPIOB, &GPIO_InitStruct); | ||||
| 
 | ||||
|     LL_USART_InitTypeDef USART_InitStruct = {0}; | ||||
|     USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1; | ||||
|     USART_InitStruct.BaudRate = CONSOLE_BAUDRATE; | ||||
|     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_SetTXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_2); | ||||
|     LL_USART_EnableFIFO(USART1); | ||||
|     LL_USART_ConfigAsyncMode(USART1); | ||||
| 
 | ||||
|     LL_USART_Enable(USART1); | ||||
| 
 | ||||
|     while(!LL_USART_IsActiveFlag_TEACK(USART1)) ; | ||||
| 
 | ||||
|     LL_USART_EnableIT_RXNE_RXFNE(USART1); | ||||
|     LL_USART_EnableIT_IDLE(USART1); | ||||
|     HAL_NVIC_SetPriority(USART1_IRQn, 5, 0); | ||||
| 
 | ||||
|     furi_hal_uart_init(FuriHalUartIdUSART1, CONSOLE_BAUDRATE); | ||||
|     furi_hal_console_alive = true; | ||||
| 
 | ||||
|     FURI_LOG_I("FuriHalConsole", "Init OK"); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_usart_init() { | ||||
|     furi_hal_console_alive = false; | ||||
| } | ||||
| 
 | ||||
| void furi_hal_usart_set_br(uint32_t baud) { | ||||
|     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); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void furi_hal_usart_deinit() { | ||||
| void furi_hal_console_enable() { | ||||
|     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, NULL); | ||||
|     while (!LL_USART_IsActiveFlag_TC(USART1)); | ||||
|     furi_hal_usart_set_br(CONSOLE_BAUDRATE); | ||||
|     furi_hal_uart_set_br(FuriHalUartIdUSART1, CONSOLE_BAUDRATE); | ||||
|     furi_hal_console_alive = true; | ||||
| } | ||||
| 
 | ||||
| void furi_hal_usart_tx(const uint8_t* buffer, size_t buffer_size) { | ||||
|     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--; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void furi_hal_usart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data)) { | ||||
|     irq_cb = cb; | ||||
|     if (irq_cb == NULL) | ||||
|         NVIC_DisableIRQ(USART1_IRQn); | ||||
|     else | ||||
|         NVIC_EnableIRQ(USART1_IRQn); | ||||
| } | ||||
| 
 | ||||
| void USART1_IRQHandler(void) { | ||||
|     if (LL_USART_IsActiveFlag_RXNE_RXFNE(USART1)) { | ||||
|         uint8_t data = LL_USART_ReceiveData8(USART1); | ||||
|         irq_cb(UartIrqEventRXNE, data); | ||||
|     } else if (LL_USART_IsActiveFlag_IDLE(USART1)) { | ||||
|         irq_cb(UartIrqEventIDLE, 0); | ||||
|         LL_USART_ClearFlag_IDLE(USART1); | ||||
|     } | ||||
| 
 | ||||
|     //TODO: more events
 | ||||
| void furi_hal_console_disable() { | ||||
|     while (!LL_USART_IsActiveFlag_TC(USART1)); | ||||
|     furi_hal_console_alive = false; | ||||
| } | ||||
| 
 | ||||
| void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size) { | ||||
| @ -111,7 +36,7 @@ void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size) { | ||||
|         return; | ||||
| 
 | ||||
|     // Transmit data
 | ||||
|     furi_hal_usart_tx(buffer, buffer_size); | ||||
|     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)); | ||||
| } | ||||
| @ -121,9 +46,9 @@ void furi_hal_console_tx_with_new_line(const uint8_t* buffer, size_t buffer_size | ||||
|         return; | ||||
| 
 | ||||
|     // Transmit data
 | ||||
|     furi_hal_usart_tx(buffer, buffer_size); | ||||
|     furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)buffer, buffer_size); | ||||
|     // Transmit new line symbols
 | ||||
|     furi_hal_usart_tx((const uint8_t*)"\r\n", 2); | ||||
|     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)); | ||||
| } | ||||
| @ -140,4 +65,4 @@ void furi_hal_console_printf(const char format[], ...) { | ||||
| 
 | ||||
| void furi_hal_console_puts(const char *data) { | ||||
|     furi_hal_console_tx((const uint8_t*)data, strlen(data)); | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -15,6 +15,10 @@ typedef enum { | ||||
| 
 | ||||
| void furi_hal_console_init(); | ||||
| 
 | ||||
| void furi_hal_console_enable(); | ||||
| 
 | ||||
| void furi_hal_console_disable(); | ||||
| 
 | ||||
| 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); | ||||
| @ -29,18 +33,6 @@ void furi_hal_console_printf(const char format[], ...); | ||||
| 
 | ||||
| void furi_hal_console_puts(const char* data); | ||||
| 
 | ||||
| 
 | ||||
| void furi_hal_usart_init(); | ||||
| 
 | ||||
| void furi_hal_usart_deinit(); | ||||
| 
 | ||||
| void furi_hal_usart_set_br(uint32_t baud); | ||||
| 
 | ||||
| void furi_hal_usart_tx(const uint8_t* buffer, size_t buffer_size); | ||||
| 
 | ||||
| void furi_hal_usart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data)); | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -1,105 +0,0 @@ | ||||
| #include <furi-hal-lpuart.h> | ||||
| #include <stdbool.h> | ||||
| #include <stm32wbxx_ll_gpio.h> | ||||
| #include <stm32wbxx_ll_lpuart.h> | ||||
| 
 | ||||
| #include <furi.h> | ||||
| 
 | ||||
| static void (*irq_cb)(uint8_t ev, uint8_t data); | ||||
| 
 | ||||
| void furi_hal_lpuart_init() { | ||||
|     LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; | ||||
|     GPIO_InitStruct.Pin = PC0_Pin|PC1_Pin; | ||||
|     GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; | ||||
|     GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; | ||||
|     GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; | ||||
|     GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; | ||||
|     GPIO_InitStruct.Alternate = LL_GPIO_AF_8; | ||||
|     LL_GPIO_Init(GPIOC, &GPIO_InitStruct); | ||||
| 
 | ||||
|     LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1); | ||||
|     LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1); | ||||
| 
 | ||||
|     LL_LPUART_InitTypeDef LPUART_InitStruct = {0}; | ||||
|     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_SetTXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8); | ||||
|     LL_LPUART_SetRXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8); | ||||
|     LL_LPUART_EnableFIFO(LPUART1); | ||||
| 
 | ||||
|     LL_LPUART_Enable(LPUART1); | ||||
| 
 | ||||
|     while((!(LL_LPUART_IsActiveFlag_TEACK(LPUART1))) || (!(LL_LPUART_IsActiveFlag_REACK(LPUART1)))); | ||||
| 
 | ||||
|     LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1); | ||||
|     LL_LPUART_EnableIT_IDLE(LPUART1); | ||||
|     HAL_NVIC_SetPriority(LPUART1_IRQn, 5, 0); | ||||
| 
 | ||||
|     FURI_LOG_I("FuriHalLpUart", "Init OK"); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_lpuart_set_br(uint32_t baud) { | ||||
|     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_GetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1)); | ||||
|         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_lpuart_deinit() { | ||||
|     furi_hal_lpuart_set_irq_cb(NULL); | ||||
|     LL_GPIO_SetPinMode(GPIOC, PC0_Pin, LL_GPIO_MODE_ANALOG); | ||||
|     LL_GPIO_SetPinMode(GPIOC, PC1_Pin, LL_GPIO_MODE_ANALOG); | ||||
|     LL_LPUART_Disable(LPUART1); | ||||
|     LL_APB1_GRP2_DisableClock(LL_APB1_GRP2_PERIPH_LPUART1); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_lpuart_tx(const uint8_t* buffer, size_t buffer_size) { | ||||
|     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_lpuart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data)) { | ||||
|     irq_cb = cb; | ||||
|     if (irq_cb == NULL) | ||||
|         NVIC_DisableIRQ(LPUART1_IRQn); | ||||
|     else | ||||
|         NVIC_EnableIRQ(LPUART1_IRQn); | ||||
| } | ||||
| 
 | ||||
| void LPUART1_IRQHandler(void) { | ||||
|     if (LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1)) { | ||||
|         uint8_t data = LL_LPUART_ReceiveData8(LPUART1); | ||||
|         irq_cb(UartIrqEventRXNE, data); | ||||
|     } else if (LL_LPUART_IsActiveFlag_IDLE(LPUART1)) { | ||||
|         irq_cb(UartIrqEventIDLE, 0); | ||||
|         LL_LPUART_ClearFlag_IDLE(LPUART1); | ||||
|     } | ||||
| 
 | ||||
|     //TODO: more events
 | ||||
| } | ||||
| @ -1,24 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| #include "furi-hal-console.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| void furi_hal_lpuart_init(); | ||||
| 
 | ||||
| void furi_hal_lpuart_deinit(); | ||||
| 
 | ||||
| void furi_hal_lpuart_set_br(uint32_t baud); | ||||
| 
 | ||||
| void furi_hal_lpuart_tx(const uint8_t* buffer, size_t buffer_size); | ||||
| 
 | ||||
| void furi_hal_lpuart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data)); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										197
									
								
								firmware/targets/f7/furi-hal/furi-hal-uart.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								firmware/targets/f7/furi-hal/furi-hal-uart.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,197 @@ | ||||
| #include <furi-hal-uart.h> | ||||
| #include <stdbool.h> | ||||
| #include <stm32wbxx_ll_lpuart.h> | ||||
| #include <stm32wbxx_ll_usart.h> | ||||
| #include <furi-hal-resources.h> | ||||
| 
 | ||||
| #include <furi.h> | ||||
| 
 | ||||
| static void (*irq_cb[2])(uint8_t ev, uint8_t data); | ||||
| 
 | ||||
| static void furi_hal_usart_init(uint32_t baud) { | ||||
|     hal_gpio_init_ex( | ||||
|         &gpio_usart_tx, | ||||
|         GpioModeAltFunctionPushPull, | ||||
|         GpioPullUp, | ||||
|         GpioSpeedVeryHigh, | ||||
|         GpioAltFn7USART1); | ||||
|     hal_gpio_init_ex( | ||||
|         &gpio_usart_rx, | ||||
|         GpioModeAltFunctionPushPull, | ||||
|         GpioPullUp, | ||||
|         GpioSpeedVeryHigh, | ||||
|         GpioAltFn7USART1); | ||||
| 
 | ||||
|     LL_USART_InitTypeDef USART_InitStruct = {0}; | ||||
|     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_SetTXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_2); | ||||
|     LL_USART_EnableFIFO(USART1); | ||||
|     LL_USART_ConfigAsyncMode(USART1); | ||||
| 
 | ||||
|     LL_USART_Enable(USART1); | ||||
| 
 | ||||
|     while(!LL_USART_IsActiveFlag_TEACK(USART1)); | ||||
| 
 | ||||
|     LL_USART_EnableIT_RXNE_RXFNE(USART1); | ||||
|     LL_USART_EnableIT_IDLE(USART1); | ||||
|     HAL_NVIC_SetPriority(USART1_IRQn, 5, 0); | ||||
| } | ||||
| 
 | ||||
| static void furi_hal_lpuart_init(uint32_t baud) { | ||||
|     hal_gpio_init_ex( | ||||
|         &gpio_ext_pc0, | ||||
|         GpioModeAltFunctionPushPull, | ||||
|         GpioPullUp, | ||||
|         GpioSpeedVeryHigh, | ||||
|         GpioAltFn8LPUART1); | ||||
|     hal_gpio_init_ex( | ||||
|         &gpio_ext_pc1, | ||||
|         GpioModeAltFunctionPushPull, | ||||
|         GpioPullUp, | ||||
|         GpioSpeedVeryHigh, | ||||
|         GpioAltFn8LPUART1); | ||||
| 
 | ||||
|     LL_LPUART_InitTypeDef LPUART_InitStruct = {0}; | ||||
|     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_SetTXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8); | ||||
|     LL_LPUART_SetRXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8); | ||||
|     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_EnableIT_RXNE_RXFNE(LPUART1); | ||||
|     LL_LPUART_EnableIT_IDLE(LPUART1); | ||||
|     HAL_NVIC_SetPriority(LPUART1_IRQn, 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_GetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1)); | ||||
|             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); | ||||
|     if (ch == FuriHalUartIdUSART1) { | ||||
|         LL_USART_Disable(USART1); | ||||
|         hal_gpio_init(&gpio_usart_tx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||
|         hal_gpio_init(&gpio_usart_rx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||
|     } else if (ch == FuriHalUartIdLPUART1) { | ||||
|         LL_LPUART_Disable(LPUART1); | ||||
|         hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||
|         hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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)) { | ||||
|     if (cb == NULL) { | ||||
|         if (ch == FuriHalUartIdUSART1) | ||||
|             NVIC_DisableIRQ(USART1_IRQn); | ||||
|         else if (ch == FuriHalUartIdLPUART1) | ||||
|             NVIC_DisableIRQ(LPUART1_IRQn); | ||||
|         irq_cb[ch] = cb; | ||||
|     } else { | ||||
|         irq_cb[ch] = cb; | ||||
|         if (ch == FuriHalUartIdUSART1) | ||||
|             NVIC_EnableIRQ(USART1_IRQn); | ||||
|         else if (ch == FuriHalUartIdLPUART1) | ||||
|             NVIC_EnableIRQ(LPUART1_IRQn); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void LPUART1_IRQHandler(void) { | ||||
|     if (LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1)) { | ||||
|         uint8_t data = LL_LPUART_ReceiveData8(LPUART1); | ||||
|         irq_cb[FuriHalUartIdLPUART1](UartIrqEventRXNE, data); | ||||
|     } else if (LL_LPUART_IsActiveFlag_IDLE(LPUART1)) { | ||||
|         irq_cb[FuriHalUartIdLPUART1](UartIrqEventIDLE, 0); | ||||
|         LL_LPUART_ClearFlag_IDLE(LPUART1); | ||||
|     } | ||||
|     //TODO: more events
 | ||||
| } | ||||
| 
 | ||||
| void USART1_IRQHandler(void) { | ||||
|     if (LL_USART_IsActiveFlag_RXNE_RXFNE(USART1)) { | ||||
|         uint8_t data = LL_USART_ReceiveData8(USART1); | ||||
|         irq_cb[FuriHalUartIdUSART1](UartIrqEventRXNE, data); | ||||
|     } else if (LL_USART_IsActiveFlag_IDLE(USART1)) { | ||||
|         irq_cb[FuriHalUartIdUSART1](UartIrqEventIDLE, 0); | ||||
|         LL_USART_ClearFlag_IDLE(USART1); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										29
									
								
								firmware/targets/f7/furi-hal/furi-hal-uart.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								firmware/targets/f7/furi-hal/furi-hal-uart.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| #include "furi-hal-console.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| typedef enum { | ||||
|     FuriHalUartIdUSART1, | ||||
|     FuriHalUartIdLPUART1, | ||||
| } FuriHalUartId; | ||||
| 
 | ||||
| 
 | ||||
| void furi_hal_uart_init(FuriHalUartId ch, uint32_t baud); | ||||
| 
 | ||||
| void furi_hal_uart_deinit(FuriHalUartId ch); | ||||
| 
 | ||||
| void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud); | ||||
| 
 | ||||
| void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size); | ||||
| 
 | ||||
| void furi_hal_uart_set_irq_cb(FuriHalUartId ch, void (*cb)(UartIrqEvent ev, uint8_t data)); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -7,12 +7,12 @@ | ||||
| #include "usb_cdc.h" | ||||
| 
 | ||||
| #define CDC0_RXD_EP      0x01 | ||||
| #define CDC0_TXD_EP      0x82 | ||||
| #define CDC0_NTF_EP      0x83 | ||||
| #define CDC0_TXD_EP      0x81 | ||||
| #define CDC0_NTF_EP      0x82 | ||||
| 
 | ||||
| #define CDC1_RXD_EP      0x04 | ||||
| #define CDC1_TXD_EP      0x85 | ||||
| #define CDC1_NTF_EP      0x86 | ||||
| #define CDC1_RXD_EP      0x03 | ||||
| #define CDC1_TXD_EP      0x83 | ||||
| #define CDC1_NTF_EP      0x84 | ||||
| 
 | ||||
| #define CDC_NTF_SZ      0x08 | ||||
| 
 | ||||
|  | ||||
| @ -36,7 +36,7 @@ template <unsigned int N> struct STOP_EXTERNING_ME {}; | ||||
| #include "furi-hal-usb.h" | ||||
| #include "furi-hal-usb-hid.h" | ||||
| #include "furi-hal-compress.h" | ||||
| #include "furi-hal-lpuart.h" | ||||
| #include "furi-hal-uart.h" | ||||
| 
 | ||||
| /** Init furi-hal */ | ||||
| void furi_hal_init(); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nikolay Minaylov
						Nikolay Minaylov