From 27213c7fd91ef9c8de7f0ec4efeab77ba433d31d Mon Sep 17 00:00:00 2001 From: James Cotton Date: Tue, 9 Aug 2011 01:18:25 -0500 Subject: [PATCH] F2 PiOS USART: Update to the new driver format for coms --- flight/PiOS/STM32F2xx/pios_usart.c | 382 +++++++++++------------------ 1 file changed, 148 insertions(+), 234 deletions(-) diff --git a/flight/PiOS/STM32F2xx/pios_usart.c b/flight/PiOS/STM32F2xx/pios_usart.c index f0ad8ac67..194c58d6d 100644 --- a/flight/PiOS/STM32F2xx/pios_usart.c +++ b/flight/PiOS/STM32F2xx/pios_usart.c @@ -42,34 +42,31 @@ /* Provide a COM driver */ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud); -static int32_t PIOS_USART_TxBufferPutMoreNonBlocking(uint32_t usart_id, const uint8_t *buffer, uint16_t len); -static int32_t PIOS_USART_TxBufferPutMore(uint32_t usart_id, const uint8_t *buffer, uint16_t len); -static int32_t PIOS_USART_RxBufferGet(uint32_t usart_id); -static int32_t PIOS_USART_RxBufferUsed(uint32_t usart_id); +static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context); +static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context); +static void PIOS_USART_TxStart(uint32_t usart_id, uint16_t tx_bytes_avail); +static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail); const struct pios_com_driver pios_usart_com_driver = { - .set_baud = PIOS_USART_ChangeBaud, - .tx_nb = PIOS_USART_TxBufferPutMoreNonBlocking, - .tx = PIOS_USART_TxBufferPutMore, - .rx = PIOS_USART_RxBufferGet, - .rx_avail = PIOS_USART_RxBufferUsed, + .set_baud = PIOS_USART_ChangeBaud, + .tx_start = PIOS_USART_TxStart, + .rx_start = PIOS_USART_RxStart, + .bind_tx_cb = PIOS_USART_RegisterTxCallback, + .bind_rx_cb = PIOS_USART_RegisterRxCallback, }; enum pios_usart_dev_magic { - PIOS_USART_DEV_MAGIC = 0x11223344, + PIOS_USART_DEV_MAGIC = 0x4152834A, }; struct pios_usart_dev { enum pios_usart_dev_magic magic; const struct pios_usart_cfg * cfg; - // align to 32-bit to try and provide speed improvement; - uint8_t rx_buffer[PIOS_USART_RX_BUFFER_SIZE] __attribute__ ((aligned(4))); - t_fifo_buffer rx; - - // align to 32-bit to try and provide speed improvement; - uint8_t tx_buffer[PIOS_USART_TX_BUFFER_SIZE] __attribute__ ((aligned(4))); - t_fifo_buffer tx; + pios_com_callback rx_in_cb; + uint32_t rx_in_context; + pios_com_callback tx_out_cb; + uint32_t tx_out_context; }; static bool PIOS_USART_validate(struct pios_usart_dev * usart_dev) @@ -114,21 +111,47 @@ static struct pios_usart_dev * PIOS_USART_alloc(void) */ static void PIOS_USART_generic_irq_handler(uint32_t usart_id); -#define USART_HANDLER(_n) \ - static uint32_t PIOS_USART_ ## _n ## _id; \ - void USART ## _n ## _IRQHandler(void) __attribute__ ((alias ("PIOS_USART_" #_n "_irq_handler"))); \ - static void PIOS_USART_ ## _n ## _irq_handler (void) \ - { \ - PIOS_USART_generic_irq_handler (PIOS_USART_ ## _n ## _id); \ - } \ - struct hack +static uint32_t PIOS_USART_1_id; +void USART1_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_1_irq_handler"))); +static void PIOS_USART_1_irq_handler (void) +{ + PIOS_USART_generic_irq_handler (PIOS_USART_1_id); +} -USART_HANDLER(1); -USART_HANDLER(2); -USART_HANDLER(3); -USART_HANDLER(4); -USART_HANDLER(5); -USART_HANDLER(6); +static uint32_t PIOS_USART_2_id; +void USART2_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_2_irq_handler"))); +static void PIOS_USART_2_irq_handler (void) +{ + PIOS_USART_generic_irq_handler (PIOS_USART_2_id); +} + +static uint32_t PIOS_USART_3_id; +void USART3_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_3_irq_handler"))); +static void PIOS_USART_3_irq_handler (void) +{ + PIOS_USART_generic_irq_handler (PIOS_USART_3_id); +} + +static uint32_t PIOS_USART_4_id; +void USART4_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_4_irq_handler"))); +static void PIOS_USART_4_irq_handler (void) +{ + PIOS_USART_generic_irq_handler (PIOS_USART_4_id); +} + +static uint32_t PIOS_USART_5_id; +void USART5_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_5_irq_handler"))); +static void PIOS_USART_5_irq_handler (void) +{ + PIOS_USART_generic_irq_handler (PIOS_USART_5_id); +} + +static uint32_t PIOS_USART_6_id; +void USART6_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_6_irq_handler"))); +static void PIOS_USART_6_irq_handler (void) +{ + PIOS_USART_generic_irq_handler (PIOS_USART_6_id); +} /** * Initialise a single USART device @@ -146,10 +169,6 @@ int32_t PIOS_USART_Init(uint32_t * usart_id, const struct pios_usart_cfg * cfg) /* Bind the configuration to the device instance */ usart_dev->cfg = cfg; - /* Clear buffer counters */ - fifoBuf_init(&usart_dev->rx, usart_dev->rx_buffer, sizeof(usart_dev->rx_buffer)); - fifoBuf_init(&usart_dev->tx, usart_dev->tx_buffer, sizeof(usart_dev->tx_buffer)); - /* Map pins to USART function */ /* note __builtin_ctz() due to the difference between GPIO_PinX and GPIO_PinSourceX */ if (usart_dev->cfg->remap) { @@ -165,6 +184,28 @@ int32_t PIOS_USART_Init(uint32_t * usart_id, const struct pios_usart_cfg * cfg) GPIO_Init(usart_dev->cfg->rx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->rx.init); GPIO_Init(usart_dev->cfg->tx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->tx.init); + /* Enable USART clock */ + switch ((uint32_t)usart_dev->cfg->regs) { + case (uint32_t)USART1: + RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); + break; + case (uint32_t)USART2: + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); + break; + case (uint32_t)USART3: + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); + break; + case (uint32_t)UART4: + RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE); + break; + case (uint32_t)UART5: + RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE); + break; + case (uint32_t)USART6: + RCC_APB1PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE); + break; + } + /* Configure the USART */ USART_Init(usart_dev->cfg->regs, (USART_InitTypeDef *)&usart_dev->cfg->init); @@ -192,8 +233,6 @@ int32_t PIOS_USART_Init(uint32_t * usart_id, const struct pios_usart_cfg * cfg) break; } NVIC_Init((NVIC_InitTypeDef *)&(usart_dev->cfg->irq.init)); - USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE); - USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE); // FIXME XXX Clear / reset uart here - sends NUL char else @@ -206,251 +245,126 @@ out_fail: return(-1); } -const struct pios_usart_cfg * PIOS_USART_GetConfig(uint32_t usart_id) +static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail) { struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; - + bool valid = PIOS_USART_validate(usart_dev); - - if (!valid) { - return (NULL); - } - - return usart_dev->cfg; + PIOS_Assert(valid); + + USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE); +} +static void PIOS_USART_TxStart(uint32_t usart_id, uint16_t tx_bytes_avail) +{ + struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + PIOS_Assert(valid); + + USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE); } /** -* Changes the baud rate of the USART peripheral without re-initialising. -* \param[in] usart_id USART name (GPS, TELEM, AUX) -* \param[in] baud Requested baud rate -*/ + * Changes the baud rate of the USART peripheral without re-initialising. + * \param[in] usart_id USART name (GPS, TELEM, AUX) + * \param[in] baud Requested baud rate + */ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud) { struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; - + bool valid = PIOS_USART_validate(usart_dev); PIOS_Assert(valid); - + USART_InitTypeDef USART_InitStructure; - + /* Start with a copy of the default configuration for the peripheral */ USART_InitStructure = usart_dev->cfg->init; - + /* Adjust the baud rate */ USART_InitStructure.USART_BaudRate = baud; - + /* Write back the new configuration */ USART_Init(usart_dev->cfg->regs, &USART_InitStructure); } -/** -* Returns number of used bytes in receive buffer -* \param[in] USART USART name -* \return > 0: number of used bytes -* \return 0 if USART not available -*/ -static int32_t PIOS_USART_RxBufferUsed(uint32_t usart_id) +static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context) { struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; - - bool valid = PIOS_USART_validate(usart_dev); - PIOS_Assert(valid) - - return (fifoBuf_getUsed(&usart_dev->rx)); -} - -/** -* Gets a byte from the receive buffer -* \param[in] USART USART name -* \return -1 if no new byte available -* \return >= 0: actual byte received -*/ -static int32_t PIOS_USART_RxBufferGet(uint32_t usart_id) -{ - struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; - - bool valid = PIOS_USART_validate(usart_dev); - PIOS_Assert(valid) - - if (fifoBuf_getUsed(&usart_dev->rx) == 0) { - /* Nothing new in the buffer */ - return -1; - } - - /* get byte - this operation should be atomic! */ - uint8_t b = fifoBuf_getByte(&usart_dev->rx); - - /* Return received byte */ - return b; -} - -/** -* puts a byte onto the receive buffer -* \param[in] USART USART name -* \param[in] b byte which should be put into Rx buffer -* \return 0 if no error -* \return -1 if buffer full (retry) -*/ -static int32_t PIOS_USART_RxBufferPut(uint32_t usart_id, uint8_t b) -{ - struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; - - bool valid = PIOS_USART_validate(usart_dev); - PIOS_Assert(valid) - - if (fifoBuf_getFree(&usart_dev->rx) < 1) { - /* Buffer full (retry) */ - return -1; - } - - /* Copy received byte into receive buffer */ - /* This operation should be atomic! */ - fifoBuf_putByte(&usart_dev->rx, b); - - /* No error */ - return 0; -} - -/** -* returns number of used bytes in transmit buffer -* \param[in] USART USART name -* \return number of used bytes -* \return 0 if USART not available -*/ -static int32_t PIOS_USART_TxBufferUsed(uint32_t usart_id) -{ - struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; - - bool valid = PIOS_USART_validate(usart_dev); - PIOS_Assert(valid) - - return (fifoBuf_getUsed(&usart_dev->tx)); -} - -/** -* gets a byte from the transmit buffer -* \param[in] USART USART name -* \return -1 if no new byte available -* \return >= 0: transmitted byte -*/ -static int32_t PIOS_USART_TxBufferGet(uint32_t usart_id) -{ - struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; - - bool valid = PIOS_USART_validate(usart_dev); - PIOS_Assert(valid) - - if (fifoBuf_getUsed(&usart_dev->tx) == 0) { - /* Nothing new in the buffer */ - return -1; - } - - /* get byte - this operation should be atomic! */ - PIOS_IRQ_Disable(); - uint8_t b = fifoBuf_getByte(&usart_dev->tx); - PIOS_IRQ_Enable(); - - /* Return received byte */ - return b; -} - -/** -* puts more than one byte onto the transmit buffer (used for atomic sends) -* \param[in] USART USART name -* \param[in] *buffer pointer to buffer to be sent -* \param[in] len number of bytes to be sent -* \return 0 if no error -* \return -1 if buffer full or cannot get all requested bytes (retry) -*/ -static int32_t PIOS_USART_TxBufferPutMoreNonBlocking(uint32_t usart_id, const uint8_t *buffer, uint16_t len) -{ - struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; - - bool valid = PIOS_USART_validate(usart_dev); - PIOS_Assert(valid) - - if (len >= fifoBuf_getFree(&usart_dev->tx)) { - /* Buffer cannot accept all requested bytes (retry) */ - return -1; - } - - /* Copy bytes to be transmitted into transmit buffer */ - /* This operation should be atomic! */ - PIOS_IRQ_Disable(); - - uint16_t used = fifoBuf_getUsed(&usart_dev->tx); - fifoBuf_putData(&usart_dev->tx,buffer,len); - if (used == 0) { - /* enable sending when buffer was previously empty */ - USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE); - } - - PIOS_IRQ_Enable(); - - /* No error */ - return 0; + bool valid = PIOS_USART_validate(usart_dev); + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usart_dev->rx_in_context = context; + usart_dev->rx_in_cb = rx_in_cb; } -/** -* puts more than one byte onto the transmit buffer (used for atomic sends)
-* (blocking function) -* \param[in] USART USART name -* \param[in] *buffer pointer to buffer to be sent -* \param[in] len number of bytes to be sent -* \return 0 if no error -*/ -static int32_t PIOS_USART_TxBufferPutMore(uint32_t usart_id, const uint8_t *buffer, uint16_t len) +static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context) { - int32_t rc; - - while ((rc = PIOS_USART_TxBufferPutMoreNonBlocking(usart_id, buffer, len)) == -1); - - return rc; + struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usart_dev->tx_out_context = context; + usart_dev->tx_out_cb = tx_out_cb; } static void PIOS_USART_generic_irq_handler(uint32_t usart_id) { struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id; - + bool valid = PIOS_USART_validate(usart_dev); PIOS_Assert(valid); - - /* Call any user provided callback function instead of processing - * the interrupt ourselves. - */ - if (usart_dev->cfg->irq.handler) { - (usart_dev->cfg->irq.handler)(usart_id); - return; - } - + /* Force read of dr after sr to make sure to clear error flags */ volatile uint16_t sr = usart_dev->cfg->regs->SR; volatile uint8_t dr = usart_dev->cfg->regs->DR; - + /* Check if RXNE flag is set */ + bool rx_need_yield = false; if (sr & USART_SR_RXNE) { - if (PIOS_USART_RxBufferPut(usart_id, dr) < 0) { - /* Here we could add some error handling */ + uint8_t byte = dr; + if (usart_dev->rx_in_cb) { + (void) (usart_dev->rx_in_cb)(usart_dev->rx_in_context, &byte, 1, NULL, &rx_need_yield); } } - + /* Check if TXE flag is set */ + bool tx_need_yield = false; if (sr & USART_SR_TXE) { - if (PIOS_USART_TxBufferUsed(usart_id) > 0) { - int32_t b = PIOS_USART_TxBufferGet(usart_id); - - if (b < 0) { - /* Here we could add some error handling */ - usart_dev->cfg->regs->DR = 0xff; + if (usart_dev->tx_out_cb) { + uint8_t b; + uint16_t bytes_to_send; + + bytes_to_send = (usart_dev->tx_out_cb)(usart_dev->tx_out_context, &b, 1, NULL, &tx_need_yield); + + if (bytes_to_send > 0) { + /* Send the byte we've been given */ + usart_dev->cfg->regs->DR = b; } else { - usart_dev->cfg->regs->DR = b & 0xff; + /* No bytes to send, disable TXE interrupt */ + USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE); } } else { - /* Disable TXE interrupt (TXEIE=0) */ + /* No bytes to send, disable TXE interrupt */ USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE); } } + +#if defined(PIOS_INCLUDE_FREERTOS) + if (rx_need_yield || tx_need_yield) { + vPortYieldFromISR(); + } +#endif /* PIOS_INCLUDE_FREERTOS */ } #endif