Subversion Repositories libSerial

Rev

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