86 lines
3.0 KiB
C
86 lines
3.0 KiB
C
#include "ds2480_stm32f4_hal.h"
|
|
|
|
#define RX_ERRORS (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE)
|
|
|
|
static int prepare(void *user)
|
|
{
|
|
ds2480_stm32f4_hal *p = (ds2480_stm32f4_hal *)user;
|
|
GPIO_InitTypeDef gpio = {0};
|
|
/* Abort resets HAL states after timeouts and disables UART IRQ/DMA. */
|
|
if (HAL_UART_Abort(p->uart) != HAL_OK) return -1;
|
|
__HAL_UART_DISABLE(p->uart);
|
|
HAL_GPIO_WritePin(p->tx_port, p->tx_pin, GPIO_PIN_RESET);
|
|
gpio.Pin = p->tx_pin;
|
|
gpio.Mode = GPIO_MODE_OUTPUT_PP;
|
|
gpio.Pull = GPIO_NOPULL;
|
|
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
|
|
HAL_GPIO_Init(p->tx_port, &gpio);
|
|
HAL_Delay(2);
|
|
HAL_GPIO_WritePin(p->tx_port, p->tx_pin, GPIO_PIN_SET);
|
|
HAL_Delay(2);
|
|
gpio.Mode = GPIO_MODE_AF_PP;
|
|
gpio.Alternate = p->tx_alternate;
|
|
HAL_GPIO_Init(p->tx_port, &gpio);
|
|
p->uart->Init.BaudRate = 9600;
|
|
p->uart->Init.WordLength = UART_WORDLENGTH_8B;
|
|
p->uart->Init.StopBits = UART_STOPBITS_1;
|
|
p->uart->Init.Parity = UART_PARITY_NONE;
|
|
p->uart->Init.Mode = UART_MODE_TX_RX;
|
|
p->uart->Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
|
p->uart->Init.OverSampling = UART_OVERSAMPLING_16;
|
|
if (HAL_UART_Init(p->uart) != HAL_OK) return -1;
|
|
/* SR then DR: discard BREAK echo/stale RX and clear FE/NE/ORE/PE. */
|
|
__HAL_UART_CLEAR_OREFLAG(p->uart);
|
|
return 0;
|
|
}
|
|
|
|
static int write_byte(void *user, const uint8_t *data, uint32_t size, uint32_t timeout)
|
|
{
|
|
ds2480_stm32f4_hal *p = (ds2480_stm32f4_hal *)user;
|
|
if (!data || size != 1 || !timeout || timeout == HAL_MAX_DELAY) return -1;
|
|
/* One reply fits in DR while HAL waits for TX complete. Never flush RX
|
|
* here: a reply may already be present when HAL_UART_Transmit returns. */
|
|
if (p->uart->Instance->SR & RX_ERRORS) return -1;
|
|
return HAL_UART_Transmit(p->uart, data, 1, timeout) == HAL_OK ? 0 : -1;
|
|
}
|
|
|
|
static int read_byte(void *user, uint8_t *data, uint32_t size, uint32_t timeout)
|
|
{
|
|
ds2480_stm32f4_hal *p = (ds2480_stm32f4_hal *)user;
|
|
uint32_t start, flags;
|
|
if (!data || size != 1 || !timeout || timeout == HAL_MAX_DELAY) return -1;
|
|
start = HAL_GetTick();
|
|
for (;;) {
|
|
flags = p->uart->Instance->SR;
|
|
/* Test errors BEFORE reading DR, including when RXNE is already set. */
|
|
if (flags & RX_ERRORS) {
|
|
__HAL_UART_CLEAR_OREFLAG(p->uart);
|
|
return -1;
|
|
}
|
|
if (flags & USART_SR_RXNE) {
|
|
*data = (uint8_t)p->uart->Instance->DR;
|
|
return 0;
|
|
}
|
|
if ((uint32_t)(HAL_GetTick() - start) >= timeout) return -1;
|
|
}
|
|
}
|
|
|
|
static void delay_ms(void *user, uint32_t ms)
|
|
{
|
|
(void)user;
|
|
HAL_Delay(ms);
|
|
}
|
|
|
|
ds2480_status ds2480_stm32f4_hal_bind(ds2480_stm32f4_hal *p, ds2480_port *port)
|
|
{
|
|
if (!p || !port || !p->uart || !p->uart->Instance || !p->tx_port ||
|
|
!p->tx_pin || (p->tx_pin & (p->tx_pin - 1U)) || p->tx_alternate > 15U)
|
|
return DS2480_ARGUMENT;
|
|
port->user = p;
|
|
port->prepare = prepare;
|
|
port->write = write_byte;
|
|
port->read = read_byte;
|
|
port->delay_ms = delay_ms;
|
|
return DS2480_OK;
|
|
}
|