Subversion Repositories libSerial

Rev

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