F1 USART - buffered interrupt-based TX (static TX buffer)

usart.h: statically define TX buffer like RX buffer. TX buffer size
defined in USART_TX_BUF_SIZE
usart.h: add function usart_reset_tx() to reset TX buffer (same as for
RX bufferI)
usart.c: usart_init() changed to init TX buffer
usart.c: usart_disable() changed to reset TX buffer
usart.c: usart_tx() changed to use TX buffer and manage interrupt TXEIE
usart_f1.c: changed to instantiate TX buffers
usart_private.h: changed interrupt handler to manage TXEIE
This commit is contained in:
edogaldo 2016-07-11 12:52:24 +02:00
parent ea6ec1d0aa
commit 51d2d9e0d9
4 changed files with 53 additions and 10 deletions

View File

@ -40,6 +40,7 @@
*/
void usart_init(usart_dev *dev) {
rb_init(dev->rb, USART_RX_BUF_SIZE, dev->rx_buf);
rb_init(dev->wb, USART_TX_BUF_SIZE, dev->tx_buf);
rcc_clk_enable(dev->clk_id);
nvic_irq_enable(dev->irq_num);
}
@ -78,6 +79,7 @@ void usart_disable(usart_dev *dev) {
/* Clean up buffer */
usart_reset_rx(dev);
usart_reset_tx(dev);
}
/**
@ -90,9 +92,20 @@ void usart_disable(usart_dev *dev) {
uint32 usart_tx(usart_dev *dev, const uint8 *buf, uint32 len) {
usart_reg_map *regs = dev->regs;
uint32 txed = 0;
while ((regs->SR & USART_SR_TXE) && (txed < len)) {
while (rb_is_empty(dev->wb) && (regs->SR & USART_SR_TXE) && (txed < len)) {
regs->DR = buf[txed++];
}
regs->CR1 &= ~((uint32)USART_CR1_TXEIE); // disable TXEIE while populating the buffer
while (txed < len) {
if (rb_safe_insert(dev->wb, buf[txed])) {
txed++;
}
else
break;
}
if (rb_full_count(dev->wb) > 0) {
regs->CR1 |= USART_CR1_TXEIE;
}
return txed;
}

View File

@ -41,9 +41,11 @@
*/
static ring_buffer usart1_rb;
static ring_buffer usart1_wb;
static usart_dev usart1 = {
.regs = USART1_BASE,
.rb = &usart1_rb,
.wb = &usart1_wb,
.max_baud = 4500000UL,
.clk_id = RCC_USART1,
.irq_num = NVIC_USART1,
@ -52,9 +54,11 @@ static usart_dev usart1 = {
usart_dev *USART1 = &usart1;
static ring_buffer usart2_rb;
static ring_buffer usart2_wb;
static usart_dev usart2 = {
.regs = USART2_BASE,
.rb = &usart2_rb,
.wb = &usart2_wb,
.max_baud = 2250000UL,
.clk_id = RCC_USART2,
.irq_num = NVIC_USART2,
@ -63,9 +67,11 @@ static usart_dev usart2 = {
usart_dev *USART2 = &usart2;
static ring_buffer usart3_rb;
static ring_buffer usart3_wb;
static usart_dev usart3 = {
.regs = USART3_BASE,
.rb = &usart3_rb,
.wb = &usart3_wb,
.max_baud = 2250000UL,
.clk_id = RCC_USART3,
.irq_num = NVIC_USART3,
@ -75,9 +81,11 @@ usart_dev *USART3 = &usart3;
#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
static ring_buffer uart4_rb;
static ring_buffer uart4_wb;
static usart_dev uart4 = {
.regs = UART4_BASE,
.rb = &uart4_rb,
.wb = &uart4_wb,
.max_baud = 2250000UL,
.clk_id = RCC_UART4,
.irq_num = NVIC_UART4,
@ -86,9 +94,11 @@ static usart_dev uart4 = {
usart_dev *UART4 = &uart4;
static ring_buffer uart5_rb;
static ring_buffer uart5_wb;
static usart_dev uart5 = {
.regs = UART5_BASE,
.rb = &uart5_rb,
.wb = &uart5_wb,
.max_baud = 2250000UL,
.clk_id = RCC_UART5,
.irq_num = NVIC_UART5,
@ -191,23 +201,23 @@ void usart_foreach(void (*fn)(usart_dev*)) {
*/
void __irq_usart1(void) {
usart_irq(&usart1_rb, USART1_BASE);
usart_irq(&usart1_rb, &usart1_wb, USART1_BASE);
}
void __irq_usart2(void) {
usart_irq(&usart2_rb, USART2_BASE);
usart_irq(&usart2_rb, &usart2_wb, USART2_BASE);
}
void __irq_usart3(void) {
usart_irq(&usart3_rb, USART3_BASE);
usart_irq(&usart3_rb, &usart3_wb, USART3_BASE);
}
#ifdef STM32_HIGH_DENSITY
void __irq_uart4(void) {
usart_irq(&uart4_rb, UART4_BASE);
usart_irq(&uart4_rb, &uart4_wb, UART4_BASE);
}
void __irq_uart5(void) {
usart_irq(&uart5_rb, UART5_BASE);
usart_irq(&uart5_rb, &uart5_wb, UART5_BASE);
}
#endif

View File

@ -381,16 +381,22 @@ typedef struct usart_reg_map {
#define USART_RX_BUF_SIZE 64
#endif
#ifndef USART_TX_BUF_SIZE
#define USART_TX_BUF_SIZE 64
#endif
/** USART device type */
typedef struct usart_dev {
usart_reg_map *regs; /**< Register map */
ring_buffer *rb; /**< RX ring buffer */
ring_buffer *wb; /**< TX ring buffer */
uint32 max_baud; /**< @brief Deprecated.
* Maximum baud rate. */
uint8 rx_buf[USART_RX_BUF_SIZE]; /**< @brief Deprecated.
* Actual RX buffer used by rb.
* This field will be removed in
* a future release. */
uint8 tx_buf[USART_TX_BUF_SIZE]; /* Actual TX buffer used by wb */
rcc_clk_id clk_id; /**< RCC clock information */
nvic_irq_num irq_num; /**< USART NVIC interrupt */
} usart_dev;
@ -502,6 +508,14 @@ static inline void usart_reset_rx(usart_dev *dev) {
rb_reset(dev->rb);
}
/**
* @brief Discard the contents of a serial port's RX buffer.
* @param dev Serial port whose buffer to empty.
*/
static inline void usart_reset_tx(usart_dev *dev) {
rb_reset(dev->wb);
}
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -37,13 +37,13 @@
#include <libmaple/ring_buffer.h>
#include <libmaple/usart.h>
static inline __always_inline void usart_irq(ring_buffer *rb, usart_reg_map *regs) {
/* We can get RXNE and ORE interrupts here. Only RXNE signifies
* availability of a byte in DR.
static inline __always_inline void usart_irq(ring_buffer *rb, ring_buffer *wb, usart_reg_map *regs) {
/* Handling RXNEIE and TXEIE interrupts.
* RXNE signifies availability of a byte in DR.
*
* See table 198 (sec 27.4, p809) in STM document RM0008 rev 15.
* We enable RXNEIE. */
if (regs->SR & USART_SR_RXNE) {
if ((regs->CR1 & USART_CR1_RXNEIE) && (regs->SR & USART_SR_RXNE)) {
#ifdef USART_SAFE_INSERT
/* If the buffer is full and the user defines USART_SAFE_INSERT,
* ignore new bytes. */
@ -53,6 +53,12 @@ static inline __always_inline void usart_irq(ring_buffer *rb, usart_reg_map *reg
rb_push_insert(rb, (uint8)regs->DR);
#endif
}
/* TXE signifies readiness to send a byte to DR. */
if ((regs->CR1 & USART_CR1_TXEIE) && (regs->SR & USART_SR_TXE)) {
regs->DR=rb_remove(wb);
if (rb_is_empty(wb))
regs->CR1 &= ~((uint32)USART_CR1_TXEIE); // disable TXEIE
}
}
uint32 _usart_clock_freq(usart_dev *dev);