Subversion Repositories libSerial

Rev

Rev 8 | 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
9 mjames 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
 *
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
9 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
{
8 mjames 61
  return TX_USART_BUFF_SIZ - instance->tx_usart_count;
7 mjames 62
}
63
 
2 mjames 64
inline uint8_t
8 mjames 65
PollSerial(usart_ctl *instance)
2 mjames 66
{
67
  uint8_t rc;
8 mjames 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);
2 mjames 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
 */
3 mjames 79
inline uint8_t
8 mjames 80
GetCharSerial(usart_ctl *instance)
2 mjames 81
{
82
  uint8_t c;
8 mjames 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
  }
2 mjames 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)
8 mjames 95
  {
96
    instance->rx_usart_out_Ptr = 0;
97
  }
98
  __HAL_UART_ENABLE_IT(instance->Handle, UART_IT_RXNE);
2 mjames 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
8 mjames 108
EnableSerialRxInterrupt(usart_ctl *instance)
2 mjames 109
{
110
  /* cheat here - this is a macro and I have the same Instance member as the HAL handle, with the same meaning */
8 mjames 111
  __HAL_UART_ENABLE_IT(instance->Handle, UART_IT_RXNE);
2 mjames 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
8 mjames 120
PutCharSerialFIFO(usart_ctl *instance, uint8_t c)
2 mjames 121
{
8 mjames 122
  __HAL_UART_DISABLE_IT(instance->Handle, UART_IT_TXE);
2 mjames 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)
8 mjames 127
  {
128
    instance->tx_usart_in_Ptr = 0;
129
  }
2 mjames 130
  /* Handle overrun by losing oldest characters */
131
  if (instance->tx_usart_in_Ptr == instance->tx_usart_out_Ptr)
8 mjames 132
  {
133
    instance->tx_usart_out_Ptr++;
134
    if (instance->tx_usart_out_Ptr >= TX_USART_BUFF_SIZ)
2 mjames 135
    {
8 mjames 136
      instance->tx_usart_out_Ptr = 0;
2 mjames 137
    }
8 mjames 138
  }
2 mjames 139
 
140
  instance->tx_usart_running = 1;
8 mjames 141
  __HAL_UART_ENABLE_IT(instance->Handle, UART_IT_TXE);
2 mjames 142
}
143
 
8 mjames 144
void UART_IRQHandler(usart_ctl *instance)
2 mjames 145
{
146
 
8 mjames 147
  __disable_irq();
148
  uint32_t rxStatus; // status from USART receiver
2 mjames 149
 
8 mjames 150
  rxStatus = instance->Handle->Instance->SR; // read the status bits - this resets all the hardware signalling flags
2 mjames 151
 
6 mjames 152
  if ((rxStatus & USART_SR_LBD))
8 mjames 153
    __HAL_UART_CLEAR_FLAG(instance->Handle, USART_SR_LBD);
6 mjames 154
 
8 mjames 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)
2 mjames 161
    {
8 mjames 162
      instance->rx_usart_buff[instance->rx_usart_in_Ptr++] = rxChar;
2 mjames 163
 
8 mjames 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
      }
2 mjames 172
    }
8 mjames 173
  }
2 mjames 174
  /* check for transmitter interrupt : this code is used */
6 mjames 175
  if ((rxStatus & USART_SR_TXE) != RESET)
8 mjames 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)
2 mjames 182
    {
183
 
8 mjames 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;
6 mjames 188
 
8 mjames 189
      if (instance->tx_usart_out_Ptr >= TX_USART_BUFF_SIZ)
190
      {
191
        instance->tx_usart_out_Ptr = 0;
192
      }
2 mjames 193
    }
8 mjames 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();
2 mjames 201
}
202
 
8 mjames 203
void PutCharSerial(usart_ctl *instance, uint8_t c)
2 mjames 204
{
205
  // Put character in Crayon/Pen interface
8 mjames 206
  PutCharSerialFIFO(instance, c);
2 mjames 207
}
208
 
209
/*
210
 * \brief
211
 * ResetTxBuffer(void) - resets the serial transmitter buffer
212
 */
8 mjames 213
void ResetTxBuffer(usart_ctl *instance)
2 mjames 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
 */
8 mjames 226
void ResetRxBuffer(usart_ctl *instance)
2 mjames 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
 */
8 mjames 237
void FlushSerial(usart_ctl *instance)
2 mjames 238
{
8 mjames 239
  ResetRxBuffer(instance);
240
  ResetTxBuffer(instance);
2 mjames 241
}
242
 
243
/***!
244
 * @brief check if tx buffer is empty...
245
 */
246
uint8_t
8 mjames 247
TxBufferEmpty(usart_ctl *instance)
2 mjames 248
{
8 mjames 249
  return (0 == instance->tx_usart_count);
2 mjames 250
}
251
 
4 mjames 252
/***!
253
 * @brief wait for transmission to finish
254
 */
255
 
256
void TxWaitEmpty(usart_ctl *instance)
257
{
258
  while (instance->tx_usart_count ||
8 mjames 259
         (instance->Handle->Instance->SR & USART_SR_TC) != RESET)
260
  {
261
  };
4 mjames 262
}
263
 
2 mjames 264
/****
265
 * @brief Initialise control structure
266
 */
8 mjames 267
void init_usart_ctl(usart_ctl *instance, UART_HandleTypeDef *handle)
2 mjames 268
{
269
 
5 mjames 270
  instance->Handle = handle;
4 mjames 271
 
272
  /* cheat here - this is a macro and I have the same Instance member as the HAL handle, with the same meaning */
8 mjames 273
  __HAL_UART_DISABLE_IT(instance->Handle, UART_IT_TXE);
274
  __HAL_UART_DISABLE_IT(instance->Handle, UART_IT_RXNE);
4 mjames 275
 
2 mjames 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
 
8 mjames 286
void setBaud(usart_ctl *ctl, uint32_t baud)
5 mjames 287
{
288
  ctl->Handle->Init.BaudRate = baud;
8 mjames 289
  __disable_irq();
290
  HAL_UART_Init(ctl->Handle);
291
  __enable_irq();
5 mjames 292
}
293
 
8 mjames 294
 
295
 
296
void sendString(usart_ctl *ctl, char const * string , int length)
7 mjames 297
{
8 mjames 298
  for (int i = 0; i < length; i++)
7 mjames 299
    PutCharSerial(ctl, string[i]);
300
}
5 mjames 301
 
2 mjames 302
/////////////////////////////////////////////////////////
303
/// Moved from generated code  to avoid crappy HAL handler
304
#if defined SERIAL_UART1
305
void USART1_IRQHandler(void)
306
{
8 mjames 307
  UART_IRQHandler(&uc1);
2 mjames 308
}
309
#endif
310
#if defined SERIAL_UART2
311
void USART2_IRQHandler(void)
312
{
8 mjames 313
  UART_IRQHandler(&uc2);
2 mjames 314
}
315
#endif
316
#if defined SERIAL_UART3
317
void USART3_IRQHandler(void)
318
{
8 mjames 319
  UART_IRQHandler(&uc3);
2 mjames 320
}
321
#endif
7 mjames 322
#if defined SERIAL_UART4
323
void UART4_IRQHandler(void)
324
{
8 mjames 325
  UART_IRQHandler(&uc4);
7 mjames 326
}
327
#endif
328
#if defined SERIAL_UART5
329
void UART5_IRQHandler(void)
330
{
8 mjames 331
  UART_IRQHandler(&uc5);
7 mjames 332
}
333
#endif