Subversion Repositories libSerial

Rev

Rev 13 | 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.  
  16. #include "libSerial/serial.h"
  17.  
  18. /* workspaces for the USARTS being used */
  19. #if defined SERIAL_UART1
  20. struct usart_ctl uc1;
  21. #endif
  22. #if defined SERIAL_UART2
  23. struct usart_ctl uc2;
  24. #endif
  25. #if defined SERIAL_UART3
  26. struct usart_ctl uc3;
  27. #endif
  28. #if defined SERIAL_UART4
  29. struct usart_ctl uc4;
  30. #endif
  31. #if defined SERIAL_UART5
  32. struct usart_ctl uc5;
  33. #endif
  34.  
  35. uint16_t
  36. SerialCharsReceived(struct 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 = instance->rx_usart_buff_size;
  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 = instance->rx_usart_buff_size - 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(struct 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 : instance->tx_usart_buff_size;
  66.   }
  67.   else if (instance->tx_usart_in_Ptr > instance->tx_usart_out_Ptr)
  68.   { // buffer has not wrapped...
  69.     result = instance->tx_usart_buff_size - instance->tx_usart_in_Ptr - instance->tx_usart_out_Ptr;
  70.   }
  71.   else
  72.   { // buffer has possibly wrapped...
  73.     result = instance->tx_usart_buff_size - 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(struct 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. inline uint8_t
  93. GetCharSerial(struct usart_ctl *instance)
  94. {
  95.   uint8_t c;
  96.   __HAL_UART_DISABLE_IT(instance->Handle, UART_IT_RXNE);
  97.   while (!instance->rx_usart_buffer_full && (instance->rx_usart_in_Ptr == instance->rx_usart_out_Ptr))
  98.   {
  99.     __HAL_UART_ENABLE_IT(instance->Handle, UART_IT_RXNE);
  100.     __WFI(); /* wait for something */
  101.     __HAL_UART_DISABLE_IT(instance->Handle, UART_IT_RXNE);
  102.   }
  103.  
  104.   c = instance->rx_usart_buff[instance->rx_usart_out_Ptr];
  105.   instance->rx_usart_buffer_full = 0; /* removed character */
  106.   instance->rx_usart_out_Ptr++;
  107.   if (instance->rx_usart_out_Ptr >= instance->rx_usart_buff_size)
  108.   {
  109.     instance->rx_usart_out_Ptr = 0;
  110.   }
  111.   __HAL_UART_ENABLE_IT(instance->Handle, UART_IT_RXNE);
  112.   return c;
  113. }
  114.  
  115. /*
  116.  * \brief
  117.  * void EnableSerialRxInterrupt(void) - this function is used from the interrupt handler and the main scheduler loop
  118.  * to enable the serial rx interrupt after resetting the serial rx buffer...
  119.  */
  120. inline void
  121. EnableSerialRxInterrupt(struct usart_ctl *instance)
  122. {
  123.   /* cheat here - this is a macro and I have the same Instance member as the HAL handle, with the same meaning */
  124.   __HAL_UART_ENABLE_IT(instance->Handle, UART_IT_RXNE);
  125. }
  126.  
  127. /****!
  128.  * @brief send a character to the serial USART via placing it in the serial buffer
  129.  *
  130.  */
  131.  
  132. static void
  133. PutCharSerialFIFO(struct usart_ctl *instance, uint8_t c)
  134. {
  135.   __HAL_UART_DISABLE_IT(instance->Handle, UART_IT_TXE);
  136.  
  137.   instance->tx_usart_buff[instance->tx_usart_in_Ptr++] = c;
  138.   if (instance->tx_usart_in_Ptr >= instance->tx_usart_buff_size)
  139.   {
  140.     instance->tx_usart_in_Ptr = 0;
  141.   }
  142.   /* Handle overrun by losing oldest characters */
  143.   if (instance->tx_usart_in_Ptr == instance->tx_usart_out_Ptr)
  144.   {
  145.     instance->tx_usart_overruns++;
  146.     instance->tx_usart_out_Ptr++;
  147.     if (instance->tx_usart_out_Ptr >= instance->tx_usart_buff_size)
  148.     {
  149.       instance->tx_usart_out_Ptr = 0;
  150.     }
  151.   }
  152.  
  153.   instance->tx_usart_running = 1;
  154.   __HAL_UART_ENABLE_IT(instance->Handle, UART_IT_TXE);
  155. }
  156.  
  157. void UART_IRQHandler(struct usart_ctl *instance)
  158. {
  159.  
  160.   __disable_irq();
  161.   // status from USART receiver
  162.   uint32_t rxStatus = instance->Handle->Instance->SR; // read the status bits - this resets all the hardware signalling flags
  163.  
  164.   if ((rxStatus & USART_SR_LBD))
  165.     __HAL_UART_CLEAR_FLAG(instance->Handle, USART_SR_LBD);
  166.  
  167.   if ((rxStatus & USART_SR_RXNE) != RESET)
  168.   {
  169.     // no error has occurred...
  170.     uint8_t rxChar = (uint8_t)(instance->Handle->Instance->DR & 0xff); // read the bottom 8-bits only
  171.  
  172.     if (!instance->rx_usart_buffer_full)
  173.     {
  174.       instance->rx_usart_buff[instance->rx_usart_in_Ptr++] = rxChar;
  175.  
  176.       if (instance->rx_usart_in_Ptr >= instance->rx_usart_buff_size)
  177.       {
  178.         instance->rx_usart_in_Ptr = 0;
  179.       }
  180.       if (instance->rx_usart_in_Ptr == instance->rx_usart_out_Ptr)
  181.       {
  182.         instance->rx_usart_buffer_full = 1; /* buffer overrun */
  183.       }
  184.     }
  185.   }
  186.   /* check for transmitter interrupt : this code is used */
  187.   if ((rxStatus & USART_SR_TXE) != RESET)
  188.   {
  189.  
  190.     /* Only enable the transmitter when baud detect has completed or check expired.
  191.      * and the software is ready for it to be enabled as programming mode is wanting
  192.      * to receive a response and that can get blocked if we're streaming a lot of debug messages*/
  193.     if (instance->tx_usart_in_Ptr != instance->tx_usart_out_Ptr)
  194.     {
  195.       instance->Handle->Instance->DR =
  196.           instance->tx_usart_buff[instance->tx_usart_out_Ptr++];
  197.  
  198.       if (instance->tx_usart_out_Ptr >= instance-> tx_usart_buff_size)
  199.       {
  200.         instance->tx_usart_out_Ptr = 0;
  201.       }
  202.     }
  203.     if (instance->tx_usart_in_Ptr == instance->tx_usart_out_Ptr)
  204.     {
  205.       __HAL_UART_DISABLE_IT(instance->Handle, UART_IT_TXE);
  206.       instance->tx_usart_running = 0;
  207.     }
  208.   }
  209.   __enable_irq();
  210. }
  211.  
  212. void PutCharSerial(struct usart_ctl *instance, uint8_t c)
  213. {
  214.   PutCharSerialFIFO(instance, c);
  215. }
  216.  
  217. void ResetTxBuffer(struct usart_ctl *instance)
  218. {
  219.  
  220.   instance->tx_usart_out_Ptr = 0;
  221.   instance->tx_usart_running = 0;
  222.   instance->tx_usart_in_Ptr = 0; /* setup in pointer last to drop any chars come in */
  223.   instance->tx_usart_overruns = 0;
  224. }
  225.  
  226. /*
  227.  * \brief
  228.  * void ResetRxBuffer(void) - resets the serial receiver buffer
  229.  */
  230. void ResetRxBuffer(struct usart_ctl *instance)
  231. {
  232.  
  233.   instance->rx_usart_out_Ptr = 0;
  234.   instance->rx_usart_buffer_full = 0;
  235.   instance->rx_usart_in_Ptr = 0; /* setup in pointer last to drop any chars come in */
  236. }
  237.  
  238. /***!
  239.  * @brief Flush Serial input and output buffers
  240.  */
  241. void FlushSerial(struct usart_ctl *instance)
  242. {
  243.   ResetRxBuffer(instance);
  244.   ResetTxBuffer(instance);
  245. }
  246.  
  247. /***!
  248.  * @brief check if tx buffer is empty...
  249.  */
  250. uint8_t
  251. TxBufferEmpty(struct usart_ctl *instance)
  252. {
  253.   if (instance->tx_usart_running)
  254.     return 0;
  255.   return (instance->Handle->Instance->SR & USART_SR_TC) == 0;
  256. }
  257.  
  258. /***!
  259.  * @brief wait for transmission to finish
  260.  */
  261.  
  262. void TxWaitEmpty(struct usart_ctl *instance)
  263. {
  264.   // no wait if not running
  265.   if (!instance->tx_usart_running)
  266.     return;
  267.   // wait for it to finish
  268.   while (instance->tx_usart_running ||
  269.          (instance->Handle->Instance->SR & USART_SR_TC) != RESET)
  270.   {
  271.   };
  272. }
  273.  
  274. /****
  275.  * @brief Initialise control structure
  276.  */
  277. void init_usart_ctl(struct usart_ctl *instance, UART_HandleTypeDef *handle,
  278.                                    volatile uint8_t * tx_buffer,
  279.                                                    volatile uint8_t * rx_buffer,
  280.                                                    uint16_t tx_buffer_size,
  281.                                                    uint16_t rx_buffer_size)
  282. {
  283.  
  284.   instance->Handle = handle;
  285.   instance->tx_usart_buff = tx_buffer;
  286.   instance->rx_usart_buff = rx_buffer;
  287.   instance->tx_usart_buff_size = tx_buffer_size;
  288.   instance->rx_usart_buff_size = rx_buffer_size;
  289.  
  290.   /* cheat here - this is a macro and I have the same Instance member as the HAL handle, with the same meaning */
  291.   __HAL_UART_DISABLE_IT(instance->Handle, UART_IT_TXE);
  292.   __HAL_UART_DISABLE_IT(instance->Handle, UART_IT_RXNE);
  293.  
  294.   FlushSerial(instance);
  295. }
  296.  
  297. void setBaud(struct usart_ctl *ctl, uint32_t baud)
  298. {
  299.   ctl->Handle->Init.BaudRate = baud;
  300.   __disable_irq();
  301.   HAL_UART_Init(ctl->Handle);
  302.   __enable_irq();
  303. }
  304.  
  305.