From 27c95abeba400c975bf204f6a6aff0c414c1f044 Mon Sep 17 00:00:00 2001 From: Andrey Perminov Date: Tue, 21 Dec 2021 12:35:20 -0800 Subject: [PATCH] Added support for BM-Lite UART interface. Implemented UART interface support in stm32Wb55 HAL --- .vscode/c_cpp_properties.json | 18 + .vscode/launch.json | 24 +- .vscode/tasks.json | 2 +- Arduino_lib/BMLite/src/bmlite_hal.h | 20 +- BMLite_examples/Makefile | 7 + BMLite_examples/embedded_app/src/main.c | 5 + BMLite_sdk/inc/bmlite_hal.h | 16 + BMLite_sdk/inc/platform.h | 6 +- BMLite_sdk/src/platform.c | 54 ++- HAL_Driver/RaspberryPi/src/platform_rpi.c | 4 +- HAL_Driver/RaspberryPi/src/rpi_com.c | 16 +- HAL_Driver/nRF52840/src/hal_leds.c | 2 +- HAL_Driver/nRF52840/src/hal_spi.c | 7 +- HAL_Driver/nRF52840/src/hal_timebase.c | 2 +- HAL_Driver/nRF52840/src/hal_uart.c | 29 ++ HAL_Driver/stm32wb55/inc/hal_config.h | 26 ++ HAL_Driver/stm32wb55/inc/stm32wbxx_hal_conf.h | 4 +- HAL_Driver/stm32wb55/src/hal_board.c | 9 + HAL_Driver/stm32wb55/src/hal_buttons.c | 2 +- HAL_Driver/stm32wb55/src/hal_leds.c | 2 +- HAL_Driver/stm32wb55/src/hal_spi.c | 8 +- HAL_Driver/stm32wb55/src/hal_uart.c | 359 ++++++++++++++++++ HAL_Driver/stm32wb55/stm32wb55.mk | 4 + README.md | 20 +- 24 files changed, 597 insertions(+), 49 deletions(-) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 HAL_Driver/nRF52840/src/hal_uart.c create mode 100644 HAL_Driver/stm32wb55/src/hal_uart.c diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..c1ebe43 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "Linux", + "defines": ["BMLITE_ON_UART", "NRF52840_XXAA", "BOARD_PCA10056", "BMLITE_USE_CALLBACK"], + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "${default}", + "compilerPath": "/usr/bin/arm-none-eabi-gcc", + "compilerArgs": [ + "-mcpu=cortex-m4", + "-mthumb", + "-mfloat-abi=hard" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 14567a8..895e143 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,17 +14,17 @@ "device": "STM32WB55xx", "interface": "swd", "runToMain": true, - } - { - "name": "Cortex Debug nRF52840", - "cwd": "${workspaceRoot}", - "executable": "${workspaceRoot}/BMLite_examples/out/embedded_app/nRF52840/embedded_app", - "request": "launch", - "type": "cortex-debug", - "servertype": "jlink", - "device": "nRF52840_xxAA", - "interface": "swd", - "runToMain": true, - } + }, + // { + // "name": "Cortex Debug nRF52840", + // "cwd": "${workspaceRoot}", + // "executable": "${workspaceRoot}/BMLite_examples/out/embedded_app/nRF52840/embedded_app", + // "request": "launch", + // "type": "cortex-debug", + // "servertype": "jlink", + // "device": "nRF52840_xxAA", + // "interface": "swd", + // "runToMain": true, + // } ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2ce5310..cc1fd58 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,7 +7,7 @@ "type": "shell", "label": "wb55 make", "command": "make", - "args": ["-j4", "-C", "BMLite_examples", "PLATFORM=stm32wb55", "APP=embedded_app", "DEBUG=y"], + "args": ["-j4", "-C", "BMLite_examples", "PLATFORM=stm32wb55", "PORT=UART", "APP=embedded_app", "DEBUG=y"], "options": { "cwd": "${workspaceFolder}" }, diff --git a/Arduino_lib/BMLite/src/bmlite_hal.h b/Arduino_lib/BMLite/src/bmlite_hal.h index a9a1c27..120df62 100644 --- a/Arduino_lib/BMLite/src/bmlite_hal.h +++ b/Arduino_lib/BMLite/src/bmlite_hal.h @@ -73,7 +73,25 @@ void hal_bmlite_reset(bool state); * @param[in] Leave CS asserted * @return ::fpc_bep_result_t */ -fpc_bep_result_t hal_bmlite_spi_write_read(uint8_t *buff, size_t size); +fpc_bep_result_t hal_bmlite_spi_write_read(uint8_t *write, uint8_t *read, size_t size, + bool leave_cs_asserted); + +/* + * @brief UART write + * @param[in] Write buffer + * @param[in] Size + * @return ::size_t Number of bytes actually written + */ +size_t hal_bmlite_uart_write(const uint8_t *data, size_t size); + +/* + * @brief UART read + * @param[in] Read buffer + * @param[in] Size + * @return ::size_t Number of butes actually read + */ +size_t hal_bmlite_uart_read(uint8_t *buff, size_t size); + /* * @brief Check if BM-Lite IRQ pin is set diff --git a/BMLite_examples/Makefile b/BMLite_examples/Makefile index e6a73af..796a395 100644 --- a/BMLite_examples/Makefile +++ b/BMLite_examples/Makefile @@ -72,6 +72,13 @@ CFLAGS +=\ -MMD \ -MP +ifeq ($(PORT),UART) +CFLAGS += -DBMLITE_ON_UART +else +CFLAGS += -DBMLITE_ON_SPI +endif + + ifeq ($(DEBUG),y) CFLAGS +=\ -g3\ diff --git a/BMLite_examples/embedded_app/src/main.c b/BMLite_examples/embedded_app/src/main.c index 018db91..4128139 100644 --- a/BMLite_examples/embedded_app/src/main.c +++ b/BMLite_examples/embedded_app/src/main.c @@ -36,8 +36,13 @@ static uint8_t hcp_txrx_buffer[MTU]; static uint8_t hcp_data_buffer[DATA_BUFFER_SIZE]; static HCP_comm_t hcp_chain = { +#ifdef BMLITE_ON_UART + .read = platform_bmlite_uart_receive, + .write = platform_bmlite_uart_send, +#else .read = platform_bmlite_spi_receive, .write = platform_bmlite_spi_send, +#endif .pkt_buffer = hcp_data_buffer, .txrx_buffer = hcp_txrx_buffer, .pkt_size = 0, diff --git a/BMLite_sdk/inc/bmlite_hal.h b/BMLite_sdk/inc/bmlite_hal.h index 6c2fb74..a98c68d 100755 --- a/BMLite_sdk/inc/bmlite_hal.h +++ b/BMLite_sdk/inc/bmlite_hal.h @@ -76,6 +76,22 @@ void hal_bmlite_reset(bool state); fpc_bep_result_t hal_bmlite_spi_write_read(uint8_t *write, uint8_t *read, size_t size, bool leave_cs_asserted); +/* + * @brief UART write + * @param[in] Write buffer + * @param[in] Size + * @return ::size_t Number of bytes actually written + */ +size_t hal_bmlite_uart_write(const uint8_t *data, size_t size); + +/* + * @brief UART read + * @param[in] Read buffer + * @param[in] Size + * @return ::size_t Number of butes actually read + */ +size_t hal_bmlite_uart_read(uint8_t *buff, size_t size); + /* * @brief Check if BM-Lite IRQ pin is set * @return ::bool diff --git a/BMLite_sdk/inc/platform.h b/BMLite_sdk/inc/platform.h index 2bf37c7..f62ad72 100644 --- a/BMLite_sdk/inc/platform.h +++ b/BMLite_sdk/inc/platform.h @@ -65,8 +65,7 @@ fpc_bep_result_t platform_bmlite_spi_send(uint16_t size, const uint8_t *data, ui * * @return ::fpc_com_result_t */ -fpc_bep_result_t platform_bmlite_uart_send(uint16_t size, const uint8_t *data, uint32_t timeout, - void *session); +fpc_bep_result_t platform_bmlite_uart_send(uint16_t size, const uint8_t *data, uint32_t timeout); /** * @brief Receives data from SPI port in blocking mode. @@ -88,8 +87,7 @@ fpc_bep_result_t platform_bmlite_spi_receive(uint16_t size, uint8_t *data, uint3 * * @return ::fpc_com_result_t */ -fpc_bep_result_t platform_bmlite_uart_receive(uint16_t size, uint8_t *data, uint32_t timeout, - void *session); +fpc_bep_result_t platform_bmlite_uart_receive(uint16_t size, uint8_t *data, uint32_t timeout); /** * @brief Stops execution if a debug interface is attached. diff --git a/BMLite_sdk/src/platform.c b/BMLite_sdk/src/platform.c index a013bc0..b42e2e0 100644 --- a/BMLite_sdk/src/platform.c +++ b/BMLite_sdk/src/platform.c @@ -36,9 +36,9 @@ fpc_bep_result_t platform_init(void *params) { fpc_bep_result_t result; + hal_timebase_init(); result = hal_board_init(params); if(result == FPC_BEP_RESULT_OK) { - hal_timebase_init(); platform_bmlite_reset(); } return result; @@ -52,6 +52,56 @@ void platform_bmlite_reset(void) hal_timebase_busy_wait(100); } +#ifdef BMLITE_ON_UART + +fpc_bep_result_t platform_bmlite_uart_send(uint16_t size, const uint8_t *data, uint32_t timeout) +{ + #ifdef DEBUG_COMM + LOG_DEBUG("-> "); + for (int i=0; iiface == COM_INTERFACE) { - p->hcp_comm->read = rpi_com_receive; - p->hcp_comm->write = rpi_com_send; + p->hcp_comm->read = platform_bmlite_uart_receive; + p->hcp_comm->write = platform_bmlite_uart_send; } else { p->hcp_comm->read = platform_bmlite_spi_receive; p->hcp_comm->write = platform_bmlite_spi_send; diff --git a/HAL_Driver/RaspberryPi/src/rpi_com.c b/HAL_Driver/RaspberryPi/src/rpi_com.c index 997ec3b..102fdcc 100644 --- a/HAL_Driver/RaspberryPi/src/rpi_com.c +++ b/HAL_Driver/RaspberryPi/src/rpi_com.c @@ -84,26 +84,20 @@ bool rpi_com_init(char *port, int baudrate, int timeout) return true; } -fpc_bep_result_t rpi_com_send(uint16_t size, const uint8_t *data, uint32_t timeout) +size_t hal_bmlite_uart_write(const uint8_t *data, size_t size) { - fpc_bep_result_t res = FPC_BEP_RESULT_OK; int n; if (fd < 0) { fprintf(stderr, "error invalid file descriptor"); - return FPC_BEP_RESULT_INVALID_ARGUMENT; + return 0; } - n = write(fd, data, size); + return write(fd, data, size); - if (n != size) { - res = FPC_BEP_RESULT_IO_ERROR; - } - - return res; } -fpc_bep_result_t rpi_com_receive(uint16_t size, uint8_t *data, uint32_t timeout) +size_t hal_bmlite_uart_read(uint8_t *data, size_t size) { fpc_bep_result_t res = FPC_BEP_RESULT_OK; int n_read = 0; @@ -136,7 +130,7 @@ fpc_bep_result_t rpi_com_receive(uint16_t size, uint8_t *data, uint32_t timeout) } } - return res; + return n_read; } diff --git a/HAL_Driver/nRF52840/src/hal_leds.c b/HAL_Driver/nRF52840/src/hal_leds.c index f75245b..249c79c 100644 --- a/HAL_Driver/nRF52840/src/hal_leds.c +++ b/HAL_Driver/nRF52840/src/hal_leds.c @@ -19,7 +19,7 @@ /** - * @file board_leds.c + * @file hal_leds.c * @brief Leds control functions. */ diff --git a/HAL_Driver/nRF52840/src/hal_spi.c b/HAL_Driver/nRF52840/src/hal_spi.c index 72b7d59..90296f9 100755 --- a/HAL_Driver/nRF52840/src/hal_spi.c +++ b/HAL_Driver/nRF52840/src/hal_spi.c @@ -18,10 +18,12 @@ */ /** - * @file platform_spi.c - * @brief SPI functions + * @file hal_spi.c + * @brief SPI HAL functions */ +#ifdef BMLITE_ON_SPI + #include "nrf_drv_spi.h" #include "boards.h" #include "nrf_gpio.h" @@ -110,3 +112,4 @@ void nordic_bmlite_spi_init(uint32_t speed_hz) nrf_drv_gpiote_out_init(BMLITE_CS_PIN, &out_config); } +#endif \ No newline at end of file diff --git a/HAL_Driver/nRF52840/src/hal_timebase.c b/HAL_Driver/nRF52840/src/hal_timebase.c index ae34f2e..7538b0f 100755 --- a/HAL_Driver/nRF52840/src/hal_timebase.c +++ b/HAL_Driver/nRF52840/src/hal_timebase.c @@ -18,7 +18,7 @@ */ /** - * @file platform_timebase.c + * @file hal_timebase.c * @brief timebase interface functions */ diff --git a/HAL_Driver/nRF52840/src/hal_uart.c b/HAL_Driver/nRF52840/src/hal_uart.c new file mode 100644 index 0000000..ed1ed4a --- /dev/null +++ b/HAL_Driver/nRF52840/src/hal_uart.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 Fingerprint Cards AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Modified by Andrey Perminov + * for FPC BM-Lite applications + */ + +/** + * @file hal_uart.c + * @brief UART HAL functions + */ + +#ifdef BMLITE_ON_UART + +#error "UART HAL for nRF52840 is not implemented yet" + +#endif diff --git a/HAL_Driver/stm32wb55/inc/hal_config.h b/HAL_Driver/stm32wb55/inc/hal_config.h index 0206711..2c364ab 100644 --- a/HAL_Driver/stm32wb55/inc/hal_config.h +++ b/HAL_Driver/stm32wb55/inc/hal_config.h @@ -68,6 +68,32 @@ #define BMLITE_SPI_DMA_IRQn_TX DMA1_Channel3_IRQn #define BMLITE_SPI_DMA_IRQ_HANDLER_TX DMA1_Channel3_IRQHandler +/** + * Configuration of UART used for BM-Lite communication. +*/ +#define FPC_BMLITE_USART USART1 +#define FPC_BMLITE_USART_AF GPIO_AF7_USART1 +#define FPC_BMLITE_USART_CLK_ENABLE __HAL_RCC_USART1_CLK_ENABLE +#define FPC_BMLITE_USART_IRQn USART1_IRQn +#define FPC_BMLITE_USART_IRQ_HANDLER USART1_IRQHandler + +#define FPC_BMLITE_USART_RX_PORT GPIOA +#define FPC_BMLITE_USART_RX_PIN GPIO_PIN_10 +#define FPC_BMLITE_USART_TX_PORT GPIOA +#define FPC_BMLITE_USART_TX_PIN GPIO_PIN_9 +#define FPC_BMLITE_USART_RX_PORT_CLK_ENABLE __HAL_RCC_GPIOA_CLK_ENABLE +#define FPC_BMLITE_USART_TX_PORT_CLK_ENABLE __HAL_RCC_GPIOB_CLK_ENABLE + +#define FPC_BMLITE_USART_DMA_CHANNEL_RX DMA1_Channel6 +#define FPC_BMLITE_USART_DMA_REQ_RX DMA_REQUEST_USART1_RX +#define FPC_BMLITE_USART_DMA_IRQn_RX DMA1_Channel6_IRQn +#define FPC_BMLITE_USART_DMA_IRQ_HANDLER_RX DMA1_Channel6_IRQHandler +#define FPC_BMLITE_USART_DMA_CHANNEL_TX DMA1_Channel7 +#define FPC_BMLITE_USART_DMA_REQ_TX DMA_REQUEST_USART1_TX +#define FPC_BMLITE_USART_DMA_IRQn_TX DMA1_Channel7_IRQn +#define FPC_BMLITE_USART_DMA_IRQ_HANDLER_TX DMA1_Channel7_IRQHandler + + /** * Configuration of GPIO used for sensor reset / sensor interrupt. */ diff --git a/HAL_Driver/stm32wb55/inc/stm32wbxx_hal_conf.h b/HAL_Driver/stm32wb55/inc/stm32wbxx_hal_conf.h index c5a4f4d..899bf5b 100644 --- a/HAL_Driver/stm32wb55/inc/stm32wbxx_hal_conf.h +++ b/HAL_Driver/stm32wb55/inc/stm32wbxx_hal_conf.h @@ -56,8 +56,8 @@ #define HAL_SPI_MODULE_ENABLED /*#define HAL_TIM_MODULE_ENABLED */ /*#define HAL_TSC_MODULE_ENABLED */ -/*#define HAL_UART_MODULE_ENABLED */ -/*#define HAL_USART_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ /*#define HAL_WWDG_MODULE_ENABLED */ #define HAL_EXTI_MODULE_ENABLED #define HAL_CORTEX_MODULE_ENABLED diff --git a/HAL_Driver/stm32wb55/src/hal_board.c b/HAL_Driver/stm32wb55/src/hal_board.c index 3c253e7..13b701d 100644 --- a/HAL_Driver/stm32wb55/src/hal_board.c +++ b/HAL_Driver/stm32wb55/src/hal_board.c @@ -36,6 +36,7 @@ static void dma_init(); static void system_irq_init(); void stm_spi_init(uint32_t speed_hz); +void stm_uart_init(uint32_t speed_hz); void board_led_init(); void board_button_init(); @@ -60,7 +61,15 @@ fpc_bep_result_t hal_board_init(void *params) /* Initialize DMA */ dma_init(); +#ifdef BMLITE_ON_UART + stm_uart_init(115200); +#else +#ifdef BMLITE_ON_SPI stm_spi_init(4000000); +#else + #error "BMLITE_ON_SPI or BMLITE_ON_SPI must be defined" +#endif +#endif if (debugger) { HAL_DBGMCU_EnableDBGStandbyMode(); diff --git a/HAL_Driver/stm32wb55/src/hal_buttons.c b/HAL_Driver/stm32wb55/src/hal_buttons.c index 26afdf2..57cddf6 100644 --- a/HAL_Driver/stm32wb55/src/hal_buttons.c +++ b/HAL_Driver/stm32wb55/src/hal_buttons.c @@ -18,7 +18,7 @@ */ /** - * @file button.c + * @file hal_buttons.c * @brief Initialization and access of button. */ diff --git a/HAL_Driver/stm32wb55/src/hal_leds.c b/HAL_Driver/stm32wb55/src/hal_leds.c index a50cc39..daaeb23 100644 --- a/HAL_Driver/stm32wb55/src/hal_leds.c +++ b/HAL_Driver/stm32wb55/src/hal_leds.c @@ -18,7 +18,7 @@ */ /** - * @file led.c + * @file hal_leds.c * @brief Initialization and access of LED. * * The user LED on the Nucleo-L476RG is using the same pin as SPI SCK (PA5) so the LED diff --git a/HAL_Driver/stm32wb55/src/hal_spi.c b/HAL_Driver/stm32wb55/src/hal_spi.c index 59d25c9..9dbf395 100644 --- a/HAL_Driver/stm32wb55/src/hal_spi.c +++ b/HAL_Driver/stm32wb55/src/hal_spi.c @@ -18,10 +18,12 @@ */ /** - * @file platform_spi.c - * @brief SPI functions + * @file hal_spi.c + * @brief SPI HAL functions */ +#ifdef BMLITE_ON_SPI + #include "stm32wbxx_hal.h" #include "bmlite_hal.h" @@ -246,3 +248,5 @@ void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) spi_rx_tx_done = true; } } + +#endif diff --git a/HAL_Driver/stm32wb55/src/hal_uart.c b/HAL_Driver/stm32wb55/src/hal_uart.c new file mode 100644 index 0000000..29700f2 --- /dev/null +++ b/HAL_Driver/stm32wb55/src/hal_uart.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2020 Fingerprint Cards AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Modified by Andrey Perminov + * for FPC BM-Lite applications + */ + +/** + * @file hal_uart.c + * @brief UART HAL functions + */ + +#ifdef BMLITE_ON_UART + +#include "stm32wbxx_hal.h" + +#include "bmlite_hal.h" +#include "fpc_bep_types.h" +#include "hal_config.h" + +#include + +#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) + +typedef struct +{ + volatile uint8_t flag; /* Timeout event flag */ + uint16_t prev_cndtr; /* Holds previous value of DMA_CNDTR (counts down) */ + uint32_t idle_irq_count; /* Debug */ + uint32_t rx_complete_count; /* Debug */ + uint32_t rx_half_count; /* Debug */ +} dma_event_t; + +UART_HandleTypeDef huart_host = { 0 }; +static DMA_HandleTypeDef hdma_rx = { 0 }; +static DMA_HandleTypeDef hdma_tx = { 0 }; + +static volatile bool tx_half; +static volatile bool tx_done; +static volatile bool error; +static volatile bool rx_available; + +#define DMA_BUF_SIZE 128 +#define DMA_TIMEOUT_MS 2 + +static uint8_t uart_rx_fifo[DMA_BUF_SIZE]; +static dma_event_t dma_uart_rx = { 0, DMA_BUF_SIZE, 0, 0, 0 }; + +// static bool tx_active(void) +// { +// return !tx_done; +// } + +// static bool rx_data_available(void) +// { +// bool avail = rx_available; + +// rx_available = false; + +// return avail; +// } + +/** + * This function handles Host USART global interrupt. + */ +void FPC_BMLITE_USART_IRQ_HANDLER(void) +{ + HAL_UART_IRQHandler(&huart_host); + + /* UART IDLE Interrupt */ + if ((huart_host.Instance->ISR & USART_ISR_IDLE) != RESET) { + huart_host.Instance->ICR = UART_CLEAR_IDLEF; + dma_uart_rx.flag = 1; + dma_uart_rx.idle_irq_count++; + if(hdma_rx.XferCpltCallback != NULL) { + hdma_rx.XferCpltCallback(&hdma_rx); + } + } +} + +/** + * This function handles Host USART DMA RX global interrupt. + */ +void FPC_BMLITE_USART_DMA_IRQ_HANDLER_RX(void) +{ + HAL_DMA_IRQHandler(huart_host.hdmarx); +} + +/** + * This function handles Host USART DMA TX global interrupt. + */ +void FPC_BMLITE_USART_DMA_IRQ_HANDLER_TX(void) +{ + HAL_DMA_IRQHandler(huart_host.hdmatx); +} + +/** + * USART init function. + * @param[in] baudrate Initial baud rate. + */ +void stm_uart_init(uint32_t baudrate) +{ + // HAL_StatusTypeDef status; + + huart_host.Instance = FPC_BMLITE_USART; + huart_host.Init.BaudRate = baudrate; + huart_host.Init.WordLength = UART_WORDLENGTH_8B; + huart_host.Init.StopBits = UART_STOPBITS_1; + huart_host.Init.Parity = UART_PARITY_NONE; + huart_host.Init.Mode = UART_MODE_TX_RX; + huart_host.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart_host.Init.OverSampling = UART_OVERSAMPLING_16; + huart_host.Init.ClockPrescaler = UART_PRESCALER_DIV1; + huart_host.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; + huart_host.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; + + // huart_host.Init.BaudRate = 921600; + + HAL_UART_Init(&huart_host); + HAL_UARTEx_EnableFifoMode(&huart_host); + + /* UART1 IDLE Interrupt Configuration */ + SET_BIT(FPC_BMLITE_USART->CR1, USART_CR1_IDLEIE); + + hal_timebase_busy_wait(100); + + /* Start UART RX */ + HAL_UART_Receive_DMA(&huart_host, uart_rx_fifo, DMA_BUF_SIZE); +} + +void uart_host_reinit(void) +{ + if (huart_host.Init.BaudRate) { + huart_host.Instance->BRR = (uint16_t)(UART_DIV_SAMPLING16(SystemCoreClock, + huart_host.Init.BaudRate, huart_host.Init.ClockPrescaler)); + } +} + +/** + * Initialize UART GPIO. + * @param[in, out] huart UART Handle. + */ +void HAL_UART_MspInit(UART_HandleTypeDef *huart) +{ + GPIO_InitTypeDef GPIO_InitStruct = { 0 }; + // HAL_StatusTypeDef status; + + if (huart->Instance == FPC_BMLITE_USART) { + /* Peripheral clock enable */ + FPC_BMLITE_USART_CLK_ENABLE(); + FPC_BMLITE_USART_RX_PORT_CLK_ENABLE(); + FPC_BMLITE_USART_TX_PORT_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; + GPIO_InitStruct.Alternate = FPC_BMLITE_USART_AF; + + GPIO_InitStruct.Pin = FPC_BMLITE_USART_RX_PIN; + HAL_GPIO_Init(FPC_BMLITE_USART_RX_PORT, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = FPC_BMLITE_USART_TX_PIN; + HAL_GPIO_Init(FPC_BMLITE_USART_TX_PORT, &GPIO_InitStruct); + + /* Peripheral DMA init*/ + hdma_rx.Instance = FPC_BMLITE_USART_DMA_CHANNEL_RX; + hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_rx.Init.Mode = DMA_CIRCULAR; + hdma_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH; + hdma_rx.Init.Request = FPC_BMLITE_USART_DMA_REQ_RX; + + HAL_DMA_Init(&hdma_rx); + __HAL_LINKDMA(huart, hdmarx, hdma_rx); + + hdma_tx.Instance = FPC_BMLITE_USART_DMA_CHANNEL_TX; + hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_tx.Init.Mode = DMA_NORMAL; + hdma_tx.Init.Priority = DMA_PRIORITY_LOW; + hdma_tx.Init.Request = FPC_BMLITE_USART_DMA_REQ_TX; + + HAL_DMA_Init(&hdma_tx); + __HAL_LINKDMA(huart, hdmatx, hdma_tx); + + /* UART Host RX DMA interrupt configuration */ + HAL_NVIC_SetPriority(FPC_BMLITE_USART_DMA_IRQn_RX, 6, 0); + HAL_NVIC_EnableIRQ(FPC_BMLITE_USART_DMA_IRQn_RX); + + /* UART Host TX DMA interrupt configuration */ + HAL_NVIC_SetPriority(FPC_BMLITE_USART_DMA_IRQn_TX, 6, 0); + HAL_NVIC_EnableIRQ(FPC_BMLITE_USART_DMA_IRQn_TX); + + /* Peripheral interrupt init*/ + HAL_NVIC_SetPriority(FPC_BMLITE_USART_IRQn, 1, 0); + HAL_NVIC_EnableIRQ(FPC_BMLITE_USART_IRQn); + + HAL_GPIO_WritePin(BMLITE_RST_PORT, BMLITE_RST_PIN, GPIO_PIN_RESET); + GPIO_InitStruct.Pin = BMLITE_RST_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; + GPIO_InitStruct.Alternate = 0; + HAL_GPIO_Init(BMLITE_RST_PORT, &GPIO_InitStruct); + } +} + +size_t hal_bmlite_uart_write(const uint8_t *data, size_t size) +{ + HAL_StatusTypeDef result = HAL_ERROR; + + tx_half = false; + tx_done = false; + error = false; + + result = HAL_UART_Transmit_DMA(&huart_host, data, size); + if (result != HAL_OK) { + return 0; + } + + while (!tx_done) { + + if (error) { + result = HAL_ERROR; + return 0; + } + } + + return size; +} + +size_t hal_bmlite_uart_read(uint8_t *data, size_t size) +{ + uint32_t n_sent = 0; + + /* Restart Host UART RX DMA transfer if it has stopped for some reason */ + if (huart_host.RxState != HAL_UART_STATE_BUSY_RX) { + dma_uart_rx.prev_cndtr = DMA_BUF_SIZE; + HAL_UART_Receive_DMA(&huart_host, uart_rx_fifo, DMA_BUF_SIZE); + } + + if (!size) { + return 0; + } + + uint16_t curr_cndtr = __HAL_DMA_GET_COUNTER(&hdma_rx); + + if (curr_cndtr != dma_uart_rx.prev_cndtr) { + uint32_t cur_pos = DMA_BUF_SIZE - curr_cndtr; + uint32_t prev_pos; + uint32_t length; + + /* Determine start position in DMA buffer based on previous CNDTR value */ + prev_pos = DMA_BUF_SIZE - dma_uart_rx.prev_cndtr; + if (prev_pos < cur_pos) { + length = MIN(cur_pos - prev_pos, size); + } else { + /* Copy until end of buffer first */ + length = MIN(DMA_BUF_SIZE - prev_pos, size); + } + memcpy(data, &uart_rx_fifo[prev_pos], length); + data += length; + n_sent += length; + dma_uart_rx.prev_cndtr -= length; + if (dma_uart_rx.prev_cndtr == 0) { + dma_uart_rx.prev_cndtr = DMA_BUF_SIZE; + } + if (prev_pos > cur_pos) { + /* Copy from start of buffer */ + length = MIN(cur_pos, size); + memcpy(data, uart_rx_fifo, length); + data += length; + n_sent += length; + dma_uart_rx.prev_cndtr -= length; + } + } + + return n_sent; + +} + +bool uart_host_rx_data_available(void) +{ + return rx_available; +} + +void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart) +{ + if (huart->Instance == huart_host.Instance) { + rx_available = true; + dma_uart_rx.rx_half_count++; + } +} + +void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) +{ + if (huart->Instance == huart_host.Instance) { + uint16_t curr_cndtr = __HAL_DMA_GET_COUNTER(huart->hdmarx); + + /* + * Ignore IDLE Timeout when the received characters exactly filled up the DMA buffer and + * DMA Rx Complete Interrupt is generated, but there is no new character during timeout. + */ + if (dma_uart_rx.flag && curr_cndtr == DMA_BUF_SIZE) { + dma_uart_rx.flag = 0; + return; + } + + if (!dma_uart_rx.flag) { + dma_uart_rx.rx_complete_count++; + } + dma_uart_rx.flag = 0; + + rx_available = true; + } +} + +void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart) +{ + if (huart->Instance == huart_host.Instance) { + tx_half = true; + } +} + +void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) +{ + if (huart->Instance == huart_host.Instance) { + tx_done = true; + } +} + +void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) +{ + if (huart->Instance == huart_host.Instance) { + error = true; + } +} + +#endif diff --git a/HAL_Driver/stm32wb55/stm32wb55.mk b/HAL_Driver/stm32wb55/stm32wb55.mk index d7bd35f..47b4429 100644 --- a/HAL_Driver/stm32wb55/stm32wb55.mk +++ b/HAL_Driver/stm32wb55/stm32wb55.mk @@ -63,6 +63,7 @@ LDFLAGS += -T $(HAL)/STM32WB55RGVX_FLASH.ld $(OUT)/obj/stm32wbxx_hal_pwr_ex.o: CFLAGS+=-Wno-unused-parameter $(OUT)/obj/stm32wbxx_hal_rtc_ex.o: CFLAGS+=-Wno-unused-parameter $(OUT)/obj/syscalls.o: CFLAGS+=-Wno-unused-parameter +$(OUT)/obj/hal_uart.o: CFLAGS+=-Wno-discarded-qualifiers ifeq ($(FPU),soft) AR_LIBS +=\ @@ -87,6 +88,9 @@ HAL_SRCS := \ $(SDK_ROOT)/Src/stm32wbxx_hal_rtc.c \ $(SDK_ROOT)/Src/stm32wbxx_hal_rtc_ex.c \ $(SDK_ROOT)/Src/stm32wbxx_hal_spi.c \ + $(SDK_ROOT)/Src/stm32wbxx_hal_uart.c \ + $(SDK_ROOT)/Src/stm32wbxx_hal_uart_ex.c \ + VPATH += $(dir $(HAL_SRCS)) C_SRCS += $(notdir $(HAL_SRCS)) diff --git a/README.md b/README.md index 2839be2..70bdc31 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ There are some variables controlling application building: APP - defines application PLATFORM - defines HW plaform with HAL implementation DEBUG - if defined as 'y' will produce debug output and add debug information +PORT - if defined as UART, BM-Lite HAL will use UART interface. Else will use SPI interface Not all applications can be built for a particular platform. To build embedded application for nRF52840 platform with additional debug info use: @@ -35,14 +36,17 @@ There are some useful makefile targets: Platform-independent interface implemented in [platform.c](BMLite_sdk/src/platform.c) -| Platform function | Description | -| :-------- | :-------- | -| fpc_bep_result_t **platform_init**(void *params) | Initilalizes hardware | -| void **platform_bmlite_reset**(void) | Implements BM-Lite HW Reset | -| fpc_bep_result_t **platform_bmlite_spi_send**(uint16_t size, const uint8_t *data, uint32_t timeout) | Send data packet to FPC BM-Lite | -| fpc_bep_result_t **platform_bmlite_spi_receive**(uint16_t size, uint8_t *data, uint32_t timeout) | Receive data packet from FPC BM-Lite. If timeout = **0**, the function will wait for data from BM-Lite indefinitely. The waiting loop will be breaked if **hal_check_button_pressed()** returns non-zero value. It is recommended to do HW or SW reset of BM-Lite if **platform_bmlite_spi_receive()** returns **FPC_BEP_RESULT_TIMEOUT** in order to return is into known state. | + + + + + + +
Platform function Description
fpc_bep_result_t platform_init(void *params) Initilalizes hardware
void platform_bmlite_reset(void) Implements BM-Lite HW Reset
fpc_bep_result_t platform_bmlite_spi_send(uint16_t size, const uint8_t *data, uint32_t timeout)
fpc_bep_result_t platform_bmlite_uart_send(uint16_t size, const uint8_t *data, uint32_t timeout)
Send data packet to FPC BM-Lite
fpc_bep_result_t platform_bmlite_spi_receive(uint16_t size, uint8_t *data, uint32_t timeout)
fpc_bep_result_t platform_bmlite_uart_receive(uint16_t size, uint8_t *data, uint32_t timeout)
Receive data packet from FPC BM-Lite. If timeout = 0, the function will wait for data from BM-Lite indefinitely. The waiting loop will be breaked if hal_check_button_pressed() returns non-zero value. It is recommended to do HW or SW reset of BM-Lite if platform_bmlite_spi_receive() returns **FPC_BEP_RESULT_TIMEOUT** in order to return is into known state.
-Currently **platform_bmlite_uart_send()** and **platform_bmlite_uart_receive()** are not implemented. For UART interface there is no need to wait for **IRQ** pin ready. However because in UART mode there is no signal from FPC-BM-LIte that it will send data, I would recommend to use UART interrupt or DMA to receive data from UART and store it to a separate buffer and read data in **platform_bmlite_uart_receive()** from that buffer. Activation UART data reading only inside **platform_bmlite_uart_receive()** could lead to loosing some incoming data and causing HCP protocol errors. + +For UART interface **IRQ/READY** pin is not used, so in UART mode there is no signal from FPC-BM-Lite indicating that BM-Lite is going to send data. To avoid data loss, all data received from UART must be stored into an incoming circular buffer. I would recommend to use UART interrupt or DMA to receive data from UART and store it to the buffer. +**platform_bmlite_uart_receive()** will read from that buffer when HCP protocol requests to read a data block. Activation UART data reading only inside **platform_bmlite_uart_receive()** will lead to loosing incoming data and causing HCP protocol errors. ------------ @@ -57,6 +61,8 @@ For porting the project to a new microcontroller, all functions from [bmlite_hal | fpc_bep_result_t **hal_board_init**(void *params) | Initialize GPIO, System timer, SPI | | void **hal_bmlite_reset**(bool state) | Activate/Deactivate BM-Lite **RST_N** pin (***Active Low***) | | fpc_bep_result_t **hal_bmlite_spi_write_read**(uint8_t *write, uint8_t *read, size_t size, bool leave_cs_asserted) | SPI data exchange | +| size_t **hal_bmlite_uart_write**(const uint8_t *data, size_t size); | Write data to UART interface | +| size_t **hal_bmlite_uart_read**(uint8_t *buff, size_t size); | Read data from UART interface | | bool **hal_bmlite_get_status**(void) | Return status of BM-Lite **IRQ** pin (***Active High***) | | void **hal_timebase_init**(void) | Initialize system clock with 1 msec tick | | uint32_t **hal_timebase_get_tick**(void) | Read currect system clock value |