Subversion Repositories libSerial

Rev

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