Subversion Repositories libSerial

Rev

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