Subversion Repositories libSerial

Rev

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