Subversion Repositories libSerial

Rev

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