Subversion Repositories DashDisplay

Rev

Rev 28 | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * serial.c
  3.  *
  4.  *  Created on: 4 Jan 2016
  5.  *      Author: Mike
  6.  *
  7.  *      This (ab)uses the STMCubeMX HAL declarations to implement a generic STM32F1xx
  8.  *      USART driver layer
  9.  */
  10.  
  11.  
  12. #include "serial.h"
  13.  
  14. /* workspaces for the USARTS being used */
  15. usart_ctl uc1;
  16. usart_ctl uc2;
  17. usart_ctl uc3;
  18.  
  19.  
  20.  
  21. /* returns the number of characters received by the Rx USART */
  22. uint16_t SerialCharsReceived(usart_ctl * instance)
  23. {
  24.         uint16_t result = 0;    // assume no characters received yet
  25.         __HAL_UART_DISABLE_IT(instance,  UART_IT_RXNE);
  26.  
  27.         if (instance->rx_usart_buffer_full)
  28.         {       // buffer is full...
  29.                 result = RX_USART_BUFF_SIZ;
  30.         }
  31.         else if (instance->rx_usart_in_Ptr >= instance->rx_usart_out_Ptr)
  32.         {       // buffer has not wrapped...
  33.                 result = instance->rx_usart_in_Ptr - instance->rx_usart_out_Ptr;
  34.         }
  35.         else
  36.         {       // buffer has possibly wrapped...
  37.                 result = RX_USART_BUFF_SIZ - instance->rx_usart_out_Ptr + instance->rx_usart_in_Ptr;
  38.         }
  39.         __HAL_UART_ENABLE_IT(instance,  UART_IT_RXNE);
  40.  
  41.         return result;
  42. }
  43.  
  44. inline uint8_t PollSerial(usart_ctl * instance)
  45. {
  46.         uint8_t rc;
  47.  
  48.         __HAL_UART_DISABLE_IT(instance,  UART_IT_RXNE);
  49.     rc =  ( instance->rx_usart_buffer_full || (instance->rx_usart_in_Ptr != instance->rx_usart_out_Ptr));
  50.         __HAL_UART_ENABLE_IT(instance,  UART_IT_RXNE);
  51.  
  52.         return rc;
  53. }
  54.  
  55. /***!
  56.  * @brief return the next character in the Serial input buffer
  57.  * This function will wait until a character arrives.
  58.  */
  59. uint8_t GetCharSerial(usart_ctl * instance)
  60. {
  61.         uint8_t c;
  62.         __HAL_UART_DISABLE_IT(instance,  UART_IT_RXNE);
  63.         while (!instance->rx_usart_buffer_full && (instance->rx_usart_in_Ptr == instance->rx_usart_out_Ptr))
  64.         {
  65.                 __HAL_UART_ENABLE_IT(instance,  UART_IT_RXNE);
  66.                 __WFI(); /* wait for something */
  67.                 __HAL_UART_DISABLE_IT(instance,  UART_IT_RXNE);
  68.         }
  69.  
  70.  
  71.         c = instance->rx_usart_buff[instance->rx_usart_out_Ptr];
  72.         instance->rx_usart_buffer_full = 0; /* removed character */
  73.         instance->rx_usart_out_Ptr++;
  74.         if (instance->rx_usart_out_Ptr >= RX_USART_BUFF_SIZ)
  75.         {
  76.                 instance->rx_usart_out_Ptr = 0;
  77.         }
  78.         __HAL_UART_ENABLE_IT(instance,  UART_IT_RXNE);
  79.         return c;
  80. }
  81.  
  82.  
  83. /*
  84.  * \brief
  85.  * void EnableSerialRxInterrupt(void) - this function is used from the interrupt handler and the main scheduler loop
  86.  * to enable the serial rx interrupt after resetting the serial rx buffer...
  87.  */
  88. inline void EnableSerialRxInterrupt(usart_ctl * instance)
  89. {
  90.         /* cheat here - this is a macro and I have the same Instance member as the HAL handle, with the same meaning */
  91.         __HAL_UART_ENABLE_IT(instance,  UART_IT_RXNE);
  92. }
  93.  
  94.  
  95.  
  96.  
  97.  
  98.  
  99. /****!
  100.  * @brief send a character to the serial USART via placing it in the serial buffer
  101.  *
  102.  */
  103.  
  104.  
  105. static void PutCharSerialFIFO(usart_ctl * instance,uint8_t c) {
  106.         __HAL_UART_DISABLE_IT(instance, UART_IT_TXE);
  107.  
  108.         instance->tx_usart_buff[instance->tx_usart_in_Ptr++] = c;
  109.         instance->tx_usart_count += 1;
  110.         if (instance->tx_usart_in_Ptr >= TX_USART_BUFF_SIZ) {
  111.                 instance->tx_usart_in_Ptr = 0;
  112.         }
  113.         /* Handle overrun by losing oldest characters */
  114.         if (instance->tx_usart_in_Ptr == instance->tx_usart_out_Ptr) {
  115.                 instance->tx_usart_out_Ptr++;
  116.                 if (instance->tx_usart_out_Ptr >= TX_USART_BUFF_SIZ) {
  117.                         instance->tx_usart_out_Ptr = 0;
  118.                 }
  119.         }
  120.  
  121.  
  122.         instance->tx_usart_running = 1;
  123.         __HAL_UART_ENABLE_IT(instance, UART_IT_TXE);
  124. }
  125.  
  126. void UART_IRQHandler(usart_ctl * instance)
  127. {
  128.  
  129.         __disable_irq();
  130.         uint32_t rxStatus;      // status from USART receiver
  131.  
  132.         rxStatus = instance->Instance->SR;      // read the status bits - this resets all the hardware signalling flags
  133.  
  134.         if (rxStatus & USART_SR_RXNE) {
  135.                 // no error has occurred...
  136.                 uint8_t rxChar = (uint8_t)(instance->Instance->DR & 0xff);      // read the bottom 8-bits only
  137.  
  138.                 if (!instance->rx_usart_buffer_full) {
  139.                         instance->rx_usart_buff[instance->rx_usart_in_Ptr++] = rxChar;
  140.  
  141.                         if (instance->rx_usart_in_Ptr >= RX_USART_BUFF_SIZ) {
  142.                                 instance->rx_usart_in_Ptr = 0;
  143.                         }
  144.                         if (instance->rx_usart_in_Ptr == instance->rx_usart_out_Ptr) {
  145.                                 instance->rx_usart_buffer_full = 1; /* buffer overrun */
  146.                         }
  147.                 }
  148.         }
  149.         /* check for transmitter interrupt : this code is used */
  150.         if ((rxStatus & USART_SR_TXE) != RESET) {
  151.  
  152.                 /* Only enable the transmitter when baud detect has completed or check expired.
  153.                  * and the software is ready for it to be enabled as programming mode is wanting
  154.                  * to receive a response and that can get blocked if we're streaming a lot of debug messages*/
  155.                 if (instance->tx_usart_in_Ptr != instance->tx_usart_out_Ptr) {
  156.                         instance->Instance->DR = instance->tx_usart_buff[instance->tx_usart_out_Ptr++];
  157.                         if (instance->tx_usart_count != 0)
  158.                                 instance->tx_usart_count -= 1;
  159.  
  160.                         if (instance->tx_usart_out_Ptr >= TX_USART_BUFF_SIZ) {
  161.                                 instance->tx_usart_out_Ptr = 0;
  162.                         }
  163.                 } else {
  164.                         __HAL_UART_DISABLE_IT(instance, UART_IT_TXE);
  165.                         instance->tx_usart_running = 0;
  166.                 }
  167.         }
  168.  
  169.         __enable_irq();
  170. }
  171.  
  172.  
  173. void PutCharSerial(usart_ctl * instance,uint8_t c)
  174. {
  175.         // Put character in Crayon/Pen interface
  176.         PutCharSerialFIFO(instance,c);
  177. }
  178.  
  179. /*
  180.  * \brief
  181.  * ResetTxBuffer(void) - resets the serial transmitter buffer
  182.  */
  183. void ResetTxBuffer(usart_ctl * instance)
  184. {
  185.  
  186.         instance->tx_usart_out_Ptr = 0;
  187.         instance->tx_usart_running = 0;
  188.         instance->tx_usart_in_Ptr = 0; /* setup in pointer last to drop any chars come in */
  189.         instance->tx_usart_count = 0;
  190.  
  191. }
  192.  
  193. /*
  194.  * \brief
  195.  * void ResetRxBuffer(void) - resets the serial receiver buffer
  196.  */
  197. void ResetRxBuffer(usart_ctl * instance)
  198. {
  199.  
  200.         instance->rx_usart_out_Ptr = 0;
  201.         instance->rx_usart_buffer_full = 0;
  202.         instance->rx_usart_in_Ptr = 0; /* setup in pointer last to drop any chars come in */
  203.  
  204. }
  205.  
  206. /***!
  207.  * @brief Flush Serial input and output buffers
  208.  */
  209. void FlushSerial(usart_ctl * instance)
  210. {
  211.         ResetRxBuffer(instance);
  212.         ResetTxBuffer(instance);
  213. }
  214.  
  215.  
  216. /***!
  217.  * @brief check if tx buffer is empty...
  218.  */
  219.  
  220. uint8_t  TxBufferEmpty(usart_ctl * instance)
  221. {
  222.         return (0 == instance->tx_usart_count);
  223. }
  224.  
  225.  
  226. /****
  227.  * @brief Initialise control structure
  228.  */
  229. void init_usart_ctl(usart_ctl * instance, USART_TypeDef * hardware)
  230. {
  231.         instance->Instance = hardware;
  232.  
  233.         instance->tx_usart_in_Ptr = 0;
  234.         instance->tx_usart_out_Ptr = 0;
  235.         instance->tx_usart_running = 0;
  236.         instance->tx_usart_count = 0;
  237.  
  238.         instance->rx_usart_in_Ptr = 0;
  239.         instance->rx_usart_out_Ptr = 0;
  240.         instance->rx_usart_buffer_full = 0;
  241.  
  242. }
  243.  
  244.  
  245. /////////////////////////////////////////////////////////
  246. /// Moved from generated code  to avoid crappy HAL handler
  247. void USART1_IRQHandler(void)
  248. {
  249.         UART_IRQHandler(&uc1);
  250. }
  251.  
  252. void USART2_IRQHandler(void)
  253. {
  254.         UART_IRQHandler(&uc2);
  255. }
  256.  
  257. void USART3_IRQHandler(void)
  258. {
  259.         UART_IRQHandler(&uc3);
  260. }
  261.  
  262.