Added support for BM-Lite UART interface.

Implemented UART interface support in stm32Wb55 HAL
This commit is contained in:
Andrey Perminov 2021-12-21 12:35:20 -08:00
parent fe5daad7bb
commit 27c95abeba
24 changed files with 597 additions and 49 deletions

18
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -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
}

24
.vscode/launch.json vendored
View File

@ -14,17 +14,17 @@
"device": "STM32WB55xx", "device": "STM32WB55xx",
"interface": "swd", "interface": "swd",
"runToMain": true, "runToMain": true,
} },
{ // {
"name": "Cortex Debug nRF52840", // "name": "Cortex Debug nRF52840",
"cwd": "${workspaceRoot}", // "cwd": "${workspaceRoot}",
"executable": "${workspaceRoot}/BMLite_examples/out/embedded_app/nRF52840/embedded_app", // "executable": "${workspaceRoot}/BMLite_examples/out/embedded_app/nRF52840/embedded_app",
"request": "launch", // "request": "launch",
"type": "cortex-debug", // "type": "cortex-debug",
"servertype": "jlink", // "servertype": "jlink",
"device": "nRF52840_xxAA", // "device": "nRF52840_xxAA",
"interface": "swd", // "interface": "swd",
"runToMain": true, // "runToMain": true,
} // }
] ]
} }

2
.vscode/tasks.json vendored
View File

@ -7,7 +7,7 @@
"type": "shell", "type": "shell",
"label": "wb55 make", "label": "wb55 make",
"command": "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": { "options": {
"cwd": "${workspaceFolder}" "cwd": "${workspaceFolder}"
}, },

View File

@ -73,7 +73,25 @@ void hal_bmlite_reset(bool state);
* @param[in] Leave CS asserted * @param[in] Leave CS asserted
* @return ::fpc_bep_result_t * @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 * @brief Check if BM-Lite IRQ pin is set

View File

@ -72,6 +72,13 @@ CFLAGS +=\
-MMD \ -MMD \
-MP -MP
ifeq ($(PORT),UART)
CFLAGS += -DBMLITE_ON_UART
else
CFLAGS += -DBMLITE_ON_SPI
endif
ifeq ($(DEBUG),y) ifeq ($(DEBUG),y)
CFLAGS +=\ CFLAGS +=\
-g3\ -g3\

View File

@ -36,8 +36,13 @@ static uint8_t hcp_txrx_buffer[MTU];
static uint8_t hcp_data_buffer[DATA_BUFFER_SIZE]; static uint8_t hcp_data_buffer[DATA_BUFFER_SIZE];
static HCP_comm_t hcp_chain = { 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, .read = platform_bmlite_spi_receive,
.write = platform_bmlite_spi_send, .write = platform_bmlite_spi_send,
#endif
.pkt_buffer = hcp_data_buffer, .pkt_buffer = hcp_data_buffer,
.txrx_buffer = hcp_txrx_buffer, .txrx_buffer = hcp_txrx_buffer,
.pkt_size = 0, .pkt_size = 0,

View File

@ -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, fpc_bep_result_t hal_bmlite_spi_write_read(uint8_t *write, uint8_t *read, size_t size,
bool leave_cs_asserted); 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 * @brief Check if BM-Lite IRQ pin is set
* @return ::bool * @return ::bool

View File

@ -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 * @return ::fpc_com_result_t
*/ */
fpc_bep_result_t platform_bmlite_uart_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);
void *session);
/** /**
* @brief Receives data from SPI port in blocking mode. * @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 * @return ::fpc_com_result_t
*/ */
fpc_bep_result_t platform_bmlite_uart_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);
void *session);
/** /**
* @brief Stops execution if a debug interface is attached. * @brief Stops execution if a debug interface is attached.

View File

@ -36,9 +36,9 @@
fpc_bep_result_t platform_init(void *params) fpc_bep_result_t platform_init(void *params)
{ {
fpc_bep_result_t result; fpc_bep_result_t result;
hal_timebase_init();
result = hal_board_init(params); result = hal_board_init(params);
if(result == FPC_BEP_RESULT_OK) { if(result == FPC_BEP_RESULT_OK) {
hal_timebase_init();
platform_bmlite_reset(); platform_bmlite_reset();
} }
return result; return result;
@ -52,6 +52,56 @@ void platform_bmlite_reset(void)
hal_timebase_busy_wait(100); 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; i<size; i++)
LOG_DEBUG("%02X ", data[i]);
LOG_DEBUG("\n");
#endif
size_t bytes_sent = hal_bmlite_uart_write(data, size);
if(bytes_sent == size)
return FPC_BEP_RESULT_OK;
return FPC_BEP_RESULT_IO_ERROR;
}
fpc_bep_result_t platform_bmlite_uart_receive(uint16_t size, uint8_t *data, uint32_t timeout)
{
size_t total = 0;
volatile uint32_t start_time = hal_timebase_get_tick();
volatile uint32_t curr_time = start_time;
while (total < size &&
(!timeout || (curr_time = hal_timebase_get_tick()) - start_time < timeout)) {
total += hal_bmlite_uart_read(data + total, size);
if(hal_check_button_pressed()) {
break;
}
}
if(total < size) {
return FPC_BEP_RESULT_TIMEOUT;
}
#ifdef DEBUG_COMM
LOG_DEBUG("<- ");
if(res == FPC_BEP_RESULT_OK) {
for (int i=0; i<size; i++)
LOG_DEBUG("%02X ", data[i]);
}
LOG_DEBUG("\n");
#endif
return FPC_BEP_RESULT_OK;
}
#else // BMLITE_ON_SPI
fpc_bep_result_t platform_bmlite_spi_send(uint16_t size, const uint8_t *data, uint32_t timeout) fpc_bep_result_t platform_bmlite_spi_send(uint16_t size, const uint8_t *data, uint32_t timeout)
{ {
uint8_t buff[size]; uint8_t buff[size];
@ -93,6 +143,8 @@ fpc_bep_result_t platform_bmlite_spi_receive(uint16_t size, uint8_t *data, uint3
return res; return res;
} }
#endif
__attribute__((weak)) uint32_t hal_check_button_pressed() __attribute__((weak)) uint32_t hal_check_button_pressed()
{ {
return 0; return 0;

View File

@ -86,8 +86,8 @@ fpc_bep_result_t hal_board_init(void *params)
} }
if (p->iface == COM_INTERFACE) { if (p->iface == COM_INTERFACE) {
p->hcp_comm->read = rpi_com_receive; p->hcp_comm->read = platform_bmlite_uart_receive;
p->hcp_comm->write = rpi_com_send; p->hcp_comm->write = platform_bmlite_uart_send;
} else { } else {
p->hcp_comm->read = platform_bmlite_spi_receive; p->hcp_comm->read = platform_bmlite_spi_receive;
p->hcp_comm->write = platform_bmlite_spi_send; p->hcp_comm->write = platform_bmlite_spi_send;

View File

@ -84,26 +84,20 @@ bool rpi_com_init(char *port, int baudrate, int timeout)
return true; 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; int n;
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "error invalid file descriptor"); 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; fpc_bep_result_t res = FPC_BEP_RESULT_OK;
int n_read = 0; 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;
} }

View File

@ -19,7 +19,7 @@
/** /**
* @file board_leds.c * @file hal_leds.c
* @brief Leds control functions. * @brief Leds control functions.
*/ */

