Subversion Repositories libSerial

Rev

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