Skip to content

Commit 0052c4b

Browse files
authored
Merge pull request #735 from maximmbed/uart-rework
Rework UART implementation for MAX32625 HIC
2 parents b8b98b0 + fe7f177 commit 0052c4b

File tree

1 file changed

+114
-81
lines changed
  • source/hic_hal/maxim/max32625

1 file changed

+114
-81
lines changed

source/hic_hal/maxim/max32625/uart.c

Lines changed: 114 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,10 @@
2323
#include "uart_regs.h"
2424
#include "pwrman_regs.h"
2525
#include "uart.h"
26+
#include "circ_buf.h"
2627

2728
// 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)
3430

3531
// Track bit rate to avoid calculation from bus clock, clock scaler and baud divisor values
3632
static uint32_t baudrate;
@@ -39,24 +35,91 @@ static mxc_uart_regs_t *CdcAcmUart = NULL;
3935
static mxc_uart_fifo_regs_t *CdcAcmUartFifo = NULL;
4036
static IRQn_Type CdcAcmUartIrqNumber = MXC_IRQ_EXT_COUNT;
4137

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];
4942

5043
/******************************************************************************/
51-
static void set_bitrate(uint32_t bps)
44+
static void set_bitrate(uint32_t target_baud)
5245
{
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+
}
54115

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+
}
58121

59-
baudrate = bps;
122+
baudrate = target_baud;
60123
}
61124

62125
/******************************************************************************/
@@ -81,21 +144,18 @@ int32_t uart_initialize(void)
81144
{
82145
int idx;
83146

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+
84150
if (CdcAcmUart == MXC_UART0) {
85151
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-
}
89152

90153
// Configure GPIO for UART
91154
MXC_IOMAN->uart0_req = ((MXC_V_IOMAN_MAP_A << MXC_F_IOMAN_UART0_REQ_IO_MAP_POS) | MXC_F_IOMAN_UART0_REQ_IO_REQ);
92155
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));
93156

94157
} else if (CdcAcmUart == MXC_UART2) {
95158
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-
}
99159

100160
// Configure GPIO for UART
101161
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)
132192
CdcAcmUart->tx_fifo_ctrl |= (MXC_UART_FIFO_DEPTH - (MXC_UART_FIFO_DEPTH >> 2)) << MXC_F_UART_TX_FIFO_CTRL_FIFO_AE_LVL_POS;
133193

134194
// 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);
136196

137197
// Enable UART
138198
CdcAcmUart->ctrl |= MXC_F_UART_CTRL_UART_EN;
139199

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+
140203
return 1;
141204
}
142205

@@ -151,8 +214,8 @@ int32_t uart_uninitialize(void)
151214
NVIC_DisableIRQ(CdcAcmUartIrqNumber);
152215

153216
// 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));
156219

157220
return 1;
158221
}
@@ -165,9 +228,8 @@ void uart_set_control_line_state(uint16_t ctrl_bmp)
165228
/******************************************************************************/
166229
int32_t uart_reset(void)
167230
{
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));
171233

172234
return 1;
173235
}
@@ -177,14 +239,11 @@ int32_t uart_set_configuration(UART_Configuration *config)
177239
{
178240
uint32_t ctrl;
179241

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;
186244

187245
switch (config->Parity) {
246+
default:
188247
case UART_PARITY_NONE: break;
189248
case UART_PARITY_ODD: ctrl |= MXC_S_UART_CTRL_PARITY_ODD;
190249
case UART_PARITY_EVEN: ctrl |= MXC_S_UART_CTRL_PARITY_EVEN;
@@ -196,26 +255,30 @@ int32_t uart_set_configuration(UART_Configuration *config)
196255
case UART_DATA_BITS_5: ctrl |= MXC_S_UART_CTRL_DATA_SIZE_5_BITS; break;
197256
case UART_DATA_BITS_6: ctrl |= MXC_S_UART_CTRL_DATA_SIZE_6_BITS; break;
198257
case UART_DATA_BITS_7: ctrl |= MXC_S_UART_CTRL_DATA_SIZE_7_BITS; break;
258+
default:
199259
case UART_DATA_BITS_8: ctrl |= MXC_S_UART_CTRL_DATA_SIZE_8_BITS; break;
200260
case UART_DATA_BITS_16: return 0;
201261
}
202262

203263
switch (config->StopBits) {
264+
default:
204265
case UART_STOP_BITS_1: break;
205266
case UART_STOP_BITS_1_5:
206267
case UART_STOP_BITS_2: ctrl |= MXC_F_UART_CTRL_EXTRA_STOP; break;
207268
}
208269

209270
switch (config->FlowControl) {
271+
default:
210272
case UART_FLOW_CONTROL_NONE: break;
211273
case UART_FLOW_CONTROL_RTS_CTS: return 0;
212274
case UART_FLOW_CONTROL_XON_XOFF: return 0;
213275
}
214276

215277
set_bitrate(config->Baudrate);
216278

217-
// Set the new configuration
279+
// Set the new configuration, enable FIFOs and UART
218280
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;
219282

220283
return 1;
221284
}
@@ -265,56 +328,35 @@ int32_t uart_get_configuration(UART_Configuration *config)
265328
/******************************************************************************/
266329
int32_t uart_write_free(void)
267330
{
268-
return BUFFER_SIZE - (write_buffer.cnt_in - write_buffer.cnt_out);
331+
return circ_buf_count_free(&write_buffer);
269332
}
270333

271334
/******************************************************************************/
272335
int32_t uart_write_data(uint8_t *data, uint16_t size)
273336
{
274337
uint16_t xfer_count = size;
275338

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) {
277341
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) &&
278342
(xfer_count > 0)) {
279-
280343
NVIC_DisableIRQ(CdcAcmUartIrqNumber);
281344
CdcAcmUart->intfl = MXC_F_UART_INTFL_TX_FIFO_AE;
282345
CdcAcmUartFifo->tx = *data++;
283346
xfer_count--;
284347
NVIC_EnableIRQ(CdcAcmUartIrqNumber);
285-
286348
}
287349
}
288350

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);
291352

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-
}
303353
return size - xfer_count;
304354
}
305355

306356
/******************************************************************************/
307357
int32_t uart_read_data(uint8_t *data, uint16_t size)
308358
{
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);
318360
}
319361

320362
/******************************************************************************/
@@ -326,23 +368,16 @@ void UART_IRQHandler(void)
326368
CdcAcmUart->intfl = intfl;
327369

328370
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;
332374
}
333375

334-
if (intfl & (MXC_F_UART_INTFL_RX_FIFO_NOT_EMPTY | UART_ERRORS)) {
376+
if (intfl & MXC_F_UART_INTFL_RX_FIFO_NOT_EMPTY) {
335377
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);
338380
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++;
346381
}
347382
}
348383

@@ -352,11 +387,9 @@ void UART_IRQHandler(void)
352387
a) write buffer contains data and
353388
b) transmit FIFO is not full
354389
*/
355-
while ((write_buffer.cnt_out != write_buffer.cnt_in) &&
390+
while (circ_buf_count_used(&write_buffer) &&
356391
(((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);
360393
}
361394
}
362395
}

0 commit comments

Comments
 (0)