diff --git a/applications/gpio/gpio_app_i.h b/applications/gpio/gpio_app_i.h index bfeab404..226fa06e 100644 --- a/applications/gpio/gpio_app_i.h +++ b/applications/gpio/gpio_app_i.h @@ -12,6 +12,14 @@ #include #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; diff --git a/applications/gpio/scenes/gpio_scene_start.c b/applications/gpio/scenes/gpio_scene_start.c index b3ed40fd..b7d94fe7 100644 --- a/applications/gpio/scenes/gpio_scene_start.c +++ b/applications/gpio/scenes/gpio_scene_start.c @@ -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, diff --git a/applications/gpio/scenes/gpio_scene_usb_uart.c b/applications/gpio/scenes/gpio_scene_usb_uart.c index 05de8e7b..c8ec0141 100644 --- a/applications/gpio/scenes/gpio_scene_usb_uart.c +++ b/applications/gpio/scenes/gpio_scene_usb_uart.c @@ -1,17 +1,6 @@ +#include "../usb_uart_bridge.h" #include "../gpio_app_i.h" #include "furi-hal.h" -#include -#include -#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); -} \ No newline at end of file + free(cfg_set); +} diff --git a/applications/gpio/usb_uart_bridge.c b/applications/gpio/usb_uart_bridge.c new file mode 100644 index 00000000..b50cc158 --- /dev/null +++ b/applications/gpio/usb_uart_bridge.c @@ -0,0 +1,246 @@ +#include "usb_uart_bridge.h" +#include "furi-hal.h" +#include +#include +#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; + } +} diff --git a/applications/gpio/usb_uart_bridge.h b/applications/gpio/usb_uart_bridge.h new file mode 100644 index 00000000..2fe6d1d8 --- /dev/null +++ b/applications/gpio/usb_uart_bridge.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +typedef struct { + uint8_t vcp_ch; + uint8_t uart_ch; + uint32_t baudrate; +} UsbUartConfig; + +void usb_uart_enable(UsbUartConfig* cfg); + +void usb_uart_disable(); diff --git a/firmware/targets/f6/furi-hal/furi-hal-clock.c b/firmware/targets/f6/furi-hal/furi-hal-clock.c index 2544c769..fd4899d4 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-clock.c +++ b/firmware/targets/f6/furi-hal/furi-hal-clock.c @@ -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); diff --git a/firmware/targets/f6/furi-hal/furi-hal-console.c b/firmware/targets/f6/furi-hal/furi-hal-console.c index 552f9e77..ffe340b9 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-console.c +++ b/firmware/targets/f6/furi-hal/furi-hal-console.c @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -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)); -} \ No newline at end of file +} diff --git a/firmware/targets/f6/furi-hal/furi-hal-console.h b/firmware/targets/f6/furi-hal/furi-hal-console.h index 013653ba..4c10d81e 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-console.h +++ b/firmware/targets/f6/furi-hal/furi-hal-console.h @@ -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 diff --git a/firmware/targets/f6/furi-hal/furi-hal-lpuart.c b/firmware/targets/f6/furi-hal/furi-hal-lpuart.c deleted file mode 100644 index 31aa8b86..00000000 --- a/firmware/targets/f6/furi-hal/furi-hal-lpuart.c +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include -#include -#include - -#include - -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 -} diff --git a/firmware/targets/f6/furi-hal/furi-hal-lpuart.h b/firmware/targets/f6/furi-hal/furi-hal-lpuart.h deleted file mode 100644 index 118a9a9c..00000000 --- a/firmware/targets/f6/furi-hal/furi-hal-lpuart.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include -#include -#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 diff --git a/firmware/targets/f6/furi-hal/furi-hal-uart.c b/firmware/targets/f6/furi-hal/furi-hal-uart.c new file mode 100644 index 00000000..ff2d94a7 --- /dev/null +++ b/firmware/targets/f6/furi-hal/furi-hal-uart.c @@ -0,0 +1,201 @@ +#include +#include +#include +#include +#include + +#include + +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); + } +} diff --git a/firmware/targets/f6/furi-hal/furi-hal-uart.h b/firmware/targets/f6/furi-hal/furi-hal-uart.h new file mode 100644 index 00000000..6be156b7 --- /dev/null +++ b/firmware/targets/f6/furi-hal/furi-hal-uart.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#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 diff --git a/firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c b/firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c index e643fe57..9386b100 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c +++ b/firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c @@ -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 diff --git a/firmware/targets/f7/furi-hal/furi-hal-clock.c b/firmware/targets/f7/furi-hal/furi-hal-clock.c index 2544c769..fd4899d4 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-clock.c +++ b/firmware/targets/f7/furi-hal/furi-hal-clock.c @@ -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); diff --git a/firmware/targets/f7/furi-hal/furi-hal-console.c b/firmware/targets/f7/furi-hal/furi-hal-console.c index 552f9e77..ffe340b9 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-console.c +++ b/firmware/targets/f7/furi-hal/furi-hal-console.c @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -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)); -} \ No newline at end of file +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-console.h b/firmware/targets/f7/furi-hal/furi-hal-console.h index 013653ba..4c10d81e 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-console.h +++ b/firmware/targets/f7/furi-hal/furi-hal-console.h @@ -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 diff --git a/firmware/targets/f7/furi-hal/furi-hal-lpuart.c b/firmware/targets/f7/furi-hal/furi-hal-lpuart.c deleted file mode 100644 index 31aa8b86..00000000 --- a/firmware/targets/f7/furi-hal/furi-hal-lpuart.c +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include -#include -#include - -#include - -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 -} diff --git a/firmware/targets/f7/furi-hal/furi-hal-lpuart.h b/firmware/targets/f7/furi-hal/furi-hal-lpuart.h deleted file mode 100644 index 118a9a9c..00000000 --- a/firmware/targets/f7/furi-hal/furi-hal-lpuart.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include -#include -#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 diff --git a/firmware/targets/f7/furi-hal/furi-hal-uart.c b/firmware/targets/f7/furi-hal/furi-hal-uart.c new file mode 100644 index 00000000..c6e74101 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-uart.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include + +#include + +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); + } +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-uart.h b/firmware/targets/f7/furi-hal/furi-hal-uart.h new file mode 100644 index 00000000..6be156b7 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-uart.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#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 diff --git a/firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c b/firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c index e643fe57..9386b100 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c +++ b/firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c @@ -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 diff --git a/firmware/targets/furi-hal-include/furi-hal.h b/firmware/targets/furi-hal-include/furi-hal.h index 4ac95d82..eb1fefeb 100644 --- a/firmware/targets/furi-hal-include/furi-hal.h +++ b/firmware/targets/furi-hal-include/furi-hal.h @@ -36,7 +36,7 @@ template 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();