You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
404 lines
9.9 KiB
404 lines
9.9 KiB
/* |
|
(c) 2017 night_ghost@ykoctpa.ru |
|
|
|
based on: LeafLabs |
|
|
|
|
|
*/ |
|
|
|
#pragma GCC optimize ("O2") |
|
|
|
#include <usart.h> |
|
#include <hal.h> |
|
#include <systick.h> |
|
/* |
|
* Devices |
|
*/ |
|
|
|
static ring_buffer usart1_txrb IN_CCM; |
|
static ring_buffer usart1_rxrb IN_CCM; |
|
static usart_state u1state IN_CCM; |
|
|
|
static const usart_dev usart1 = { |
|
.USARTx = USART1, |
|
.clk = RCC_APB2Periph_USART1, |
|
.txrb = &usart1_txrb, |
|
.rxrb = &usart1_rxrb, |
|
.state = &u1state, |
|
.irq = USART1_IRQn, |
|
.rx_pin = BOARD_USART1_RX_PIN, |
|
.tx_pin = BOARD_USART1_TX_PIN, |
|
.gpio_af = GPIO_AF_USART1 |
|
}; |
|
/** USART1 device */ |
|
const usart_dev * const _USART1 = &usart1; |
|
|
|
#if defined(BOARD_USART2_RX_PIN) && defined(BOARD_USART2_RX_PIN) |
|
static ring_buffer usart2_txrb IN_CCM; |
|
static ring_buffer usart2_rxrb IN_CCM; |
|
static usart_state u2state IN_CCM; |
|
|
|
static const usart_dev usart2 = { |
|
.USARTx = USART2, |
|
.clk = RCC_APB1Periph_USART2, |
|
.txrb = &usart2_txrb, |
|
.rxrb = &usart2_rxrb, |
|
.state = &u2state, |
|
.irq = USART2_IRQn, |
|
.rx_pin = BOARD_USART2_RX_PIN, |
|
.tx_pin = BOARD_USART2_TX_PIN, |
|
.gpio_af = GPIO_AF_USART2 |
|
}; |
|
/** USART2 device */ |
|
const usart_dev * const _USART2 = &usart2; |
|
#else |
|
#define _USART2 NULL |
|
#endif |
|
|
|
static ring_buffer usart3_txrb IN_CCM; |
|
static ring_buffer usart3_rxrb IN_CCM; |
|
static usart_state u3state IN_CCM; |
|
|
|
static const usart_dev usart3 = { |
|
.USARTx = USART3, |
|
.clk = RCC_APB1Periph_USART3, |
|
.txrb = &usart3_txrb, |
|
.rxrb = &usart3_rxrb, |
|
.state = &u3state, |
|
.irq = USART3_IRQn, |
|
.rx_pin = BOARD_USART3_RX_PIN, |
|
.tx_pin = BOARD_USART3_TX_PIN, |
|
.gpio_af = GPIO_AF_USART3 |
|
}; |
|
/** USART3 device */ |
|
const usart_dev * const _USART3 = &usart3; |
|
|
|
#if defined(BOARD_USART4_RX_PIN) && defined(BOARD_USART4_TX_PIN) |
|
static ring_buffer uart4_txrb IN_CCM; |
|
static ring_buffer uart4_rxrb IN_CCM; |
|
static usart_state u4state IN_CCM; |
|
|
|
static const usart_dev uart4 = { |
|
.USARTx = UART4, |
|
.clk = RCC_APB1Periph_UART4, |
|
.txrb = &uart4_txrb, |
|
.rxrb = &uart4_rxrb, |
|
.state = &u4state, |
|
.irq = UART4_IRQn, |
|
.rx_pin = BOARD_USART4_RX_PIN, |
|
.tx_pin = BOARD_USART4_TX_PIN, |
|
.gpio_af = GPIO_AF_UART4 |
|
}; |
|
/** UART4 device */ |
|
const usart_dev * const _UART4 = &uart4; |
|
#endif |
|
|
|
#if defined(BOARD_USART5_RX_PIN) && defined(BOARD_USART5_TX_PIN) |
|
static ring_buffer uart5_txrb IN_CCM; |
|
static ring_buffer uart5_rxrb IN_CCM; |
|
static usart_state u5state IN_CCM; |
|
|
|
static const usart_dev uart5 = { |
|
.USARTx = UART5, |
|
.clk = RCC_APB1Periph_UART5, |
|
.txrb = &uart5_txrb, |
|
.rxrb = &uart5_rxrb, |
|
.state = &u5state, |
|
.irq = UART5_IRQn, |
|
.rx_pin = BOARD_USART5_RX_PIN, |
|
.tx_pin = BOARD_USART5_TX_PIN, |
|
.gpio_af = GPIO_AF_UART5 |
|
}; |
|
/* UART5 device */ |
|
const usart_dev * const _UART5 = &uart5; |
|
#endif |
|
|
|
#if defined(BOARD_USART6_RX_PIN) && defined(BOARD_USART6_TX_PIN) |
|
static ring_buffer usart6_txrb IN_CCM; |
|
static ring_buffer usart6_rxrb IN_CCM; |
|
static usart_state u6state IN_CCM; |
|
|
|
static const usart_dev usart6 = { |
|
.USARTx = USART6, |
|
.clk = RCC_APB2Periph_USART6, |
|
.txrb = &usart6_txrb, |
|
.rxrb = &usart6_rxrb, |
|
.state = &u6state, |
|
.irq = USART6_IRQn, |
|
.rx_pin = BOARD_USART6_RX_PIN, |
|
.tx_pin = BOARD_USART6_TX_PIN, |
|
.gpio_af = GPIO_AF_USART6 |
|
}; |
|
/** UART6 device */ |
|
const usart_dev * const _USART6 = &usart6; |
|
#endif |
|
|
|
const usart_dev * const UARTS[] = { |
|
NULL, |
|
&usart1, |
|
#if defined(BOARD_USART2_RX_PIN) && defined(BOARD_USART2_RX_PIN) |
|
&usart2, |
|
#else |
|
NULL, |
|
#endif |
|
&usart3, |
|
#if defined(BOARD_USART4_RX_PIN) && defined(BOARD_USART4_TX_PIN) |
|
&uart4, |
|
#else |
|
NULL, |
|
#endif |
|
#if defined(BOARD_USART5_RX_PIN) && defined(BOARD_USART5_TX_PIN) |
|
&uart5, |
|
#else |
|
NULL, |
|
#endif |
|
#if defined(BOARD_USART6_RX_PIN) && defined(BOARD_USART6_TX_PIN) |
|
&usart6, |
|
#else |
|
NULL, |
|
#endif |
|
|
|
}; |
|
|
|
void usart_foreach(void (*fn)(const usart_dev*)) |
|
{ |
|
fn(_USART1); |
|
#if defined(BOARD_USART2_RX_PIN) && defined(BOARD_USART2_RX_PIN) |
|
fn(_USART2); |
|
#endif |
|
fn(_USART3); |
|
#if defined(BOARD_USART4_RX_PIN) && defined(BOARD_USART4_TX_PIN) |
|
fn(_UART4); |
|
#endif |
|
#if defined(BOARD_USART5_RX_PIN) && defined(BOARD_USART5_TX_PIN) |
|
fn(_UART5); |
|
#endif |
|
#if defined(BOARD_USART6_RX_PIN) && defined(BOARD_USART6_TX_PIN) |
|
fn(_USART6); |
|
#endif |
|
} |
|
|
|
extern uint32_t us_ticks; |
|
|
|
/** |
|
* @brief Initialize a serial port. |
|
* @param dev Serial port to be initialized |
|
*/ |
|
void usart_init(const usart_dev *dev) { |
|
/* Check the parameters */ |
|
assert_param(IS_USART_ALL_PERIPH(dev->USARTx)); |
|
|
|
// Turn on peripheral clocks |
|
if (dev->USARTx == USART1 || dev->USARTx == USART6 ) |
|
RCC_APB2PeriphClockCmd(dev->clk, ENABLE); // we must wait some time before access to |
|
else |
|
RCC_APB1PeriphClockCmd(dev->clk, ENABLE); |
|
|
|
} |
|
|
|
void usart_setup(const usart_dev *dev, uint32_t baudRate, uint16_t wordLength, |
|
uint16_t stopBits, uint16_t parity, uint16_t mode, uint16_t hardwareFlowControl) |
|
{ |
|
/* Check the parameters */ |
|
assert_param(IS_USART_ALL_PERIPH(dev->USARTx)); |
|
assert_param(IS_USART_BAUDRATE(baud)); |
|
assert_param(IS_USART_STOPBITS(stopbits)); |
|
assert_param(IS_USART_PARITY(parity)); |
|
assert_param(IS_USART_WORD_LENGTH(wordLength)); |
|
assert_param(IS_USART_MODE(mode)); |
|
assert_param(IS_USART_HARDWARE_FLOW_CONTROL(hardwareFlowControl)); |
|
|
|
memset(dev->state, 0, sizeof(*dev->state)); |
|
|
|
dev->state->txbusy = 0; |
|
dev->state->callback = 0; |
|
|
|
/* Disable USARTx */ |
|
usart_disable(dev); |
|
|
|
rb_init(dev->txrb, USART_TX_BUF_SIZE, dev->state->tx_buf); |
|
rb_init(dev->rxrb, USART_RX_BUF_SIZE, dev->state->rx_buf); |
|
|
|
/* Enables the USART's 8x oversampling mode. */ |
|
USART_OverSampling8Cmd(dev->USARTx, ENABLE); |
|
|
|
USART_ClockInitTypeDef USART_InitClock; |
|
USART_ClockStructInit(&USART_InitClock); |
|
USART_ClockInit(dev->USARTx, &USART_InitClock); |
|
|
|
USART_InitTypeDef USART_config; |
|
USART_StructInit(&USART_config); |
|
USART_config.USART_BaudRate = baudRate; |
|
USART_config.USART_WordLength = wordLength; |
|
USART_config.USART_StopBits = stopBits; |
|
USART_config.USART_Parity = parity; |
|
USART_config.USART_Mode = mode; |
|
USART_config.USART_HardwareFlowControl = hardwareFlowControl; |
|
|
|
USART_Init(dev->USARTx, &USART_config); |
|
|
|
dev->USARTx->CR1 &= ~(USART_MASK_IDLEIE | USART_MASK_RXNEIE | USART_MASK_TCEIE | USART_MASK_TXEIE | USART_MASK_PEIE); |
|
dev->USARTx->CR2 &= ~(USART_MASK2_LBDIE); |
|
dev->USARTx->CR3 &= ~(USART_MASK3_CTSIE | USART_MASK3_EIE); |
|
|
|
if(mode & USART_Mode_Rx) { /* Enable Rx request */ |
|
USART_ClearFlag(dev->USARTx, USART_FLAG_RXNE); |
|
dev->USARTx->CR1 |= USART_MASK_RXNEIE; |
|
} |
|
|
|
if(mode & USART_Mode_Tx) { |
|
USART_ClearFlag(dev->USARTx, USART_FLAG_TC); |
|
} |
|
|
|
enable_nvic_irq(dev->irq, UART_INT_PRIORITY); |
|
} |
|
|
|
|
|
|
|
uint32_t usart_tx(const usart_dev *dev, const uint8_t *buf, uint32_t len) |
|
{ |
|
/* Check the parameters */ |
|
assert_param(IS_USART_ALL_PERIPH(USARTx)); |
|
assert_param(IS_USART_DATA(Data)); |
|
|
|
uint32_t tosend = len; |
|
uint32_t sent = 0; |
|
|
|
while (tosend) { |
|
if (rb_is_full(dev->txrb)) |
|
break; |
|
rb_insert(dev->txrb, *buf++); |
|
sent++; |
|
tosend--; |
|
} |
|
if (dev->state->txbusy == 0 && sent > 0) { |
|
dev->state->txbusy = 1; |
|
dev->USARTx->CR1 |= USART_MASK_TXEIE; |
|
} |
|
|
|
return sent; |
|
} |
|
|
|
void usart_putudec(const usart_dev *dev, uint32_t val) { |
|
char digits[12]; |
|
int i = 0; |
|
|
|
do { |
|
digits[i++] = val % 10 + '0'; |
|
val /= 10; |
|
} while (val > 0); |
|
|
|
while (--i >= 0){ |
|
usart_putc(dev, digits[i]); |
|
} |
|
} |
|
|
|
/* |
|
* Interrupt handlers. |
|
*/ |
|
|
|
|
|
static inline void usart_rx_irq(const usart_dev *dev) { |
|
#ifdef ISR_PERF |
|
uint32_t t=stopwatch_getticks(); |
|
#endif |
|
|
|
/* Check on Receive Data register Not Empty interrupt */ |
|
uint16_t sr = dev->USARTx->SR; |
|
if( (sr & USART_F_RXNE) && (dev->USARTx->CR1 & USART_MASK_RXNEIE) ){ |
|
#ifdef USART_SAFE_INSERT |
|
/* If the buffer is full and the user defines USART_SAFE_INSERT, ignore new bytes. */ |
|
rb_safe_insert(dev->rxrb, (uint8_t) dev->USARTx->DR); |
|
#else |
|
/* By default, push bytes around in the ring buffer. */ |
|
rb_push_insert(dev->rxrb, (uint8_t)dev->USARTx->DR); |
|
#endif |
|
|
|
if(dev->state->callback) { |
|
revo_call_handler(dev->state->callback, (uint32_t)dev); |
|
} |
|
} |
|
|
|
if( sr & USART_F_ORE ){ |
|
(void)dev->USARTx->DR; // cleared after reading sr, dr |
|
} |
|
|
|
#ifdef ISR_PERF |
|
t = stopwatch_getticks() - t; |
|
isr_time += t; |
|
if(t>max_isr_time) max_isr_time=t; |
|
#endif |
|
|
|
} |
|
|
|
static inline void usart_tx_irq(const usart_dev *dev) { |
|
#ifdef ISR_PERF |
|
uint32_t t=stopwatch_getticks(); |
|
#endif |
|
/* Check USART Transmit Data Register Empty Interrupt */ |
|
uint16_t sr = dev->USARTx->SR; |
|
if( (sr & USART_F_TXE) && (dev->USARTx->CR1 & USART_MASK_TXEIE) ){ |
|
|
|
if (dev->txrb && !rb_is_empty(dev->txrb)) { |
|
dev->USARTx->DR = rb_remove(dev->txrb); |
|
dev->state->txbusy = 1; |
|
} else { |
|
/* Disable the USART Transmit Data Register Empty Interrupt */ |
|
dev->USARTx->CR1 &= ~USART_MASK_TXEIE; |
|
dev->state->txbusy = 0; |
|
// nops needed to deactivate the irq before irq handler is left |
|
asm volatile("nop"); |
|
asm volatile("nop"); |
|
} |
|
} |
|
#ifdef ISR_PERF |
|
t = stopwatch_getticks() - t; |
|
isr_time += t; |
|
if(t>max_isr_time) max_isr_time=t; |
|
#endif |
|
|
|
} |
|
|
|
void USART1_IRQHandler(void) |
|
{ |
|
usart_rx_irq(_USART1); |
|
usart_tx_irq(_USART1); |
|
} |
|
|
|
#if defined(BOARD_USART2_RX_PIN) && defined(BOARD_USART2_RX_PIN) |
|
void USART2_IRQHandler(void) |
|
{ |
|
usart_rx_irq(_USART2); |
|
usart_tx_irq(_USART2); |
|
} |
|
#endif |
|
|
|
void USART3_IRQHandler(void) |
|
{ |
|
usart_rx_irq(_USART3); |
|
usart_tx_irq(_USART3); |
|
} |
|
|
|
#if defined( BOARD_USART4_RX_PIN) && defined( BOARD_USART4_TX_PIN) |
|
void UART4_IRQHandler(void) |
|
{ |
|
usart_rx_irq(_UART4); |
|
usart_tx_irq(_UART4); |
|
} |
|
#endif |
|
|
|
#if defined( BOARD_USART5_RX_PIN) && defined( BOARD_USART5_TX_PIN) |
|
void UART5_IRQHandler(void) |
|
{ |
|
usart_rx_irq(_UART5); |
|
usart_tx_irq(_UART5); |
|
} |
|
#endif |
|
|
|
#if defined( BOARD_USART6_RX_PIN) && defined( BOARD_USART6_TX_PIN) |
|
void USART6_IRQHandler(void) |
|
{ |
|
usart_rx_irq(_USART6); |
|
usart_tx_irq(_USART6); |
|
} |
|
#endif
|
|
|