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