1 /******************************************************************************
2 *
3 * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
4 * Analog Devices, Inc.),
5 * Copyright (C) 2023-2024 Analog Devices, Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 ******************************************************************************/
20
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 #include "spi.h"
26 #include "afe.h"
27 #include "hart_uart.h"
28 #include "mxc_delay.h"
29 #include "mxc_sys.h"
30 #include "mxc_device.h"
31 #include "nvic_table.h"
32
33 #include "afe_gpio.h"
34 #include "afe_timer.h"
35 #include "gpio.h"
36 #include "gpio_reva.h"
37 #include "gpio_common.h"
38 #include "uart.h"
39 #include "uart_revb.h"
40 #include "uart_common.h"
41 #include "mcr_regs.h"
42 #include "dma.h"
43
44 #if (TARGET_NUM == 32680)
45 #include "ptg_regs.h"
46 #include "pt_regs.h"
47 #endif
48
49 // Defines
50 // #define HART_CLK_4MHZ_CHECK
51
52 // 20 Preamble, 1 Delimiter, 5 address, 3 Expansion, 1 Command, 1 Byte Count, 255 Max Data, 1 Check Byte
53 #define HART_UART_MAX_PACKET_LEN 286
54
55 // This is used to guarantee at least 2 bytes in UART transmit FIFO, which are
56 // necessary to trigger the MXC_F_UART_INT_FL_TX_OB interrupt. That is, one
57 // byte left in FIFO, which occurs when FIFO level goes from 2 to 1.
58 // Since first write to FIFO will immediately drop through to shift register
59 // we need 3 bytes.
60 // NOTE: Due to all real HART messages containing at least 5 preambles etc. this
61 // should never be an issues unless caller specifies incorrect length.
62 #define HART_UART_MIN_PACKET_LENGTH 3
63
64 #define HART_UART_FIFO_SIZE 8
65
66 // Only arm the transmission complete callback when FIFO level is this or less
67 #define HART_UART_FIFO_LEVEL_TO_ARM_CALLBACK 1
68
69 // This is used while waiting for the current HART transmission to finish.
70 // The primary timeout is calculated in hart_uart_transmit_irq, but if we
71 // arrive in the callback and transmission is still in progress we will
72 // schedule another callback this many microseconds later to recheck.
73 // Each bit in the 1200 baud transmission is 1/1200 834us.
74 // Currently delaying 2 characters more.
75 #define HART_TRANSMIT_COMPLETE_RETRY_IN_US (834 * 2)
76
77 // Use 128 times oversampling of demodulated HART serial data for optimal bit decoding.
78 #define UART_RX_BIT_OVERSAMPLING_128 0
79
80 // Detect and handle UART Framing, Parity and Overrun Errors
81 #define MXC_UART_ERRINT_EN \
82 (MXC_F_UART_INT_EN_RX_FERR | MXC_F_UART_INT_EN_RX_PAR | MXC_F_UART_INT_EN_RX_OV)
83
84 #define MXC_UART_ERRINT_FL \
85 (MXC_F_UART_INT_FL_RX_FERR | MXC_F_UART_INT_FL_RX_PAR | MXC_F_UART_INT_FL_RX_OV)
86
87 // Enables for the interrupts we care about
88 #define HART_UART_INTERRUPT_ENABLES \
89 ((MXC_F_UART_INT_EN_TX_HE | MXC_F_UART_INT_EN_TX_OB | MXC_F_UART_INT_EN_RX_THD) | \
90 (MXC_UART_ERRINT_EN))
91
92 // Note, this is internally bonded, but is Y bonded to MAX32675 package as well, as pin: 51, aka P1.8
93 #if (TARGET_NUM == 32675)
94 #define HART_UART_INSTANCE MXC_UART2
95
96 #define HART_RTS_GPIO_PORT MXC_GPIO1
97 #define HART_RTS_GPIO_PIN MXC_GPIO_PIN_8
98
99 #define HART_CD_GPIO_PORT MXC_GPIO0
100 #define HART_CD_GPIO_PIN MXC_GPIO_PIN_16
101
102 #define HART_IN_GPIO_PORT MXC_GPIO0
103 #define HART_IN_GPIO_PIN MXC_GPIO_PIN_15
104
105 #define HART_OUT_GPIO_PORT MXC_GPIO0
106 #define HART_OUT_GPIO_PIN MXC_GPIO_PIN_14
107
108 #define HART_CLK_GPIO_PORT MXC_GPIO0
109 #define HART_CLK_GPIO_PIN MXC_GPIO_PIN_10
110
111 #define PCLKDIV_DIV_BY_4 2
112
113 #elif (TARGET_NUM == 32680)
114 #define HART_UART_INSTANCE MXC_UART0
115
116 #define HART_RTS_GPIO_PORT MXC_GPIO0
117 #define HART_RTS_GPIO_PIN MXC_GPIO_PIN_3
118
119 #define HART_CD_GPIO_PORT MXC_GPIO0
120 #define HART_CD_GPIO_PIN MXC_GPIO_PIN_2
121
122 #define HART_IN_GPIO_PORT MXC_GPIO0
123 #define HART_IN_GPIO_PIN MXC_GPIO_PIN_1
124
125 #define HART_OUT_GPIO_PORT MXC_GPIO0
126 #define HART_OUT_GPIO_PIN MXC_GPIO_PIN_0
127
128 #define HART_CLK_GPIO_PORT MXC_GPIO0
129 #define HART_CLK_GPIO_PIN MXC_GPIO_PIN_18
130 #define HART_CLK_GPIO_ALT_FUNC MXC_GPIO_FUNC_ALT1
131
132 #endif
133
134 // Globals
135 volatile uint8_t hart_buf[HART_UART_MAX_PACKET_LEN]; // used for transmit and receive
136 volatile uint32_t hart_uart_reception_len = 0;
137 volatile uint32_t hart_uart_transmission_len = 0;
138 volatile uint32_t hart_uart_transmission_byte_index = 0;
139 volatile uint32_t hart_uart_transmission_complete = 0;
140 volatile int32_t hart_uart_reception_avail = 0;
141 volatile uint32_t hart_receive_active = 0;
142 volatile uint32_t hart_uart_errors = 0;
143
144 /**
145 * Global callback structure
146 */
147 hart_uart_callbacks_t sap_callbacks = { NULL, NULL, NULL, NULL, NULL };
148
149 #if (TARGET_NUM == 32680)
150 mxc_pt_regs_t *pPT0 = MXC_PT0;
151 mxc_ptg_regs_t *pPTG = MXC_PTG;
152 #endif
153
154 #ifdef HART_CLK_4MHZ_CHECK
155 mxc_pt_regs_t *pPT2 = MXC_PT2;
156 #endif
157
158 // Prototypes
159 void hart_cd_isr(void *cbdata);
160 void hart_uart_irq_handler(void);
161
hart_uart_init(mxc_uart_regs_t * uart,unsigned int baud,mxc_uart_clock_t clock)162 static int hart_uart_init(mxc_uart_regs_t *uart, unsigned int baud, mxc_uart_clock_t clock)
163 {
164 int retval = E_NO_ERROR;
165
166 retval = MXC_UART_Shutdown(uart);
167 if (retval) {
168 return retval;
169 }
170
171 switch (clock) {
172 case MXC_UART_EXT_CLK:
173 MXC_AFE_GPIO_Config(&gpio_cfg_extclk);
174 break;
175
176 case MXC_UART_ERTCO_CLK:
177 return E_BAD_PARAM;
178 break;
179
180 case MXC_UART_IBRO_CLK:
181 MXC_SYS_ClockSourceEnable(MXC_SYS_CLOCK_IBRO);
182 break;
183
184 case MXC_UART_ERFO_CLK:
185 MXC_SYS_ClockSourceEnable(MXC_SYS_CLOCK_ERFO);
186 break;
187
188 default:
189 break;
190 }
191
192 switch (MXC_UART_GET_IDX(uart)) {
193 case 0:
194 MXC_AFE_GPIO_Config(&gpio_cfg_uart0);
195 MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_UART0);
196 break;
197
198 case 2:
199 MXC_AFE_GPIO_Config(&gpio_cfg_uart2);
200 MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_UART2);
201 break;
202
203 default:
204 return E_NOT_SUPPORTED;
205 }
206
207 retval = MXC_UART_RevB_Init((mxc_uart_revb_regs_t *)uart, baud, (mxc_uart_revb_clock_t)clock);
208 if (retval != E_NO_ERROR) {
209 return retval;
210 }
211
212 // Set RX threshold to 1 byte
213 retval = MXC_UART_SetRXThreshold(uart, 1);
214 if (retval != E_NO_ERROR) {
215 return retval;
216 }
217
218 // Set Datasize to 8 bits
219 retval = MXC_UART_SetDataSize(uart, 8);
220 if (retval != E_NO_ERROR) {
221 return retval;
222 }
223
224 // HART messages use ODD parity
225 retval = MXC_UART_SetParity(uart, MXC_UART_PARITY_ODD_0);
226 if (retval != E_NO_ERROR) {
227 return retval;
228 }
229
230 retval = MXC_UART_SetStopBits(uart, MXC_UART_STOP_1);
231 if (retval != E_NO_ERROR) {
232 return retval;
233 }
234
235 // IMPORTANT: by default the SDK uart driver uses only 4 samples per bit
236 // This can cause issues for HART as the bit times are not always
237 // perfectly sized at 833.3uS. Up to 15% inaccuracy observed.
238 // Increase oversampling to 128x to improve receiver accuracy
239 uart->osr = UART_RX_BIT_OVERSAMPLING_128;
240
241 // NOTE: RTS is handled by software, so the gpio_cfg_uart2_flow structure in pins_me15.c
242 // only describes the CTS pin.
243 // OCD from HART modem is hooked up to CTS, But CD doesn't function like CTS, So this
244 // is handled by software as well.
245
246 // Clear any flags
247 MXC_UART_ClearFlags(uart, MXC_UART_GetFlags(uart));
248
249 // Enable FIFO threshold exceeded so we can drain it into receive buffer
250 retval = MXC_UART_EnableInt(uart, HART_UART_INTERRUPT_ENABLES);
251 if (retval != E_NO_ERROR) {
252 return retval;
253 }
254
255 // Overwrite default UART IRQ Vector with ours
256 MXC_NVIC_SetVector(MXC_UART_GET_IRQ(MXC_UART_GET_IDX(uart)), hart_uart_irq_handler);
257 NVIC_EnableIRQ(MXC_UART_GET_IRQ(MXC_UART_GET_IDX(uart)));
258
259 return E_NO_ERROR;
260 }
261
setup_rts_pin(void)262 static int setup_rts_pin(void)
263 {
264 int retval = E_NO_ERROR;
265 mxc_gpio_cfg_t hart_rts;
266
267 hart_rts.port = HART_RTS_GPIO_PORT;
268 hart_rts.mask = HART_RTS_GPIO_PIN;
269 hart_rts.pad = MXC_GPIO_PAD_NONE;
270 hart_rts.func = MXC_GPIO_FUNC_OUT;
271 hart_rts.vssel = MXC_GPIO_VSSEL_VDDIOH;
272 hart_rts.drvstr = MXC_GPIO_DRVSTR_0;
273
274 retval = MXC_AFE_GPIO_Config(&hart_rts);
275 if (retval != E_NO_ERROR) {
276 return retval;
277 }
278
279 MXC_GPIO_OutSet(HART_RTS_GPIO_PORT, HART_RTS_GPIO_PIN);
280
281 return retval;
282 }
283
idle_rts_pin(void)284 static int idle_rts_pin(void)
285 {
286 int retval = 0;
287 mxc_gpio_cfg_t hart_rts;
288
289 hart_rts.port = HART_RTS_GPIO_PORT;
290 hart_rts.mask = HART_RTS_GPIO_PIN;
291 hart_rts.pad = MXC_GPIO_PAD_PULL_DOWN;
292 hart_rts.func = MXC_GPIO_FUNC_OUT;
293 hart_rts.vssel = MXC_GPIO_VSSEL_VDDIOH;
294 hart_rts.drvstr = MXC_GPIO_DRVSTR_0;
295
296 retval = MXC_AFE_GPIO_Config(&hart_rts);
297 if (retval != E_NO_ERROR) {
298 return retval;
299 }
300
301 return retval;
302 }
303
setup_cd_pin(void)304 static int setup_cd_pin(void)
305 {
306 int retval = E_NO_ERROR;
307 mxc_gpio_cfg_t hart_cd;
308
309 hart_cd.port = HART_CD_GPIO_PORT;
310 hart_cd.mask = HART_CD_GPIO_PIN;
311 hart_cd.pad = MXC_GPIO_PAD_NONE;
312 hart_cd.func = MXC_GPIO_FUNC_IN;
313 hart_cd.vssel = MXC_GPIO_VSSEL_VDDIOH;
314 hart_cd.drvstr = MXC_GPIO_DRVSTR_0;
315
316 retval = MXC_AFE_GPIO_Config(&hart_cd);
317 if (retval != E_NO_ERROR) {
318 return retval;
319 }
320
321 MXC_GPIO_RegisterCallback(&hart_cd, hart_cd_isr, NULL);
322
323 retval = MXC_GPIO_IntConfig(&hart_cd, MXC_GPIO_INT_BOTH);
324 if (retval != E_NO_ERROR) {
325 return retval;
326 }
327
328 MXC_GPIO_EnableInt(hart_cd.port, hart_cd.mask);
329 NVIC_EnableIRQ(MXC_GPIO_GET_IRQ(MXC_GPIO_GET_IDX(hart_cd.port)));
330
331 return retval;
332 }
333
idle_cd_pin(void)334 static int idle_cd_pin(void)
335 {
336 int retval = E_NO_ERROR;
337 mxc_gpio_cfg_t hart_cd;
338
339 hart_cd.port = HART_CD_GPIO_PORT;
340 hart_cd.mask = HART_CD_GPIO_PIN;
341 hart_cd.pad = MXC_GPIO_PAD_PULL_DOWN;
342 hart_cd.func = MXC_GPIO_FUNC_IN;
343 hart_cd.vssel = MXC_GPIO_VSSEL_VDDIOH;
344 hart_cd.drvstr = MXC_GPIO_DRVSTR_0;
345
346 retval = MXC_AFE_GPIO_Config(&hart_cd);
347 if (retval != E_NO_ERROR) {
348 return retval;
349 }
350
351 return retval;
352 }
353
get_hart_cd_state(void)354 static uint32_t get_hart_cd_state(void)
355 {
356 return MXC_GPIO_InGet(HART_CD_GPIO_PORT, HART_CD_GPIO_PIN);
357 }
358
setup_hart_in_pin(void)359 static int setup_hart_in_pin(void)
360 {
361 int retval = E_NO_ERROR;
362 mxc_gpio_cfg_t hart_in;
363
364 hart_in.port = HART_IN_GPIO_PORT;
365 hart_in.mask = HART_IN_GPIO_PIN;
366 hart_in.pad = MXC_GPIO_PAD_NONE;
367 hart_in.func = MXC_GPIO_FUNC_OUT;
368 hart_in.vssel = MXC_GPIO_VSSEL_VDDIOH;
369 hart_in.drvstr = MXC_GPIO_DRVSTR_0;
370
371 retval = MXC_AFE_GPIO_Config(&hart_in);
372 if (retval != E_NO_ERROR) {
373 return retval;
374 }
375
376 // Clear (0) means 2200 signal
377 MXC_GPIO_OutClr(HART_IN_GPIO_PORT, HART_IN_GPIO_PIN);
378
379 return retval;
380 }
381
idle_hart_in_pin(void)382 static int idle_hart_in_pin(void)
383 {
384 int retval = E_NO_ERROR;
385 mxc_gpio_cfg_t hart_in;
386
387 hart_in.port = HART_IN_GPIO_PORT;
388 hart_in.mask = HART_IN_GPIO_PIN;
389 hart_in.pad = MXC_GPIO_PAD_PULL_DOWN;
390 hart_in.func = MXC_GPIO_FUNC_OUT;
391 hart_in.vssel = MXC_GPIO_VSSEL_VDDIOH;
392 hart_in.drvstr = MXC_GPIO_DRVSTR_0;
393
394 retval = MXC_AFE_GPIO_Config(&hart_in);
395 if (retval != E_NO_ERROR) {
396 return retval;
397 }
398
399 return retval;
400 }
401
setup_hart_out_pin(void)402 static int setup_hart_out_pin(void)
403 {
404 int retval = E_NO_ERROR;
405 mxc_gpio_cfg_t hart_out;
406
407 hart_out.port = HART_OUT_GPIO_PORT;
408 hart_out.mask = HART_OUT_GPIO_PIN;
409 hart_out.pad = MXC_GPIO_PAD_NONE;
410 hart_out.func = MXC_GPIO_FUNC_IN;
411 hart_out.vssel = MXC_GPIO_VSSEL_VDDIOH;
412 hart_out.drvstr = MXC_GPIO_DRVSTR_0;
413
414 retval = MXC_AFE_GPIO_Config(&hart_out);
415 if (retval != E_NO_ERROR) {
416 return retval;
417 }
418
419 return retval;
420 }
421
idle_hart_out_pin(void)422 static int idle_hart_out_pin(void)
423 {
424 int retval = E_NO_ERROR;
425 mxc_gpio_cfg_t hart_out;
426
427 hart_out.port = HART_OUT_GPIO_PORT;
428 hart_out.mask = HART_OUT_GPIO_PIN;
429 hart_out.pad = MXC_GPIO_PAD_PULL_DOWN;
430 hart_out.func = MXC_GPIO_FUNC_OUT;
431 hart_out.vssel = MXC_GPIO_VSSEL_VDDIOH;
432 hart_out.drvstr = MXC_GPIO_DRVSTR_0;
433
434 retval = MXC_AFE_GPIO_Config(&hart_out);
435 if (retval != E_NO_ERROR) {
436 return retval;
437 }
438
439 return retval;
440 }
441
hart_uart_pins_idle_mode(void)442 static int hart_uart_pins_idle_mode(void)
443 {
444 // To avoid floating inputs, when HART is NOT enabled, pull the HART UART pins low
445 // NOTE: this only handles the HART uart pins, not the HART clock output
446 int retval = E_NO_ERROR;
447
448 retval = idle_hart_in_pin();
449
450 if (retval != E_NO_ERROR) {
451 return retval;
452 }
453
454 retval = idle_rts_pin();
455
456 if (retval != E_NO_ERROR) {
457 return retval;
458 }
459
460 retval = idle_cd_pin();
461
462 if (retval != E_NO_ERROR) {
463 return retval;
464 }
465
466 retval = idle_hart_out_pin();
467
468 if (retval != E_NO_ERROR) {
469 return retval;
470 }
471
472 return retval;
473 }
474
hart_uart_pins_external_test_mode_state(void)475 static int hart_uart_pins_external_test_mode_state(void)
476 {
477 int retval = 0;
478 mxc_gpio_cfg_t hart_pin;
479
480 // RTS Input to AFE, LOW is transmit mode, so Pulling Up
481 hart_pin.port = HART_RTS_GPIO_PORT;
482 hart_pin.mask = HART_RTS_GPIO_PIN;
483 hart_pin.pad = MXC_GPIO_PAD_PULL_UP;
484 hart_pin.func = MXC_GPIO_FUNC_IN;
485
486 retval = MXC_AFE_GPIO_Config(&hart_pin);
487 if (retval != E_NO_ERROR) {
488 return retval;
489 }
490
491 // CD output from AFE, Tristate
492 hart_pin.port = HART_CD_GPIO_PORT;
493 hart_pin.mask = HART_CD_GPIO_PIN;
494 hart_pin.pad = MXC_GPIO_PAD_NONE;
495
496 retval = MXC_AFE_GPIO_Config(&hart_pin);
497 if (retval != E_NO_ERROR) {
498 return retval;
499 }
500
501 // IN input to AFE, pulling Up
502 hart_pin.port = HART_IN_GPIO_PORT;
503 hart_pin.mask = HART_IN_GPIO_PIN;
504 hart_pin.pad = MXC_GPIO_PAD_PULL_UP;
505
506 retval = MXC_AFE_GPIO_Config(&hart_pin);
507 if (retval != E_NO_ERROR) {
508 return retval;
509 }
510
511 // IN output from AFE, Tristate
512 hart_pin.port = HART_OUT_GPIO_PORT;
513 hart_pin.mask = HART_OUT_GPIO_PIN;
514 hart_pin.pad = MXC_GPIO_PAD_NONE;
515
516 retval = MXC_AFE_GPIO_Config(&hart_pin);
517 if (retval != E_NO_ERROR) {
518 return retval;
519 }
520
521 return retval;
522 }
523
hart_rts_transmit_mode(void)524 void hart_rts_transmit_mode(void)
525 {
526 MXC_GPIO_OutClr(HART_RTS_GPIO_PORT, HART_RTS_GPIO_PIN);
527 }
528
hart_rts_receive_mode(void)529 void hart_rts_receive_mode(void)
530 {
531 MXC_GPIO_OutSet(HART_RTS_GPIO_PORT, HART_RTS_GPIO_PIN);
532 }
533
hart_sap_enable_request(uint32_t state)534 void hart_sap_enable_request(uint32_t state)
535 {
536 if (state == HART_STATE_TRANSMIT) {
537 hart_rts_transmit_mode();
538 } else {
539 hart_rts_receive_mode();
540 }
541
542 // Call Enable.confirm(state)
543 if (sap_callbacks.enable_confirm_cb) {
544 if (state == HART_STATE_TRANSMIT) {
545 sap_callbacks.enable_confirm_cb(HART_STATE_TRANSMIT);
546 } else {
547 sap_callbacks.enable_confirm_cb(HART_STATE_IDLE);
548 }
549 }
550 }
551
hart_reset_check_and_handle(void)552 int hart_reset_check_and_handle(void)
553 {
554 int retval = E_NO_ERROR;
555 uint32_t read_val = 0;
556 uint32_t masked_read_val = 0;
557
558 // Check to see if HART is still enabled after a reset
559 retval = afe_read_register(MXC_R_AFE_ADC_ZERO_SYS_CTRL, &read_val);
560 if (retval != E_NO_ERROR) {
561 return retval;
562 }
563
564 // MASK off all status bits but HART_EN and ST_DIS
565 masked_read_val = read_val &
566 (MXC_F_AFE_ADC_ZERO_SYS_CTRL_HART_EN | MXC_F_AFE_ADC_ZERO_SYS_CTRL_ST_DIS);
567
568 // If BOTH HART_EN and ST_DIS are set, then a NON-POR reset has occurred.
569 // in this case we need to clear ST_DIS to allow the HART state machine to proceed
570 // normally.
571 if (masked_read_val ==
572 (MXC_F_AFE_ADC_ZERO_SYS_CTRL_HART_EN | MXC_F_AFE_ADC_ZERO_SYS_CTRL_ST_DIS)) {
573 // Both HART_EN and ST_DIS are set. (NON POR reset indicated)
574
575 // Clear State Machine Disable
576 read_val &= ~MXC_F_AFE_ADC_ZERO_SYS_CTRL_ST_DIS;
577
578 retval = afe_write_register(MXC_R_AFE_ADC_ZERO_SYS_CTRL, read_val);
579 if (retval != E_NO_ERROR) {
580 return retval;
581 }
582 } else {
583 // HART_EN or ST_DIS are clear. (Normal, POR behavior)
584 }
585
586 return E_SUCCESS;
587 }
588
589 // TODO(ADI): Consider adding some parameters to this function to specify
590 // clock divider settings. Complicated due to differences in MAX32675 and
591 // MAX32680 divider output methodologies.
hart_clock_enable(void)592 int hart_clock_enable(void)
593 {
594 int retval = E_NO_ERROR;
595
596 #if (TARGET_NUM == 32675)
597
598 // ERFO Crystal is required for the HART device in the AFE
599 retval = MXC_SYS_ClockSourceEnable(MXC_SYS_CLOCK_ERFO);
600
601 if (retval != E_NO_ERROR) {
602 return retval;
603 }
604
605 //
606 // Put clock output pin in correct mode
607 //
608
609 // To avoid any glitches on the clock output first configure the in I/O mode
610 HART_CLK_GPIO_PORT->en0_set = HART_CLK_GPIO_PIN;
611 HART_CLK_GPIO_PORT->out_clr = HART_CLK_GPIO_PIN;
612 HART_CLK_GPIO_PORT->outen_set = HART_CLK_GPIO_PIN;
613
614 // Transition to requested alternate function clearing en0 last
615 HART_CLK_GPIO_PORT->en2_set = HART_CLK_GPIO_PIN;
616 HART_CLK_GPIO_PORT->en1_set = HART_CLK_GPIO_PIN;
617 HART_CLK_GPIO_PORT->en0_clr = HART_CLK_GPIO_PIN;
618
619 // Leave GPIO pad pull down enabled, pulls are overridden in IO and alternate function modes.
620 // But will take over if clock is later disabled.
621 HART_CLK_GPIO_PORT->padctrl0 |= HART_CLK_GPIO_PIN;
622 HART_CLK_GPIO_PORT->ps &= ~HART_CLK_GPIO_PIN;
623
624 // Since we have 16Mhz External RF Oscillator (ERFO)
625 // We need to divide it by 4 to get desired 4Mhz output (DIV_CLK_OUT_CTRL of 2)
626 MXC_GCR->pclkdiv &= ~(MXC_F_GCR_PCLKDIV_DIV_CLK_OUT_CTRL | MXC_F_GCR_PCLKDIV_DIV_CLK_OUT_EN);
627 MXC_GCR->pclkdiv |= ((PCLKDIV_DIV_BY_4 << MXC_F_GCR_PCLKDIV_DIV_CLK_OUT_CTRL_POS) &
628 MXC_F_GCR_PCLKDIV_DIV_CLK_OUT_CTRL);
629 MXC_GCR->pclkdiv |= MXC_F_GCR_PCLKDIV_DIV_CLK_OUT_EN;
630
631 #elif (TARGET_NUM == 32680)
632 MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_PT);
633 MXC_SYS_Reset_Periph(MXC_SYS_RESET1_PT);
634
635 //set clock scale, DIV1
636 MXC_GCR->clkctrl &= ~MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV128;
637 MXC_GCR->clkctrl |= MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV1;
638
639 //disable all PT0
640 pPTG->enable = ~0x01;
641
642 //clear PT0 interrupt flag
643 pPTG->intfl = 0x01;
644
645 //enable ISO before enabling ERFO
646 MXC_GCR->btleldoctrl |= (MXC_F_GCR_BTLELDOCTRL_LDOTXEN | MXC_F_GCR_BTLELDOCTRL_LDORXEN |
647 MXC_F_GCR_BTLELDOCTRL_LDOTXVSEL0 | MXC_F_GCR_BTLELDOCTRL_LDOTXVSEL1 |
648 MXC_F_GCR_BTLELDOCTRL_LDORXVSEL0 | MXC_F_GCR_BTLELDOCTRL_LDORXVSEL1);
649
650 MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_ISO_EN;
651
652 MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_ISO_RDY);
653
654 retval = MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_ISO_RDY);
655 if (retval != E_NO_ERROR) {
656 return retval;
657 }
658
659 retval = MXC_SYS_ClockSourceEnable(MXC_SYS_CLOCK_ERFO);
660 if (retval != E_NO_ERROR) {
661 return retval;
662 }
663
664 //change to ERFO before starting PT.
665 retval = MXC_SYS_Clock_Select(MXC_SYS_CLOCK_ERFO);
666 if (retval != E_NO_ERROR) {
667 return retval;
668 }
669
670 MXC_SYS_SetClockDiv(MXC_SYS_CLOCK_DIV_1);
671
672 MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_PT);
673 MXC_SYS_Reset_Periph(MXC_SYS_RESET1_PT);
674
675 //set clock scale, DIV1
676 MXC_GCR->clkctrl &= ~MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV128;
677 MXC_GCR->clkctrl |= MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV1;
678
679 //disable all PT0
680 pPTG->enable = ~0x01;
681
682 //clear PT0 interrupt flag
683 pPTG->intfl = 0x01;
684
685 //4MHz frequency
686 pPT0->rate_length =
687 ((2 << MXC_F_PT_RATE_LENGTH_RATE_CONTROL_POS) & MXC_F_PT_RATE_LENGTH_RATE_CONTROL) |
688 ((2 << MXC_F_PT_RATE_LENGTH_MODE_POS) & MXC_F_PT_RATE_LENGTH_MODE);
689
690 //50% duty cycle
691 pPT0->train = 1;
692
693 //number of cycles (infinite)
694 pPT0->loop = ((0 << MXC_F_PT_LOOP_COUNT_POS) & MXC_F_PT_LOOP_COUNT) |
695 ((0 << MXC_F_PT_LOOP_DELAY_POS) & MXC_F_PT_LOOP_DELAY);
696
697 retval = MXC_AFE_GPIO_Config(&gpio_cfg_pt0);
698 if (retval != E_NO_ERROR) {
699 return retval;
700 }
701
702 #ifdef HART_CLK_4MHZ_CHECK
703 //4MHz frequency
704 pPT2->rate_length =
705 ((2 << MXC_F_PT_RATE_LENGTH_RATE_CONTROL_POS) & MXC_F_PT_RATE_LENGTH_RATE_CONTROL) |
706 ((2 << MXC_F_PT_RATE_LENGTH_MODE_POS) & MXC_F_PT_RATE_LENGTH_MODE);
707
708 //50% duty cycle
709 pPT2->train = 1;
710
711 //number of cycles (infinite) for PT2 (P0_16)
712 pPT2->loop = ((0 << MXC_F_PT_LOOP_COUNT_POS) & MXC_F_PT_LOOP_COUNT) |
713 ((0 << MXC_F_PT_LOOP_DELAY_POS) & MXC_F_PT_LOOP_DELAY);
714
715 retval = MXC_AFE_GPIO_Config(&gpio_cfg_pt2);
716 if (retval != E_NO_ERROR) {
717 return retval;
718 }
719
720 pPTG->enable |= MXC_F_PTG_ENABLE_PT0 | MXC_F_PTG_ENABLE_PT2;
721 #else
722 pPTG->enable |= MXC_F_PTG_ENABLE_PT0;
723 #endif // End of HART_CLK_4MHZ_CHECK
724
725 //wait for PT to start
726 while ((pPTG->enable & (MXC_F_PTG_ENABLE_PT0)) != MXC_F_PTG_ENABLE_PT0) {}
727
728 #endif // End of (TARGET_NUM == 32680)
729
730 return retval;
731 }
732
idle_hart_clock_pin(void)733 static void idle_hart_clock_pin(void)
734 {
735 // To avoid potential glitches when changing from Alternate functions
736 // First return to IO mode before clearing AF selections
737 HART_CLK_GPIO_PORT->en0_set = HART_CLK_GPIO_PIN;
738 HART_CLK_GPIO_PORT->out_clr = HART_CLK_GPIO_PIN;
739 HART_CLK_GPIO_PORT->outen_set = HART_CLK_GPIO_PIN;
740
741 HART_CLK_GPIO_PORT->en1_clr = HART_CLK_GPIO_PIN;
742 HART_CLK_GPIO_PORT->en2_clr = HART_CLK_GPIO_PIN;
743
744 // GPIO pad pull down enabled
745 HART_CLK_GPIO_PORT->padctrl0 |= HART_CLK_GPIO_PIN;
746 HART_CLK_GPIO_PORT->ps &= ~HART_CLK_GPIO_PIN;
747
748 return;
749 }
750
hart_clock_disable(void)751 void hart_clock_disable(void)
752 {
753 #if (TARGET_NUM == 32675)
754 MXC_GCR->pclkdiv &= ~MXC_F_GCR_PCLKDIV_DIV_CLK_OUT_EN;
755 #elif (TARGET_NUM == 32680)
756 pPTG->enable &= ~MXC_F_PTG_ENABLE_PT0;
757 #endif // End of (TARGET_NUM == 32675)
758
759 // Before disabling the HART clock output, configure pin pull-down
760 idle_hart_clock_pin();
761
762 return;
763 }
764
hart_uart_enable(void)765 int hart_uart_enable(void)
766 {
767 int retval = E_NO_ERROR;
768 uint32_t read_val = 0;
769
770 retval = afe_read_register(MXC_R_AFE_ADC_ZERO_SYS_CTRL, &read_val);
771 if (retval != E_NO_ERROR) {
772 return retval;
773 }
774
775 read_val |= MXC_F_AFE_ADC_ZERO_SYS_CTRL_HART_EN;
776
777 retval = afe_write_register(MXC_R_AFE_ADC_ZERO_SYS_CTRL, read_val);
778
779 return retval;
780 }
781
hart_uart_disable(void)782 int hart_uart_disable(void)
783 {
784 int retval = E_NO_ERROR;
785 uint32_t read_val = 0;
786
787 retval = afe_read_register(MXC_R_AFE_ADC_ZERO_SYS_CTRL, &read_val);
788 if (retval != E_NO_ERROR) {
789 return retval;
790 }
791
792 read_val &= ~MXC_F_AFE_ADC_ZERO_SYS_CTRL_HART_EN;
793
794 retval = afe_write_register(MXC_R_AFE_ADC_ZERO_SYS_CTRL, read_val);
795
796 return retval;
797 }
798
hart_uart_takedown(void)799 int hart_uart_takedown(void)
800 {
801 int retval = E_NO_ERROR;
802
803 // Set the HART uart pins in correct mode for idling
804 retval = hart_uart_pins_idle_mode();
805
806 if (retval != E_NO_ERROR) {
807 return retval;
808 }
809
810 retval = hart_uart_disable();
811
812 if (retval != E_NO_ERROR) {
813 return retval;
814 }
815
816 hart_clock_disable();
817
818 return retval;
819 }
820
hart_uart_setup_saps(hart_uart_callbacks_t callbacks)821 void hart_uart_setup_saps(hart_uart_callbacks_t callbacks)
822 {
823 // Set global callback structure
824 sap_callbacks = callbacks;
825 }
826
hart_uart_setup(uint32_t test_mode)827 int hart_uart_setup(uint32_t test_mode)
828 {
829 int retval = E_NO_ERROR;
830 uint32_t read_val = 0;
831
832 //
833 // NOTE: enable HART Clock output last to avoid any unexpected behaviors by
834 // HART state machine.
835 //
836
837 //
838 // Any HART configuration modifications must be made before enabling HART.
839 //
840
841 //
842 // Utilize character based re-timing on received HART data.
843 // Provides enhanced noise tolerance.
844 //
845 retval = afe_read_register(MXC_R_AFE_HART_RX_TX_CTL, &read_val);
846 if (retval != E_NO_ERROR) {
847 return retval;
848 }
849
850 read_val |= MXC_F_AFE_HART_RX_TX_CTL_RX_DOUT_UART_EN;
851
852 retval = afe_write_register(MXC_R_AFE_HART_RX_TX_CTL, read_val);
853 if (retval != E_NO_ERROR) {
854 return retval;
855 }
856
857 //
858 // Enable HART mode on ME19/AFE.
859 // Puts AFE gpios 2-5 into UART mode
860 //
861
862 retval = hart_uart_enable();
863 if (retval != E_NO_ERROR) {
864 return retval;
865 }
866
867 //
868 // HART UART gpio configuration
869 //
870 // Note, all four UART pins on the ME19/AFE are just floating inputs
871 // until HART_EN in SYS_CTRL is enabled.
872 //
873 // Seems safer to enable the ME19 HART UART side first, and endure
874 // contention until the ME15 side is configured. This means a small
875 // known current drawn between the ME19 HART OUT high and the ME15 HART OUT
876 // pin pull down. Better than floating inputs on the 19 that may consume mAs.
877
878 // The HART OUT pin will have contention, configure it first to minimize current.
879 retval = setup_hart_out_pin();
880 if (retval != E_NO_ERROR) {
881 return retval;
882 }
883
884 retval = setup_rts_pin();
885 if (retval != E_NO_ERROR) {
886 return retval;
887 }
888
889 retval = setup_cd_pin();
890 if (retval != E_NO_ERROR) {
891 return retval;
892 }
893
894 if (test_mode) {
895 // Test mode is required for physical layer test to output constant bit
896 // Frequencies.
897
898 if (test_mode == HART_TEST_MODE_TX_1200) {
899 // Force mode for constant transmit.
900 retval = setup_hart_in_pin();
901 if (retval != E_NO_ERROR) {
902 return retval;
903 }
904
905 // Set (1) means 1200 signal
906 MXC_GPIO_OutSet(HART_IN_GPIO_PORT, HART_IN_GPIO_PIN);
907
908 hart_rts_transmit_mode(); // start transmit
909 } else if (test_mode == HART_TEST_MODE_TX_2200) {
910 // Force mode for constant transmit.
911 retval = setup_hart_in_pin();
912 if (retval != E_NO_ERROR) {
913 return retval;
914 }
915
916 // Clear (0) means 2200 signal
917 MXC_GPIO_OutClr(HART_IN_GPIO_PORT, HART_IN_GPIO_PIN);
918
919 hart_rts_transmit_mode(); // start transmit
920 } else if (test_mode == HART_TEST_MODE_EXTERNAL) {
921 // Allow HART UART pins to be driven externally
922 retval = hart_uart_pins_external_test_mode_state();
923
924 if (retval != E_NO_ERROR) {
925 return retval;
926 }
927 } else {
928 // Unknown Mode
929 return E_BAD_PARAM;
930 }
931
932 } else {
933 hart_rts_receive_mode();
934
935 retval = hart_uart_init(HART_UART_INSTANCE, 1200, MXC_UART_ERFO_CLK);
936 if (retval != E_NO_ERROR) {
937 return E_COMM_ERR;
938 }
939 }
940
941 //
942 // In the case a NON POR reset occurred we must clear ST_DIS to allow normal
943 // HART state machine behavior. This is designed to prevent the HART state
944 // machine from operating when a reset occurs, but leaves the internal and
945 // external biases enabled.
946 //
947 retval = hart_reset_check_and_handle();
948 if (retval != E_NO_ERROR) {
949 return retval;
950 }
951
952 //
953 // Finally turn on HART 4Mhz Clock
954 //
955 retval = hart_clock_enable();
956 if (retval != E_NO_ERROR) {
957 return retval;
958 }
959
960 return retval;
961 }
962
hart_sap_reset_request(void)963 void hart_sap_reset_request(void)
964 {
965 // First disable HART mode, idle pins etc.
966 hart_uart_takedown();
967
968 // Now set it back up
969 // NOTE: Assuming there is no reason to for any test modes while using
970 // this SAP, defaulting to normal hart transceive mode.
971 hart_uart_setup(NORMAL_HART_TRANSCEIVE_MODE);
972
973 // Call RESET.confirm()
974 if (sap_callbacks.reset_confirm_cb) {
975 sap_callbacks.reset_confirm_cb();
976 }
977 }
978
hart_uart_test_transmit_1200(void)979 void hart_uart_test_transmit_1200(void)
980 {
981 // Set (1) means 1200 signal
982 MXC_GPIO_OutSet(HART_IN_GPIO_PORT, HART_IN_GPIO_PIN);
983 }
984
hart_uart_test_transmit_2200(void)985 void hart_uart_test_transmit_2200(void)
986 {
987 // Clear (0) means 2200 signal
988 MXC_GPIO_OutClr(HART_IN_GPIO_PORT, HART_IN_GPIO_PIN);
989 }
990
hart_uart_load_tx_fifo(void)991 int hart_uart_load_tx_fifo(void)
992 {
993 uint32_t num_written = 0;
994 uint32_t load_num = 0;
995 uint32_t avail = MXC_UART_GetTXFIFOAvailable(HART_UART_INSTANCE);
996 int32_t left_to_send = hart_uart_transmission_len - hart_uart_transmission_byte_index;
997
998 // Figure out how many more bytes we need to send
999 if (left_to_send > 0) {
1000 if (left_to_send > avail) {
1001 load_num = avail;
1002 } else {
1003 load_num = left_to_send;
1004 }
1005 } else {
1006 // Nothing to send
1007 return 0;
1008 }
1009
1010 num_written = MXC_UART_WriteTXFIFO(
1011 HART_UART_INSTANCE, (const unsigned char *)(hart_buf + hart_uart_transmission_byte_index),
1012 load_num);
1013
1014 // Advance index based on bytes actually written.
1015 // This should always equal load_num though.
1016 hart_uart_transmission_byte_index += num_written;
1017
1018 // Return the number actually written in case someone is interested.
1019 return num_written;
1020 }
1021
hart_uart_send(uint8_t * data,uint32_t length)1022 int hart_uart_send(uint8_t *data, uint32_t length)
1023 {
1024 // Ensure the line is quiet before beginning transmission
1025 if (hart_receive_active) {
1026 return E_BUSY;
1027 }
1028
1029 if (!data) {
1030 return E_NULL_PTR;
1031 }
1032
1033 if (length < HART_UART_MIN_PACKET_LENGTH) {
1034 // Message is too short to engage proper UART interrupts
1035 // Or if length is 0, there is nothing to do, do not toggle
1036 // RTS disabling receive mode.
1037 return E_BAD_PARAM;
1038 }
1039
1040 if (length > HART_UART_MAX_PACKET_LEN) {
1041 // Message is longer than allowed, do not overflow our buffer
1042 return E_BAD_PARAM;
1043 }
1044
1045 // Set length to transmit, reset transmit index, clear complete
1046 hart_uart_transmission_len = length;
1047 hart_uart_transmission_byte_index = 0;
1048 hart_uart_transmission_complete = 0;
1049
1050 // Copy data to our internal buffer
1051 memcpy((uint8_t *)hart_buf, data, hart_uart_transmission_len);
1052
1053 // NOTE: we are not forcing preamble
1054 hart_rts_transmit_mode();
1055
1056 // Load up the FIFO and allow interrupts handle the rest
1057 hart_uart_load_tx_fifo();
1058
1059 return E_SUCCESS;
1060 }
1061
hart_sap_data_request(uint8_t data)1062 int hart_sap_data_request(uint8_t data)
1063 {
1064 int retval = E_NO_ERROR;
1065
1066 retval = MXC_UART_WriteCharacter(HART_UART_INSTANCE, data);
1067
1068 if (retval != E_SUCCESS) {
1069 // data was not written correctly
1070 // Most likely, FIFO is full, let caller know
1071 return retval;
1072 }
1073
1074 // Call Enable.confirm(state)
1075 if (sap_callbacks.data_confirm_cb) {
1076 sap_callbacks.data_confirm_cb(data);
1077 }
1078
1079 return retval;
1080 }
1081
convert_comm_errors(uint32_t int_flags)1082 static uint8_t convert_comm_errors(uint32_t int_flags)
1083 {
1084 // Convert from UART peripheral error status into formate used by TPDLL
1085 uint8_t comm_status = TPDLL_COMM_ERROR_INDICATOR;
1086
1087 if (int_flags & MXC_F_UART_INT_FL_RX_FERR) {
1088 comm_status |= TPDLL_FRAMING_ERROR;
1089 }
1090
1091 if (int_flags & MXC_F_UART_INT_FL_RX_PAR) {
1092 comm_status |= TPDLL_VERTICAL_PARITY_ERROR;
1093 }
1094
1095 if (int_flags & MXC_F_UART_INT_FL_RX_OV) {
1096 comm_status |= TPDLL_OVERRUN_ERROR;
1097 }
1098
1099 return comm_status;
1100 }
1101
hart_uart_receive_irq(uint32_t uart_err,uint32_t uart_flags)1102 void hart_uart_receive_irq(uint32_t uart_err, uint32_t uart_flags)
1103 {
1104 int retval = E_NO_ERROR;
1105 uint8_t sap_comm_error_status = 0;
1106
1107 // Communications Errors, (Parity, Framing, Overrun)
1108 // Note: Continue attempting to receive, even if error occurs
1109 if (uart_err) {
1110 __disable_irq();
1111 // NOTE: This global error gets cleared in CD ISR
1112 // Or in new errors without clearing any previous
1113 hart_uart_errors |= uart_err;
1114 sap_comm_error_status = convert_comm_errors(uart_err);
1115 __enable_irq();
1116 }
1117
1118 // Data Available, Threshold should be set to 1
1119 if (uart_flags & MXC_F_UART_INT_FL_RX_THD) {
1120 // Should only be one byte available in FIFO, but handle more anyway
1121 while (1) {
1122 // Read out any available chars
1123 retval = MXC_UART_ReadCharacterRaw(HART_UART_INSTANCE);
1124
1125 if (retval >= 0) {
1126 // Only place into our buffer if Carrier Detect is set
1127 // Look at other IRQ flag in critical section for safety
1128 __disable_irq();
1129
1130 if (hart_receive_active) {
1131 if (hart_uart_reception_len < HART_UART_MAX_PACKET_LEN) {
1132 hart_buf[hart_uart_reception_len++] = retval;
1133 } else {
1134 hart_uart_errors |= UART_FLAG_BUFFER_OVERFLOW_ERROR;
1135 sap_comm_error_status |= TPDLL_BUFFER_OVERFLOW_ERROR;
1136 }
1137
1138 // SAP
1139 // If any error occurred during this reception, send ERROR.Indicate
1140 if (sap_comm_error_status) {
1141 // Call ERROR.Indicate(status, data)
1142 if (sap_callbacks.error_indicate_cb) {
1143 sap_callbacks.error_indicate_cb(sap_comm_error_status, retval);
1144 }
1145 } else {
1146 // Call DATA.Indicate(data)
1147 if (sap_callbacks.data_indicate_cb) {
1148 sap_callbacks.data_indicate_cb(retval);
1149 }
1150 }
1151 }
1152
1153 __enable_irq();
1154
1155 } else {
1156 // Otherwise nothing available
1157 break;
1158 }
1159 }
1160 } else {
1161 // No data in the FIFO, but if we do have an error report it.
1162 // NOTE: in some cases error flags will be set but data will be dropped
1163 if (sap_comm_error_status) {
1164 // Call ERROR.Indicate(status, data)
1165 if (sap_callbacks.error_indicate_cb) {
1166 sap_callbacks.error_indicate_cb(sap_comm_error_status, 0);
1167 }
1168 }
1169 }
1170 }
1171
hart_uart_trans_complete_callback(void)1172 void hart_uart_trans_complete_callback(void)
1173 {
1174 // Check to see if the HART UART is actually complete, since this is called
1175 // via calculated delay.
1176 if (MXC_UART_GetStatus(HART_UART_INSTANCE) & MXC_F_UART_STATUS_TX_BUSY) {
1177 // Still busy transmitting.
1178 // We don't want to spend time here polling for completion so register
1179 // another callback and try again.
1180
1181 // Start another wait for SPI TX to complete
1182 afe_timer_delay_async(HART_TIMER, HART_TRANSMIT_COMPLETE_RETRY_IN_US,
1183 (mxc_delay_complete_t)hart_uart_trans_complete_callback);
1184 } else {
1185 // Transmission is DONE, release RTS to return to receive mode
1186 hart_uart_transmission_complete = 1;
1187 hart_rts_receive_mode();
1188
1189 // Call Enable.confirm(state)
1190 if (sap_callbacks.enable_confirm_cb) {
1191 sap_callbacks.enable_confirm_cb(HART_STATE_IDLE);
1192 }
1193 }
1194 }
1195
hart_uart_transmit_irq(void)1196 void hart_uart_transmit_irq(void)
1197 {
1198 // This ISR should only be called when Transmit FIFO is Half or Almost Empty
1199 // NOTE: Need to use Almost Empty here as well, in the case that a short
1200 // HART message is send.
1201 //
1202 // However, smallest HART packet would still contain 9 Bytes. So this is
1203 // just for safety
1204 // 5 Preambles (0xFF), 1 Delimiter, 1 Command, 1 Byte Count, 1 Check Byte
1205 uint32_t bytes_yet_to_load = 0;
1206 uint32_t bytes_in_fifo = 0;
1207 uint32_t transmit_complete_in_us = 0;
1208
1209 // Update pointers etc in critical section
1210 __disable_irq();
1211
1212 // Send more bytes. Also updates transmit index
1213 hart_uart_load_tx_fifo();
1214
1215 // Check how many more bytes left to load in FIFO
1216 if (hart_uart_transmission_byte_index < hart_uart_transmission_len) {
1217 bytes_yet_to_load = hart_uart_transmission_len - hart_uart_transmission_byte_index;
1218 } else {
1219 bytes_yet_to_load = 0;
1220 }
1221
1222 if (bytes_yet_to_load == 0) {
1223 //
1224 // NOTE: due to lack of interrupt source for transmit complete we will arm
1225 // a timer callback to terminate the transmission and switch to receive.
1226 //
1227
1228 //
1229 // To avoid arming multiple timer callbacks, ONLY arm when one byte
1230 // aka TX FIFO Almost Empty interrupt occurs, AND no more bytes are
1231 // left to place in FIFO
1232 //
1233 bytes_in_fifo = HART_UART_FIFO_SIZE - MXC_UART_GetTXFIFOAvailable(HART_UART_INSTANCE);
1234
1235 if (bytes_in_fifo <= HART_UART_FIFO_LEVEL_TO_ARM_CALLBACK) {
1236 // Assume that this interrupt is called shortly after next byte leaves the
1237 // FIFO and is now going out from the shift register. So number
1238 // of bytes in FIFO + 1 (shift register) * 11 bits at 1200 baud.
1239 // 1/1200 = 834us per bit.
1240 transmit_complete_in_us = (bytes_in_fifo + 1) * 11 * 834;
1241
1242 // Start timeout, wait for SPI TX to complete
1243 afe_timer_delay_async(HART_TIMER, transmit_complete_in_us,
1244 (mxc_delay_complete_t)hart_uart_trans_complete_callback);
1245 }
1246 }
1247
1248 __enable_irq();
1249 }
1250
hart_uart_irq_handler(void)1251 void hart_uart_irq_handler(void)
1252 {
1253 uint32_t uart_flags = MXC_UART_GetFlags(HART_UART_INSTANCE);
1254 uint32_t uart_err = 0;
1255
1256 // Clear any flags
1257 MXC_UART_ClearFlags(HART_UART_INSTANCE, uart_flags);
1258
1259 // Check for reception error
1260 uart_err = uart_flags & MXC_UART_ERRINT_FL & HART_UART_INSTANCE->int_en;
1261
1262 // Handle receive events
1263 if ((uart_err) || (uart_flags & MXC_F_UART_INT_FL_RX_THD)) {
1264 hart_uart_receive_irq(uart_err, uart_flags);
1265 }
1266
1267 // Handle transmit events
1268 if (uart_flags & (MXC_F_UART_INT_FL_TX_HE | MXC_F_UART_INT_FL_TX_OB)) {
1269 hart_uart_transmit_irq();
1270 }
1271 }
1272
hart_cd_isr(void * cbdata)1273 void hart_cd_isr(void *cbdata)
1274 {
1275 // NOTE: cbdata is setup to be null
1276
1277 if (get_hart_cd_state()) {
1278 // HART CD is high, reception active
1279 // NOTE: could be carrier without data though
1280 hart_receive_active = 1;
1281 // Reset global error status
1282 hart_uart_errors = 0;
1283
1284 } else {
1285 // HART CD is low, NO reception active
1286 hart_receive_active = 0;
1287
1288 // TODO(ADI): If RX threshold is ever increased: drain rx fifo here
1289 if (hart_uart_reception_len > 0) {
1290 // Got some chars
1291 hart_uart_reception_avail = 1;
1292 }
1293 }
1294
1295 // Call Enable.Indicate(state)
1296 if (sap_callbacks.enable_indicate_cb) {
1297 if (hart_receive_active) {
1298 sap_callbacks.enable_indicate_cb(HART_STATE_RECEIVE_ACTIVE);
1299 } else {
1300 sap_callbacks.enable_indicate_cb(HART_STATE_IDLE);
1301 }
1302 }
1303 }
1304
hart_uart_check_for_receive(void)1305 int hart_uart_check_for_receive(void)
1306 {
1307 // NOTE: RTS is placed into receive mode by hart_uart_send
1308 // Receive mode is default operation for the HART UART
1309
1310 // The HART modem output Carrier Detect (CD) is connected to the UART CTS pin
1311 // reception is handled in interrupt context
1312
1313 return hart_uart_reception_avail;
1314 }
1315
hart_uart_check_transmit_complete()1316 int hart_uart_check_transmit_complete()
1317 {
1318 return hart_uart_transmission_complete;
1319 }
1320
hart_uart_get_received_packet(uint8_t * buffer,uint32_t * packet_length,uint32_t * comm_errors)1321 int hart_uart_get_received_packet(uint8_t *buffer, uint32_t *packet_length, uint32_t *comm_errors)
1322 {
1323 if (!buffer) {
1324 return E_NULL_PTR;
1325 }
1326
1327 if (!packet_length) {
1328 return E_NULL_PTR;
1329 }
1330
1331 if (!comm_errors) {
1332 return E_NULL_PTR;
1333 }
1334
1335 if (hart_receive_active) {
1336 *packet_length = 0;
1337 *comm_errors = 0;
1338 return E_BUSY;
1339 }
1340
1341 if (!hart_uart_reception_avail) {
1342 // No reception available
1343 *packet_length = 0;
1344 *comm_errors = 0;
1345 return E_NONE_AVAIL;
1346 }
1347
1348 // Update interrupt variables in critical section
1349 __disable_irq();
1350
1351 *packet_length = hart_uart_reception_len;
1352 *comm_errors = hart_uart_errors;
1353 hart_uart_reception_avail = 0;
1354 hart_uart_reception_len = 0;
1355
1356 // Otherwise, copy received data for return
1357 memcpy(buffer, (uint8_t *)hart_buf, *packet_length);
1358
1359 __enable_irq();
1360
1361 // Finally report any communications errors
1362 if (hart_uart_errors) {
1363 return E_COMM_ERR;
1364 }
1365
1366 return E_SUCCESS;
1367 }
1368