[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 <gui/modules/variable-item-list.h> | ||||||
| #include "views/gpio_test.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 { | struct GpioApp { | ||||||
|     Gui* gui; |     Gui* gui; | ||||||
|     ViewDispatcher* view_dispatcher; |     ViewDispatcher* view_dispatcher; | ||||||
|  | |||||||
| @ -1,11 +1,6 @@ | |||||||
| #include "../gpio_app_i.h" | #include "../gpio_app_i.h" | ||||||
| #include "furi-hal-power.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 { | enum GpioItem { | ||||||
|     GpioItemOtg, |     GpioItemOtg, | ||||||
|     GpioItemTest, |     GpioItemTest, | ||||||
|  | |||||||
| @ -1,17 +1,6 @@ | |||||||
|  | #include "../usb_uart_bridge.h" | ||||||
| #include "../gpio_app_i.h" | #include "../gpio_app_i.h" | ||||||
| #include "furi-hal.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 { | typedef enum { | ||||||
|     UsbUartLineIndexVcp, |     UsbUartLineIndexVcp, | ||||||
| @ -21,42 +10,7 @@ typedef enum { | |||||||
|     UsbUartLineIndexDisable, |     UsbUartLineIndexDisable, | ||||||
| } LineIndex; | } LineIndex; | ||||||
| 
 | 
 | ||||||
| typedef enum { | static UsbUartConfig* cfg_set; | ||||||
|     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 const char* vcp_ch[] = {"0 (CLI)", "1"}; | static const char* vcp_ch[] = {"0 (CLI)", "1"}; | ||||||
| static const char* uart_ch[] = {"USART1", "LPUART1"}; | static const char* uart_ch[] = {"USART1", "LPUART1"}; | ||||||
| @ -73,197 +27,14 @@ static const uint32_t baudrate_list[] = { | |||||||
|     921600, |     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) { | bool gpio_scene_usb_uart_on_event(void* context, SceneManagerEvent event) { | ||||||
|     //GpioApp* app = context;
 |     //GpioApp* app = context;
 | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == UsbUartLineIndexEnable) { |         if(event.event == GPIO_SCENE_USB_UART_CUSTOM_EVENT_ENABLE) { | ||||||
|             usb_uart_enable(); |             usb_uart_enable(cfg_set); | ||||||
|         } else if(event.event == UsbUartLineIndexDisable) { |         } else if(event.event == GPIO_SCENE_USB_UART_CUSTOM_EVENT_DISABLE) { | ||||||
|             usb_uart_disable(); |             usb_uart_disable(); | ||||||
|         } |         } | ||||||
|         consumed = true; |         consumed = true; | ||||||
| @ -271,15 +42,13 @@ bool gpio_scene_usb_uart_on_event(void* context, SceneManagerEvent event) { | |||||||
|     return consumed; |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Scene callbacks */ |  | ||||||
| 
 |  | ||||||
| static void line_vcp_cb(VariableItem* item) { | static void line_vcp_cb(VariableItem* item) { | ||||||
|     //GpioApp* app = variable_item_get_context(item);
 |     //GpioApp* app = variable_item_get_context(item);
 | ||||||
|     uint8_t index = variable_item_get_current_value_index(item); |     uint8_t index = variable_item_get_current_value_index(item); | ||||||
| 
 | 
 | ||||||
|     variable_item_set_current_value_text(item, vcp_ch[index]); |     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) { | 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]); |     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) { | static void line_baudrate_cb(VariableItem* item) { | ||||||
|     //GpioApp* app = variable_item_get_context(item);
 |     //GpioApp* app = variable_item_get_context(item);
 | ||||||
|     uint8_t index = variable_item_get_current_value_index(item); |     uint8_t index = variable_item_get_current_value_index(item); | ||||||
| 
 | 
 | ||||||
|  |     char br_text[8]; | ||||||
|  | 
 | ||||||
|     if(index > 0) { |     if(index > 0) { | ||||||
|         snprintf(usb_uart->br_text, 7, "%lu", baudrate_list[index - 1]); |         snprintf(br_text, 7, "%lu", baudrate_list[index - 1]); | ||||||
|         variable_item_set_current_value_text(item, usb_uart->br_text); |         variable_item_set_current_value_text(item, br_text); | ||||||
|         usb_uart->cfg_set.baudrate = baudrate_list[index - 1]; |         cfg_set->baudrate = baudrate_list[index - 1]; | ||||||
|     } else { |     } else { | ||||||
|         variable_item_set_current_value_text(item, baudrate_mode[index]); |         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) { | static void gpio_scene_usb_uart_enter_callback(void* context, uint32_t index) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     GpioApp* app = 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) { | void gpio_scene_usb_uart_on_enter(void* context) { | ||||||
|     GpioApp* app = context; |     GpioApp* app = context; | ||||||
|     VariableItemList* var_item_list = app->var_item_list; |     VariableItemList* var_item_list = app->var_item_list; | ||||||
| 
 | 
 | ||||||
|     usb_uart = furi_alloc(sizeof(UsbUartParams)); |     cfg_set = furi_alloc(sizeof(UsbUartConfig)); | ||||||
| 
 | 
 | ||||||
|     VariableItem* item; |     VariableItem* item; | ||||||
| 
 | 
 | ||||||
| @ -348,5 +127,5 @@ void gpio_scene_usb_uart_on_exit(void* context) { | |||||||
|     GpioApp* app = context; |     GpioApp* app = context; | ||||||
|     usb_uart_disable(); |     usb_uart_disable(); | ||||||
|     variable_item_list_clean(app->var_item_list); |     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_EnableRTC(); | ||||||
| 
 | 
 | ||||||
|     LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); |     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_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_PLLSAI1); | ||||||
|     LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); |     LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); | ||||||
|     LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); |     LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); | ||||||
| @ -117,6 +118,7 @@ void furi_hal_clock_init() { | |||||||
|     // APB1
 |     // APB1
 | ||||||
|     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB); |     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB); | ||||||
|     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); |     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); | ||||||
|  |     LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1); | ||||||
| 
 | 
 | ||||||