View File

@ -18,10 +18,12 @@
*/ */
/** /**
* @file platform_spi.c * @file hal_spi.c
* @brief SPI functions * @brief SPI HAL functions
*/ */
#ifdef BMLITE_ON_SPI
#include "nrf_drv_spi.h" #include "nrf_drv_spi.h"
#include "boards.h" #include "boards.h"
#include "nrf_gpio.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); nrf_drv_gpiote_out_init(BMLITE_CS_PIN, &out_config);
} }
#endif

View File

@ -18,7 +18,7 @@
*/ */
/** /**
* @file platform_timebase.c * @file hal_timebase.c
* @brief timebase interface functions * @brief timebase interface functions
*/ */

View File

@ -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 <andrey.ppp@gmail.com>
* 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

View File

@ -68,6 +68,32 @@
#define BMLITE_SPI_DMA_IRQn_TX DMA1_Channel3_IRQn #define BMLITE_SPI_DMA_IRQn_TX DMA1_Channel3_IRQn
#define BMLITE_SPI_DMA_IRQ_HANDLER_TX DMA1_Channel3_IRQHandler #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. * Configuration of GPIO used for sensor reset / sensor interrupt.
*/ */

View File

@ -56,8 +56,8 @@
#define HAL_SPI_MODULE_ENABLED #define HAL_SPI_MODULE_ENABLED
/*#define HAL_TIM_MODULE_ENABLED */ /*#define HAL_TIM_MODULE_ENABLED */
/*#define HAL_TSC_MODULE_ENABLED */ /*#define HAL_TSC_MODULE_ENABLED */
/*#define HAL_UART_MODULE_ENABLED */ #define HAL_UART_MODULE_ENABLED
/*#define HAL_USART_MODULE_ENABLED */ /* #define HAL_USART_MODULE_ENABLED */
/*#define HAL_WWDG_MODULE_ENABLED */ /*#define HAL_WWDG_MODULE_ENABLED */
#define HAL_EXTI_MODULE_ENABLED #define HAL_EXTI_MODULE_ENABLED
#define HAL_CORTEX_MODULE_ENABLED #define HAL_CORTEX_MODULE_ENABLED

View File

