23
23
#include "uart_regs.h"
24
24
#include "pwrman_regs.h"
25
25
#include "uart.h"
26
+ #include "circ_buf.h"
26
27
27
28
// Size must be 2^n
28
- #define BUFFER_SIZE (4096)
29
-
30
- #define UART_ERRORS (MXC_F_UART_INTFL_RX_FRAMING_ERR | \
31
- MXC_F_UART_INTFL_RX_PARITY_ERR | \
32
- MXC_F_UART_INTFL_RX_FIFO_OVERFLOW)
33
-
29
+ #define BUFFER_SIZE (4096)
34
30
35
31
// Track bit rate to avoid calculation from bus clock, clock scaler and baud divisor values
36
32
static uint32_t baudrate ;
@@ -39,24 +35,91 @@ static mxc_uart_regs_t *CdcAcmUart = NULL;
39
35
static mxc_uart_fifo_regs_t * CdcAcmUartFifo = NULL ;
40
36
static IRQn_Type CdcAcmUartIrqNumber = MXC_IRQ_EXT_COUNT ;
41
37
42
- static struct {
43
- uint8_t data [BUFFER_SIZE ];
44
- volatile uint16_t idx_in ;
45
- volatile uint16_t idx_out ;
46
- volatile int16_t cnt_in ;
47
- volatile int16_t cnt_out ;
48
- } write_buffer , read_buffer ;
38
+ circ_buf_t write_buffer ;
39
+ uint8_t write_buffer_data [BUFFER_SIZE ];
40
+ circ_buf_t read_buffer ;
41
+ uint8_t read_buffer_data [BUFFER_SIZE ];
49
42
50
43
/******************************************************************************/
51
- static void set_bitrate (uint32_t bps )
44
+ static void set_bitrate (uint32_t target_baud )
52
45
{
53
- uint32_t baud_divisor ;
46
+ uint32_t clk_scale ;
47
+ uint32_t min_baud ;
48
+ uint32_t uart_clk ;
49
+ uint16_t baud_shift ;
50
+ uint16_t baud_div ;
51
+ uint32_t baud , diff_baud ;
52
+ uint32_t baud_1 , diff_baud_1 ;
53
+
54
+ // Setup system clock divider for given bit rate
55
+ clk_scale = 0 ;
56
+ do {
57
+ min_baud = (SystemCoreClock >> clk_scale ++ ) / (16 * (MXC_F_UART_BAUD_BAUD_DIVISOR >> MXC_F_UART_BAUD_BAUD_DIVISOR_POS ));
58
+ } while ((target_baud < min_baud ) && (clk_scale < MXC_V_CLKMAN_CLK_SCALE_DIV_256 ));
59
+
60
+ // Check if the bit rate can be reached
61
+ if (target_baud < min_baud ) {
62
+ // Fail silently
63
+ return ;
64
+ }
65
+
66
+ if (MXC_CLKMAN -> sys_clk_ctrl_8_uart != clk_scale ) {
67
+ MXC_CLKMAN -> sys_clk_ctrl_8_uart = clk_scale ;
68
+ }
69
+
70
+ uart_clk = SystemCoreClock >> (clk_scale - 1 );
71
+
72
+ baud_shift = 2 ;
73
+ baud_div = uart_clk / (target_baud * 4 );
74
+
75
+ // Bitrate too high
76
+ if (baud_div == 0 ) {
77
+ // Fail silently
78
+ return ;
79
+ }
80
+
81
+ // Decrease the divisor if baud_div is overflowing
82
+ while (baud_div > 0x00FF ) {
83
+ if (baud_shift == 0 ) {
84
+ // Fail silently
85
+ return ;
86
+ }
87
+ baud_shift -- ;
88
+ baud_div = uart_clk / (target_baud * (16 >> baud_shift ));
89
+ }
90
+
91
+ // Adjust baud_div to avoid overflow in the calculations below
92
+ if (baud_div == 0x00FF ) {
93
+ baud_div = 0x00FE ;
94
+ }
95
+
96
+ if (baud_div == 0x0000 ) {
97
+ baud_div = 0x0001 ;
98
+ }
99
+
100
+ // Determine if truncation increases the error
101
+ baud = uart_clk / (baud_div * (16 >> baud_shift ));
102
+ baud_1 = uart_clk / ((baud_div + 1 ) * (16 >> baud_shift ));
103
+
104
+ if (target_baud > baud ) {
105
+ diff_baud = target_baud - baud ;
106
+ } else {
107
+ diff_baud = baud - target_baud ;
108
+ }
109
+
110
+ if (target_baud > baud_1 ) {
111
+ diff_baud_1 = target_baud - baud_1 ;
112
+ } else {
113
+ diff_baud_1 = baud_1 - target_baud ;
114
+ }
54
115
55
- baud_divisor = SystemCoreClock / (1 << (MXC_CLKMAN -> sys_clk_ctrl_8_uart - 1 ));
56
- baud_divisor /= (bps * 16 );
57
- CdcAcmUart -> baud = baud_divisor ;
116
+ if (diff_baud < diff_baud_1 ) {
117
+ CdcAcmUart -> baud = (baud_div & MXC_F_UART_BAUD_BAUD_DIVISOR ) | (baud_shift << MXC_F_UART_BAUD_BAUD_MODE_POS );
118
+ } else {
119
+ CdcAcmUart -> baud = ((baud_div + 1 ) & MXC_F_UART_BAUD_BAUD_DIVISOR ) | (baud_shift << MXC_F_UART_BAUD_BAUD_MODE_POS );
120
+ }
58
121
59
- baudrate = bps ;
122
+ baudrate = target_baud ;
60
123
}
61
124
62
125
/******************************************************************************/
@@ -81,21 +144,18 @@ int32_t uart_initialize(void)
81
144
{
82
145
int idx ;
83
146
147
+ /* Do not enable UART Common Clock here, must happen inside uart_set_configuration()
148
+ to ensure correct clock scale for a given baud rate */
149
+
84
150
if (CdcAcmUart == MXC_UART0 ) {
85
151
MXC_CLKMAN -> clk_gate_ctrl1 |= MXC_F_CLKMAN_CLK_GATE_CTRL1_UART0_CLK_GATER ;
86
- if (MXC_CLKMAN -> sys_clk_ctrl_8_uart != MXC_S_CLKMAN_CLK_SCALE_DIV_4 ) {
87
- MXC_CLKMAN -> sys_clk_ctrl_8_uart = MXC_S_CLKMAN_CLK_SCALE_DIV_4 ;
88
- }
89
152
90
153
// Configure GPIO for UART
91
154
MXC_IOMAN -> uart0_req = ((MXC_V_IOMAN_MAP_A << MXC_F_IOMAN_UART0_REQ_IO_MAP_POS ) | MXC_F_IOMAN_UART0_REQ_IO_REQ );
92
155
while (MXC_IOMAN -> uart0_ack != ((MXC_V_IOMAN_MAP_A << MXC_F_IOMAN_UART0_REQ_IO_MAP_POS ) | MXC_F_IOMAN_UART0_REQ_IO_REQ ));
93
156
94
157
} else if (CdcAcmUart == MXC_UART2 ) {
95
158
MXC_CLKMAN -> clk_gate_ctrl1 |= MXC_F_CLKMAN_CLK_GATE_CTRL1_UART2_CLK_GATER ;
96
- if (MXC_CLKMAN -> sys_clk_ctrl_8_uart != MXC_S_CLKMAN_CLK_SCALE_DIV_4 ) {
97
- MXC_CLKMAN -> sys_clk_ctrl_8_uart = MXC_S_CLKMAN_CLK_SCALE_DIV_4 ;
98
- }
99
159
100
160
// Configure GPIO for UART
101
161
MXC_IOMAN -> uart2_req = ((MXC_V_IOMAN_MAP_A << MXC_F_IOMAN_UART2_REQ_IO_MAP_POS ) | MXC_F_IOMAN_UART2_REQ_IO_REQ );
@@ -132,11 +192,14 @@ int32_t uart_initialize(void)
132
192
CdcAcmUart -> tx_fifo_ctrl |= (MXC_UART_FIFO_DEPTH - (MXC_UART_FIFO_DEPTH >> 2 )) << MXC_F_UART_TX_FIFO_CTRL_FIFO_AE_LVL_POS ;
133
193
134
194
// Enable RX and TX interrupts
135
- CdcAcmUart -> inten = (MXC_F_UART_INTEN_RX_FIFO_NOT_EMPTY | MXC_F_UART_INTFL_RX_FIFO_OVERFLOW | MXC_F_UART_INTEN_TX_FIFO_AE );
195
+ CdcAcmUart -> inten = (MXC_F_UART_INTEN_RX_FIFO_NOT_EMPTY | MXC_F_UART_INTEN_RX_FIFO_OVERFLOW | MXC_F_UART_INTEN_TX_FIFO_AE );
136
196
137
197
// Enable UART
138
198
CdcAcmUart -> ctrl |= MXC_F_UART_CTRL_UART_EN ;
139
199
200
+ circ_buf_init (& write_buffer , write_buffer_data , sizeof (write_buffer_data ));
201
+ circ_buf_init (& read_buffer , read_buffer_data , sizeof (read_buffer_data ));
202
+
140
203
return 1 ;
141
204
}
142
205
@@ -151,8 +214,8 @@ int32_t uart_uninitialize(void)
151
214
NVIC_DisableIRQ (CdcAcmUartIrqNumber );
152
215
153
216
// Clear buffers
154
- memset (& write_buffer , 0 , sizeof (write_buffer ));
155
- memset (& read_buffer , 0 , sizeof (read_buffer ));
217
+ memset (& write_buffer_data , 0 , sizeof (write_buffer_data ));
218
+ memset (& read_buffer_data , 0 , sizeof (read_buffer_data ));
156
219
157
220
return 1 ;
158
221
}
@@ -165,9 +228,8 @@ void uart_set_control_line_state(uint16_t ctrl_bmp)
165
228
/******************************************************************************/
166
229
int32_t uart_reset (void )
167
230
{
168
- // Clear buffers
169
- memset (& write_buffer , 0 , sizeof (write_buffer ));
170
- memset (& read_buffer , 0 , sizeof (read_buffer ));
231
+ circ_buf_init (& write_buffer , write_buffer_data , sizeof (write_buffer_data ));
232
+ circ_buf_init (& read_buffer , read_buffer_data , sizeof (read_buffer_data ));
171
233
172
234
return 1 ;
173
235
}
@@ -177,14 +239,11 @@ int32_t uart_set_configuration(UART_Configuration *config)
177
239
{
178
240
uint32_t ctrl ;
179
241
180
- // Get current configuration; clearing parameters that may be configured here
181
- ctrl = CdcAcmUart -> ctrl & ~(MXC_F_UART_CTRL_PARITY |
182
- MXC_F_UART_CTRL_DATA_SIZE |
183
- MXC_F_UART_CTRL_EXTRA_STOP |
184
- MXC_F_UART_CTRL_CTS_EN |
185
- MXC_F_UART_CTRL_RTS_EN );
242
+ // Disable UART, clear FIFOs and configuration
243
+ CdcAcmUart -> ctrl = 0 ;
186
244
187
245
switch (config -> Parity ) {
246
+ default :
188
247
case UART_PARITY_NONE : break ;
189
248
case UART_PARITY_ODD : ctrl |= MXC_S_UART_CTRL_PARITY_ODD ;
190
249
case UART_PARITY_EVEN : ctrl |= MXC_S_UART_CTRL_PARITY_EVEN ;
@@ -196,26 +255,30 @@ int32_t uart_set_configuration(UART_Configuration *config)
196
255
case UART_DATA_BITS_5 : ctrl |= MXC_S_UART_CTRL_DATA_SIZE_5_BITS ; break ;
197
256
case UART_DATA_BITS_6 : ctrl |= MXC_S_UART_CTRL_DATA_SIZE_6_BITS ; break ;
198
257
case UART_DATA_BITS_7 : ctrl |= MXC_S_UART_CTRL_DATA_SIZE_7_BITS ; break ;
258
+ default :
199
259
case UART_DATA_BITS_8 : ctrl |= MXC_S_UART_CTRL_DATA_SIZE_8_BITS ; break ;
200
260
case UART_DATA_BITS_16 : return 0 ;
201
261
}
202
262
203
263
switch (config -> StopBits ) {
264
+ default :
204
265
case UART_STOP_BITS_1 : break ;
205
266
case UART_STOP_BITS_1_5 :
206
267
case UART_STOP_BITS_2 : ctrl |= MXC_F_UART_CTRL_EXTRA_STOP ; break ;
207
268
}
208
269
209
270
switch (config -> FlowControl ) {
271
+ default :
210
272
case UART_FLOW_CONTROL_NONE : break ;
211
273
case UART_FLOW_CONTROL_RTS_CTS : return 0 ;
212
274
case UART_FLOW_CONTROL_XON_XOFF : return 0 ;
213
275
}
214
276
215
277
set_bitrate (config -> Baudrate );
216
278
217
- // Set the new configuration
279
+ // Set the new configuration, enable FIFOs and UART
218
280
CdcAcmUart -> ctrl = ctrl ;
281
+ CdcAcmUart -> ctrl |= MXC_F_UART_CTRL_RX_FIFO_EN | MXC_F_UART_CTRL_TX_FIFO_EN | MXC_F_UART_CTRL_UART_EN ;
219
282
220
283
return 1 ;
221
284
}
@@ -265,56 +328,35 @@ int32_t uart_get_configuration(UART_Configuration *config)
265
328
/******************************************************************************/
266
329
int32_t uart_write_free (void )
267
330
{
268
- return BUFFER_SIZE - ( write_buffer . cnt_in - write_buffer . cnt_out );
331
+ return circ_buf_count_free ( & write_buffer );
269
332
}
270
333
271
334
/******************************************************************************/
272
335
int32_t uart_write_data (uint8_t * data , uint16_t size )
273
336
{
274
337
uint16_t xfer_count = size ;
275
338
276
- if (write_buffer .cnt_in == write_buffer .cnt_out ) {
339
+ // Prioritize writes to TX FIFO, then to write_buffer
340
+ if (circ_buf_count_used (& write_buffer ) == 0 ) {
277
341
while ((((CdcAcmUart -> tx_fifo_ctrl & MXC_F_UART_TX_FIFO_CTRL_FIFO_ENTRY ) >> MXC_F_UART_TX_FIFO_CTRL_FIFO_ENTRY_POS ) < MXC_UART_FIFO_DEPTH ) &&
278
342
(xfer_count > 0 )) {
279
-
280
343
NVIC_DisableIRQ (CdcAcmUartIrqNumber );
281
344
CdcAcmUart -> intfl = MXC_F_UART_INTFL_TX_FIFO_AE ;
282
345
CdcAcmUartFifo -> tx = * data ++ ;
283
346
xfer_count -- ;
284
347
NVIC_EnableIRQ (CdcAcmUartIrqNumber );
285
-
286
348
}
287
349
}
288
350
289
- while (xfer_count > 0 ) {
290
- if ((write_buffer .cnt_in - write_buffer .cnt_out ) < BUFFER_SIZE ) {
351
+ xfer_count = circ_buf_write (& write_buffer , data , xfer_count );
291
352
292
- NVIC_DisableIRQ (CdcAcmUartIrqNumber );
293
- write_buffer .data [write_buffer .idx_in ++ ] = * data ++ ;
294
- write_buffer .idx_in &= (BUFFER_SIZE - 1 );
295
- write_buffer .cnt_in ++ ;
296
- xfer_count -- ;
297
- NVIC_EnableIRQ (CdcAcmUartIrqNumber );
298
-
299
- } else {
300
- break ;
301
- }
302
- }
303
353
return size - xfer_count ;
304
354
}
305
355
306
356
/******************************************************************************/
307
357
int32_t uart_read_data (uint8_t * data , uint16_t size )
308
358
{
309
- int32_t cnt ;
310
-
311
- for (cnt = 0 ; (cnt < size ) && (read_buffer .cnt_in != read_buffer .cnt_out ); cnt ++ ) {
312
- * data ++ = read_buffer .data [read_buffer .idx_out ++ ];
313
- read_buffer .idx_out &= (BUFFER_SIZE - 1 );
314
- read_buffer .cnt_out ++ ;
315
- }
316
-
317
- return cnt ;
359
+ return circ_buf_read (& read_buffer , data , size );
318
360
}
319
361
320
362
/******************************************************************************/
@@ -326,23 +368,16 @@ void UART_IRQHandler(void)
326
368
CdcAcmUart -> intfl = intfl ;
327
369
328
370
if (intfl & MXC_F_UART_INTFL_RX_FIFO_OVERFLOW ) {
329
- read_buffer . data [ read_buffer . idx_in ++ ] = '*' ;
330
- read_buffer . idx_in &= ( BUFFER_SIZE - 1 ) ;
331
- read_buffer . cnt_in ++ ;
371
+ // Flush RX FIFO, prepare for new characters
372
+ CdcAcmUart -> ctrl &= ~ MXC_F_UART_CTRL_RX_FIFO_EN ;
373
+ CdcAcmUart -> ctrl |= MXC_F_UART_CTRL_RX_FIFO_EN ;
332
374
}
333
375
334
- if (intfl & ( MXC_F_UART_INTFL_RX_FIFO_NOT_EMPTY | UART_ERRORS ) ) {
376
+ if (intfl & MXC_F_UART_INTFL_RX_FIFO_NOT_EMPTY ) {
335
377
while ((CdcAcmUart -> rx_fifo_ctrl & MXC_F_UART_RX_FIFO_CTRL_FIFO_ENTRY ) &&
336
- (( read_buffer . cnt_in - read_buffer . cnt_out ) < BUFFER_SIZE )) {
337
- read_buffer . data [ read_buffer . idx_in ++ ] = CdcAcmUartFifo -> rx ;
378
+ circ_buf_count_free ( & read_buffer )) {
379
+ circ_buf_push ( & read_buffer , CdcAcmUartFifo -> rx ) ;
338
380
CdcAcmUart -> intfl = MXC_F_UART_INTFL_RX_FIFO_NOT_EMPTY ;
339
- read_buffer .idx_in &= (BUFFER_SIZE - 1 );
340
- read_buffer .cnt_in ++ ;
341
- }
342
- if (((read_buffer .cnt_in - read_buffer .cnt_out ) >= BUFFER_SIZE )) {
343
- read_buffer .data [read_buffer .idx_in ++ ] = '%' ;
344
- read_buffer .idx_in &= (BUFFER_SIZE - 1 );
345
- read_buffer .cnt_in ++ ;
346
381
}
347
382
}
348
383
@@ -352,11 +387,9 @@ void UART_IRQHandler(void)
352
387
a) write buffer contains data and
353
388
b) transmit FIFO is not full
354
389
*/
355
- while (( write_buffer . cnt_out != write_buffer . cnt_in ) &&
390
+ while (circ_buf_count_used ( & write_buffer ) &&
356
391
(((CdcAcmUart -> tx_fifo_ctrl & MXC_F_UART_TX_FIFO_CTRL_FIFO_ENTRY ) >> MXC_F_UART_TX_FIFO_CTRL_FIFO_ENTRY_POS ) < MXC_UART_FIFO_DEPTH )) {
357
- CdcAcmUartFifo -> tx = write_buffer .data [write_buffer .idx_out ++ ];
358
- write_buffer .idx_out &= (BUFFER_SIZE - 1 );
359
- write_buffer .cnt_out ++ ;
392
+ CdcAcmUartFifo -> tx = circ_buf_pop (& write_buffer );
360
393
}
361
394
}
362
395
}
0 commit comments