Subversion Repositories libSerial

Rev

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