@ -36,6 +36,7 @@ static void dma_init();
static void system_irq_init(); static void system_irq_init();
void stm_spi_init(uint32_t speed_hz); void stm_spi_init(uint32_t speed_hz);
void stm_uart_init(uint32_t speed_hz);
void board_led_init(); void board_led_init();
void board_button_init(); void board_button_init();
@ -60,7 +61,15 @@ fpc_bep_result_t hal_board_init(void *params)
/* Initialize DMA */ /* Initialize DMA */
dma_init(); dma_init();
#ifdef BMLITE_ON_UART
stm_uart_init(115200);
#else
#ifdef BMLITE_ON_SPI
stm_spi_init(4000000); stm_spi_init(4000000);
#else
#error "BMLITE_ON_SPI or BMLITE_ON_SPI must be defined"
#endif
#endif
if (debugger) { if (debugger) {
HAL_DBGMCU_EnableDBGStandbyMode(); HAL_DBGMCU_EnableDBGStandbyMode();

View File

@ -18,7 +18,7 @@
*/ */
/** /**
* @file button.c * @file hal_buttons.c
* @brief Initialization and access of button. * @brief Initialization and access of button.
*/ */

View File

@ -18,7 +18,7 @@
*/ */
/** /**
* @file led.c * @file hal_leds.c
* @brief Initialization and access of LED. * @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 * The user LED on the Nucleo-L476RG is using the same pin as SPI SCK (PA5) so the LED

View File

@ -18,10 +18,12 @@
*/ */
/** /**
* @file platform_spi.c * @file hal_spi.c
* @brief SPI functions * @brief SPI HAL functions
*/ */
#ifdef BMLITE_ON_SPI
#include "stm32wbxx_hal.h" #include "stm32wbxx_hal.h"
#include "bmlite_hal.h" #include "bmlite_hal.h"
@ -246,3 +248,5 @@ void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
spi_rx_tx_done = true; spi_rx_tx_done = true;
} }
} }
#endif

View File

@ -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 <andrey.ppp@gmail.com>
* 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 <string.h>
#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

View File

@ -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_pwr_ex.o: CFLAGS+=-Wno-unused-parameter
$(OUT)/obj/stm32wbxx_hal_rtc_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/syscalls.o: CFLAGS+=-Wno-unused-parameter
$(OUT)/obj/hal_uart.o: CFLAGS+=-Wno-discarded-qualifiers
ifeq ($(FPU),soft) ifeq ($(FPU),soft)
AR_LIBS +=\ AR_LIBS +=\
@ -87,6 +88,9 @@ HAL_SRCS := \
$(SDK_ROOT)/Src/stm32wbxx_hal_rtc.c \ $(SDK_ROOT)/Src/stm32wbxx_hal_rtc.c \
$(SDK_ROOT)/Src/stm32wbxx_hal_rtc_ex.c \ $(SDK_ROOT)/Src/stm32wbxx_hal_rtc_ex.c \
$(SDK_ROOT)/Src/stm32wbxx_hal_spi.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)) VPATH += $(dir $(HAL_SRCS))
C_SRCS += $(notdir $(HAL_SRCS)) C_SRCS += $(notdir $(HAL_SRCS))

View File

@ -14,6 +14,7 @@ There are some variables controlling application building:
APP - defines application APP - defines application
PLATFORM - defines HW plaform with HAL implementation PLATFORM - defines HW plaform with HAL implementation
DEBUG - if defined as 'y' will produce debug output and add debug information 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: 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-independent interface implemented in [platform.c](BMLite_sdk/src/platform.c)
| Platform function | Description | <table>
| :-------- | :-------- | <tr><th> Platform function <th> Description</tr>
| fpc_bep_result_t **platform_init**(void *params) | Initilalizes hardware | <tr><td> fpc_bep_result_t <b>platform_init</b>(void *params) <td> Initilalizes hardware </tr>
| void **platform_bmlite_reset**(void) | Implements BM-Lite HW Reset | <tr><td> void <b>platform_bmlite_reset</b>(void) <td> Implements BM-Lite HW Reset </tr>
| 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 | <tr><td> fpc_bep_result_t <b>platform_bmlite_spi_send</b>(uint16_t size, const uint8_t *data, uint32_t timeout) <br> fpc_bep_result_t <b>platform_bmlite_uart_send</b>(uint16_t size, const uint8_t *data, uint32_t timeout) <td> Send data packet to FPC BM-Lite </tr>
| 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. | <tr><td> fpc_bep_result_t <b>platform_bmlite_spi_receive</b>(uint16_t size, uint8_t *data, uint32_t timeout) <br> fpc_bep_result_t <b>platform_bmlite_uart_receive</b>(uint16_t size, uint8_t *data, uint32_t timeout)<td> Receive data packet from FPC BM-Lite. If timeout = <b>0</b>, the function will wait for data from BM-Lite indefinitely. The waiting loop will be breaked if <b>hal_check_button_pressed()</b> returns non-zero value. It is recommended to do HW or SW reset of BM-Lite if <b>platform_bmlite_spi_receive()</b> returns **FPC_BEP_RESULT_TIMEOUT** in order to return is into known state. </tr>
</table>
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 | | 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***) | | 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 | | 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***) | | 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 | | void **hal_timebase_init**(void) | Initialize system clock with 1 msec tick |
| uint32_t **hal_timebase_get_tick**(void) | Read currect system clock value | | uint32_t **hal_timebase_get_tick**(void) | Read currect system clock value |