Subversion Repositories libSerial

Rev

Rev 4 | Rev 6 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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