Subversion Repositories libSerial

Rev

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