Subversion Repositories libSerial

Rev

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