Subversion Repositories libSerial

Rev

Rev 5 | Rev 7 | 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->Handle, 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->Handle, 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->Handle, 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->Handle, 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->Handle, 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->Handle, UART_IT_RXNE);
  75.       __WFI (); /* wait for something */
  76.       __HAL_UART_DISABLE_IT (instance->Handle, 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->Handle, 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->Handle, 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->Handle, 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->Handle, 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->Handle->Instance->SR;// read the status bits - this resets all the hardware signalling flags
  141.  
  142.   if ((rxStatus & USART_SR_LBD))
  143.       __HAL_UART_CLEAR_FLAG(instance->Handle,USART_SR_LBD);
  144.  
  145.   if ((rxStatus & USART_SR_RXNE)!= RESET)
  146.     {
  147.       // no error has occurred...
  148.       uint8_t rxChar = (uint8_t) (instance->Handle->Instance->DR & 0xff);// read the bottom 8-bits only
  149.  
  150.       if (!instance->rx_usart_buffer_full)
  151.         {
  152.           instance->rx_usart_buff[instance->rx_usart_in_Ptr++] = rxChar;
  153.  
  154.           if (instance->rx_usart_in_Ptr >= RX_USART_BUFF_SIZ)
  155.             {
  156.               instance->rx_usart_in_Ptr = 0;
  157.             }
  158.           if (instance->rx_usart_in_Ptr == instance->rx_usart_out_Ptr)
  159.             {
  160.               instance->rx_usart_buffer_full = 1; /* buffer overrun */
  161.             }
  162.         }
  163.     }
  164.   /* check for transmitter interrupt : this code is used */
  165.   if ((rxStatus & USART_SR_TXE) != RESET)
  166.     {
  167.  
  168.  
  169.       /* Only enable the transmitter when baud detect has completed or check expired.
  170.        * and the software is ready for it to be enabled as programming mode is wanting
  171.        * to receive a response and that can get blocked if we're streaming a lot of debug messages*/
  172.       if (instance->tx_usart_in_Ptr != instance->tx_usart_out_Ptr)
  173.         {
  174.           instance->Handle->Instance->DR =
  175.               instance->tx_usart_buff[instance->tx_usart_out_Ptr++];
  176.           if (instance->tx_usart_count != 0)
  177.             instance->tx_usart_count -= 1;
  178.  
  179.           if (instance->tx_usart_out_Ptr >= TX_USART_BUFF_SIZ)
  180.             {
  181.               instance->tx_usart_out_Ptr = 0;
  182.             }
  183.         }
  184.       if (instance->tx_usart_count == 0)
  185.         {
  186.           __HAL_UART_DISABLE_IT (instance->Handle, UART_IT_TXE);
  187.           instance->tx_usart_running = 0;
  188.         }
  189.     }
  190.  
  191.   __enable_irq ();
  192. }
  193.  
  194. void
  195. PutCharSerial (usart_ctl *instance, uint8_t c)
  196. {
  197.   // Put character in Crayon/Pen interface
  198.   PutCharSerialFIFO (instance, c);
  199. }
  200.  
  201. /*
  202.  * \brief
  203.  * ResetTxBuffer(void) - resets the serial transmitter buffer
  204.  */
  205. void
  206. ResetTxBuffer (usart_ctl *instance)
  207. {
  208.  
  209.   instance->tx_usart_out_Ptr = 0;
  210.   instance->tx_usart_running = 0;
  211.   instance->tx_usart_in_Ptr = 0; /* setup in pointer last to drop any chars come in */
  212.   instance->tx_usart_count = 0;
  213.  
  214. }
  215.  
  216. /*
  217.  * \brief
  218.  * void ResetRxBuffer(void) - resets the serial receiver buffer
  219.  */
  220. void
  221. ResetRxBuffer (usart_ctl *instance)
  222. {
  223.  
  224.   instance->rx_usart_out_Ptr = 0;
  225.   instance->rx_usart_buffer_full = 0;
  226.   instance->rx_usart_in_Ptr = 0; /* setup in pointer last to drop any chars come in */
  227.  
  228. }
  229.  
  230. /***!
  231.  * @brief Flush Serial input and output buffers
  232.  */
  233. void
  234. FlushSerial (usart_ctl *instance)
  235. {
  236.   ResetRxBuffer (instance);
  237.   ResetTxBuffer (instance);
  238. }
  239.  
  240. /***!
  241.  * @brief check if tx buffer is empty...
  242.  */
  243. uint8_t
  244. TxBufferEmpty (usart_ctl *instance)
  245. {
  246.   return (0 == instance->tx_usart_count );
  247. }
  248.  
  249. /***!
  250.  * @brief wait for transmission to finish
  251.  */
  252.  
  253. void TxWaitEmpty(usart_ctl *instance)
  254. {
  255.   while (instance->tx_usart_count ||
  256.        (instance->Handle->Instance->SR & USART_SR_TC) != RESET) {};
  257. }
  258.  
  259. /****
  260.  * @brief Initialise control structure
  261.  */
  262. void
  263. init_usart_ctl (usart_ctl *instance, UART_HandleTypeDef * handle )
  264. {
  265.  
  266.   instance->Handle = handle;
  267.  
  268.   /* cheat here - this is a macro and I have the same Instance member as the HAL handle, with the same meaning */
  269.    __HAL_UART_DISABLE_IT (instance->Handle, UART_IT_TXE);
  270.   __HAL_UART_DISABLE_IT (instance->Handle, UART_IT_RXNE);
  271.  
  272.   instance->tx_usart_in_Ptr = 0;
  273.   instance->tx_usart_out_Ptr = 0;
  274.   instance->tx_usart_running = 0;
  275.   instance->tx_usart_count = 0;
  276.  
  277.   instance->rx_usart_in_Ptr = 0;
  278.   instance->rx_usart_out_Ptr = 0;
  279.   instance->rx_usart_buffer_full = 0;
  280.  
  281. }
  282.  
  283. void
  284. setBaud (usart_ctl *ctl, uint32_t baud)
  285. {
  286.   ctl->Handle->Init.BaudRate = baud;
  287.   __disable_irq ();
  288.   HAL_UART_Init (ctl->Handle);
  289.   __enable_irq ();
  290. }
  291.  
  292.  
  293.  
  294. /////////////////////////////////////////////////////////
  295. /// Moved from generated code  to avoid crappy HAL handler
  296. #if defined SERIAL_UART1
  297. void USART1_IRQHandler(void)
  298. {
  299.         UART_IRQHandler(&uc1);
  300. }
  301. #endif
  302. #if defined SERIAL_UART2
  303. void USART2_IRQHandler(void)
  304. {
  305.         UART_IRQHandler(&uc2);
  306. }
  307. #endif
  308. #if defined SERIAL_UART3
  309. void USART3_IRQHandler(void)
  310. {
  311.         UART_IRQHandler(&uc3);
  312. }
  313. #endif
  314.