|     // APB2
 |     // APB2
 | ||||||
|     LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1); |     LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1); | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| #include <furi-hal-console.h> | #include <furi-hal-console.h> | ||||||
| #include <furi-hal-lpuart.h> | #include <furi-hal-uart.h> | ||||||
| 
 | 
 | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <stm32wbxx_ll_gpio.h> | #include <stm32wbxx_ll_gpio.h> | ||||||
| @ -12,98 +12,23 @@ | |||||||
| 
 | 
 | ||||||
| volatile bool furi_hal_console_alive = false; | volatile bool furi_hal_console_alive = false; | ||||||
| 
 | 
 | ||||||
| static void (*irq_cb)(uint8_t ev, uint8_t data); |  | ||||||
| 
 |  | ||||||
| void furi_hal_console_init() { | void furi_hal_console_init() { | ||||||
|     LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; |     furi_hal_uart_init(FuriHalUartIdUSART1, CONSOLE_BAUDRATE); | ||||||
|     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_console_alive = true; |     furi_hal_console_alive = true; | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I("FuriHalConsole", "Init OK"); |     FURI_LOG_I("FuriHalConsole", "Init OK"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_usart_init() { | void furi_hal_console_enable() { | ||||||
|     furi_hal_console_alive = false; |     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, NULL); | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 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)); |     while (!LL_USART_IsActiveFlag_TC(USART1)); | ||||||
|         LL_USART_Disable(USART1); |     furi_hal_uart_set_br(FuriHalUartIdUSART1, CONSOLE_BAUDRATE); | ||||||
|         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() { |  | ||||||
|     while (!LL_USART_IsActiveFlag_TC(USART1)); |  | ||||||
|     furi_hal_usart_set_br(CONSOLE_BAUDRATE); |  | ||||||
|     furi_hal_console_alive = true; |     furi_hal_console_alive = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_usart_tx(const uint8_t* buffer, size_t buffer_size) { | void furi_hal_console_disable() { | ||||||
|     if (LL_USART_IsEnabled(USART1) == 0) |     while (!LL_USART_IsActiveFlag_TC(USART1)); | ||||||
|         return; |     furi_hal_console_alive = false; | ||||||
| 
 |  | ||||||
|     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_tx(const uint8_t* buffer, size_t buffer_size) { | 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; |         return; | ||||||
| 
 | 
 | ||||||
|     // Transmit data
 |     // 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
 |     // Wait for TC flag to be raised for last char
 | ||||||
|     while (!LL_USART_IsActiveFlag_TC(USART1)); |     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; |         return; | ||||||
| 
 | 
 | ||||||
|     // Transmit data
 |     // Transmit data
 | ||||||
|     furi_hal_usart_tx(buffer, buffer_size); |     furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)buffer, buffer_size); | ||||||
|     // Transmit new line symbols
 |     // 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
 |     // Wait for TC flag to be raised for last char
 | ||||||
|     while (!LL_USART_IsActiveFlag_TC(USART1)); |     while (!LL_USART_IsActiveFlag_TC(USART1)); | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,6 +15,10 @@ typedef enum { | |||||||
| 
 | 
 | ||||||
| void furi_hal_console_init(); | 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(const uint8_t* buffer, size_t buffer_size); | ||||||
| 
 | 
 | ||||||
| void furi_hal_console_tx_with_new_line(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_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 | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #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" | #include "usb_cdc.h" | ||||||
| 
 | 
 | ||||||
| #define CDC0_RXD_EP      0x01 | #define CDC0_RXD_EP      0x01 | ||||||
| #define CDC0_TXD_EP      0x82 | #define CDC0_TXD_EP      0x81 | ||||||
| #define CDC0_NTF_EP      0x83 | #define CDC0_NTF_EP      0x82 | ||||||
| 
 | 
 | ||||||
| #define CDC1_RXD_EP      0x04 | #define CDC1_RXD_EP      0x03 | ||||||
| #define CDC1_TXD_EP      0x85 | #define CDC1_TXD_EP      0x83 | ||||||
| #define CDC1_NTF_EP      0x86 | #define CDC1_NTF_EP      0x84 | ||||||
| 
 | 
 | ||||||
| #define CDC_NTF_SZ      0x08 | #define CDC_NTF_SZ      0x08 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -84,6 +84,7 @@ void furi_hal_clock_init() { | |||||||
|     LL_RCC_EnableRTC(); |     LL_RCC_EnableRTC(); | ||||||
| 
 | 
 | ||||||
|     LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); |     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_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_PLLSAI1); | ||||||
|     LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); |     LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); | ||||||
|     LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); |     LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); | ||||||
| @ -117,6 +118,7 @@ void furi_hal_clock_init() { | |||||||
|     // APB1
 |     // APB1
 | ||||||
|     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB); |     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB); | ||||||
|     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); |     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); | ||||||
|  |     LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1); | ||||||
| 
 | 
 | ||||||
|     // APB2
 |     // APB2
 | ||||||
|     LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1); |     LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1); | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| #include <furi-hal-console.h> | #include <furi-hal-console.h> | ||||||
| #include <furi-hal-lpuart.h> | #include <furi-hal-uart.h> | ||||||
| 
 | 
 | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <stm32wbxx_ll_gpio.h> | #include <stm32wbxx_ll_gpio.h> | ||||||
| @ -12,98 +12,23 @@ | |||||||
| 
 | 
 | ||||||
| volatile bool furi_hal_console_alive = false; | volatile bool furi_hal_console_alive = false; | ||||||
| 
 | 
 | ||||||
| static void (*irq_cb)(uint8_t ev, uint8_t data); |  | ||||||
| 
 |  | ||||||
| void furi_hal_console_init() { | void furi_hal_console_init() { | ||||||
|     LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; |     furi_hal_uart_init(FuriHalUartIdUSART1, CONSOLE_BAUDRATE); | ||||||
|     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_console_alive = true; |     furi_hal_console_alive = true; | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I("FuriHalConsole", "Init OK"); |     FURI_LOG_I("FuriHalConsole", "Init OK"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_usart_init() { | void furi_hal_console_enable() { | ||||||
|     furi_hal_console_alive = false; |     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, NULL); | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 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)); |     while (!LL_USART_IsActiveFlag_TC(USART1)); | ||||||
|         LL_USART_Disable(USART1); |     furi_hal_uart_set_br(FuriHalUartIdUSART1, CONSOLE_BAUDRATE); | ||||||
|         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() { |  | ||||||
|     while (!LL_USART_IsActiveFlag_TC(USART1)); |  | ||||||
|     furi_hal_usart_set_br(CONSOLE_BAUDRATE); |  | ||||||
|     furi_hal_console_alive = true; |     furi_hal_console_alive = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_usart_tx(const uint8_t* buffer, size_t buffer_size) { | void furi_hal_console_disable() { | ||||||
|     if (LL_USART_IsEnabled(USART1) == 0) |     while (!LL_USART_IsActiveFlag_TC(USART1)); | ||||||
|         return; |     furi_hal_console_alive = false; | ||||||
| 
 |  | ||||||
|     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_tx(const uint8_t* buffer, size_t buffer_size) { | 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; |         return; | ||||||
| 
 | 
 | ||||||
|     // Transmit data
 |     // 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
 |     // Wait for TC flag to be raised for last char
 | ||||||
|     while (!LL_USART_IsActiveFlag_TC(USART1)); |     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; |         return; | ||||||
| 
 | 
 | ||||||
|     // Transmit data
 |     // Transmit data
 | ||||||
|     furi_hal_usart_tx(buffer, buffer_size); |     furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)buffer, buffer_size); | ||||||
|     // Transmit new line symbols
 |     // 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
 |     // Wait for TC flag to be raised for last char
 | ||||||
|     while (!LL_USART_IsActiveFlag_TC(USART1)); |     while (!LL_USART_IsActiveFlag_TC(USART1)); | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,6 +15,10 @@ typedef enum { | |||||||
| 
 | 
 | ||||||
| void furi_hal_console_init(); | 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(const uint8_t* buffer, size_t buffer_size); | ||||||
| 
 | 
 | ||||||
| void furi_hal_console_tx_with_new_line(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_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 | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #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" | #include "usb_cdc.h" | ||||||
| 
 | 
 | ||||||
| #define CDC0_RXD_EP      0x01 | #define CDC0_RXD_EP      0x01 | ||||||
| #define CDC0_TXD_EP      0x82 | #define CDC0_TXD_EP      0x81 | ||||||
| #define CDC0_NTF_EP      0x83 | #define CDC0_NTF_EP      0x82 | ||||||
| 
 | 
 | ||||||
| #define CDC1_RXD_EP      0x04 | #define CDC1_RXD_EP      0x03 | ||||||
| #define CDC1_TXD_EP      0x85 | #define CDC1_TXD_EP      0x83 | ||||||
| #define CDC1_NTF_EP      0x86 | #define CDC1_NTF_EP      0x84 | ||||||
| 
 | 
 | ||||||
| #define CDC_NTF_SZ      0x08 | #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.h" | ||||||
| #include "furi-hal-usb-hid.h" | #include "furi-hal-usb-hid.h" | ||||||
| #include "furi-hal-compress.h" | #include "furi-hal-compress.h" | ||||||
| #include "furi-hal-lpuart.h" | #include "furi-hal-uart.h" | ||||||
| 
 | 
 | ||||||
| /** Init furi-hal */ | /** Init furi-hal */ | ||||||
| void furi_hal_init(); | void furi_hal_init(); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nikolay Minaylov
						Nikolay Minaylov