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 /* **** Includes **** */
22 #include <stdint.h>
23 #include <stddef.h>
24 #include "mxc_device.h"
25 #include "mxc_assert.h"
26 #include "mxc_sys.h"
27 #include "afe_timer.h"
28 #include "nvic_table.h"
29 #include "tmr_revb.h"
30
31 #define MAX32675_FIRST_LP_TIMER_INSTANCE_NUMBER 4
32 #define MAX32680_FIRST_LP_TIMER_INSTANCE_NUMBER 4
33
34 #define TIMER_16A_OFFSET 0
35 #define TIMER_16B_OFFSET 16
36
37 // Globals
38 afe_timeout_complete_t afe_irq_callback;
39 afe_timeout_complete_t hart_irq_callback;
40
41 uint32_t g_timer_prescaler = 0;
42 mxc_tmr_regs_t *g_afe_timer_inst;
43 uint32_t g_afe_spi_timer_complete = 0;
44 uint32_t g_afe_hart_timer_complete = 0;
45
AFE_TMR_Stop_16(mxc_tmr_regs_t * tmr,mxc_tmr_bit_mode_t bitMode)46 static void AFE_TMR_Stop_16(mxc_tmr_regs_t *tmr, mxc_tmr_bit_mode_t bitMode)
47 {
48 int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
49 (void)tmr_id;
50 MXC_ASSERT(tmr_id >= 0);
51
52 uint32_t timerOffset;
53
54 if (bitMode == TMR_BIT_MODE_16B) {
55 timerOffset = TIMER_16B_OFFSET;
56 } else {
57 timerOffset = TIMER_16A_OFFSET;
58 }
59
60 tmr->ctrl0 &= ~(MXC_F_TMR_CTRL0_EN_A << timerOffset);
61 }
62
AFE_TMR_SetCompare_16(mxc_tmr_regs_t * tmr,mxc_tmr_bit_mode_t bitMode,uint16_t cmp_cnt)63 static void AFE_TMR_SetCompare_16(mxc_tmr_regs_t *tmr, mxc_tmr_bit_mode_t bitMode, uint16_t cmp_cnt)
64 {
65 int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
66 (void)tmr_id;
67 MXC_ASSERT(tmr_id >= 0);
68
69 uint32_t timerOffset;
70
71 if (bitMode == TMR_BIT_MODE_16B) {
72 timerOffset = TIMER_16B_OFFSET;
73 } else {
74 timerOffset = TIMER_16A_OFFSET;
75 }
76
77 tmr->cmp &= ~(0xFFFF << timerOffset);
78 tmr->cmp |= (cmp_cnt << timerOffset);
79 }
80
AFE_TMR_SetCount_16(mxc_tmr_regs_t * tmr,mxc_tmr_bit_mode_t bitMode,uint16_t cnt)81 static void AFE_TMR_SetCount_16(mxc_tmr_regs_t *tmr, mxc_tmr_bit_mode_t bitMode, uint16_t cnt)
82 {
83 int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
84 (void)tmr_id;
85 MXC_ASSERT(tmr_id >= 0);
86
87 uint32_t timerOffset;
88
89 if (bitMode == TMR_BIT_MODE_16B) {
90 timerOffset = TIMER_16B_OFFSET;
91 } else {
92 timerOffset = TIMER_16A_OFFSET;
93 }
94
95 // Note: must wait for Timer Write Done when setting TMR_CNT
96 tmr->cnt &= ~(0xFFFF << timerOffset);
97 while (!(tmr->intfl & (MXC_F_TMR_REVB_INTFL_WRDONE_A << timerOffset))) {}
98 tmr->cnt |= (cnt << timerOffset);
99 while (!(tmr->intfl & (MXC_F_TMR_REVB_INTFL_WRDONE_A << timerOffset))) {}
100 }
101
AFE_TMR_ClearFlags_16(mxc_tmr_regs_t * tmr,mxc_tmr_bit_mode_t bitMode)102 static void AFE_TMR_ClearFlags_16(mxc_tmr_regs_t *tmr, mxc_tmr_bit_mode_t bitMode)
103 {
104 int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
105 (void)tmr_id;
106 MXC_ASSERT(tmr_id >= 0);
107
108 uint32_t timerOffset;
109
110 if (bitMode == TMR_BIT_MODE_16B) {
111 timerOffset = TIMER_16B_OFFSET;
112 } else {
113 timerOffset = TIMER_16A_OFFSET;
114 }
115
116 tmr->intfl |= (MXC_F_TMR_INTFL_IRQ_A << timerOffset);
117 }
118
AFE_TMR_EnableInt_16(mxc_tmr_regs_t * tmr,mxc_tmr_bit_mode_t bitMode)119 static void AFE_TMR_EnableInt_16(mxc_tmr_regs_t *tmr, mxc_tmr_bit_mode_t bitMode)
120 {
121 int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
122 (void)tmr_id;
123 MXC_ASSERT(tmr_id >= 0);
124
125 uint32_t timerOffset;
126
127 if (bitMode == TMR_BIT_MODE_16B) {
128 timerOffset = TIMER_16B_OFFSET;
129 } else {
130 timerOffset = TIMER_16A_OFFSET;
131 }
132
133 tmr->ctrl1 |= (MXC_F_TMR_CTRL1_IE_A << timerOffset);
134 }
135
AFE_TMR_Start_16(mxc_tmr_regs_t * tmr,mxc_tmr_bit_mode_t bitMode)136 static void AFE_TMR_Start_16(mxc_tmr_regs_t *tmr, mxc_tmr_bit_mode_t bitMode)
137 {
138 int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
139 (void)tmr_id;
140 MXC_ASSERT(tmr_id >= 0);
141
142 uint32_t timerOffset;
143
144 if (bitMode == TMR_BIT_MODE_16B) {
145 timerOffset = TIMER_16B_OFFSET;
146 } else {
147 timerOffset = TIMER_16A_OFFSET;
148 }
149
150 tmr->ctrl0 |= (MXC_F_TMR_CTRL0_EN_A << timerOffset);
151 while (!(tmr->ctrl1 & (MXC_F_TMR_CTRL1_CLKEN_A << timerOffset))) {}
152 }
153
154 // Note, this only applies to NON-Lower Power Timers
AFE_TMR_GetClockSrc(mxc_tmr_clock_t clk,uint8_t * clockSource)155 static int AFE_TMR_GetClockSrc(mxc_tmr_clock_t clk, uint8_t *clockSource)
156 {
157 switch (clk) {
158 case MXC_TMR_APB_CLK:
159 *clockSource = MXC_TMR_CLK0;
160 break;
161
162 case MXC_TMR_8M_CLK:
163 *clockSource = MXC_TMR_CLK2;
164 break;
165
166 case MXC_TMR_32M_CLK:
167 *clockSource = MXC_TMR_CLK3;
168 break;
169
170 default:
171 return E_BAD_PARAM;
172 break;
173 }
174
175 return E_NO_ERROR;
176 }
177
AFE_TMR_Config_16(mxc_tmr_regs_t * tmr,mxc_tmr_cfg_t * cfg)178 static int AFE_TMR_Config_16(mxc_tmr_regs_t *tmr, mxc_tmr_cfg_t *cfg)
179 {
180 uint32_t timerOffset;
181 uint8_t clk_src = 0;
182 int status = E_NO_ERROR;
183 int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
184 (void)tmr_id;
185 MXC_ASSERT(tmr_id >= 0);
186
187 if (cfg == NULL) {
188 return E_NULL_PTR;
189 }
190
191 if (cfg->bitMode == TMR_BIT_MODE_16B) {
192 timerOffset = TIMER_16B_OFFSET;
193 } else {
194 timerOffset = TIMER_16A_OFFSET;
195 }
196
197 // Convert Clock Type
198 status = AFE_TMR_GetClockSrc(cfg->clock, &clk_src);
199 if (status != E_NO_ERROR) {
200 return status;
201 }
202
203 // Clear any existing config
204 tmr->ctrl0 &= ~(0xFFFF << timerOffset);
205 tmr->ctrl1 &= ~(0xFFFF << timerOffset);
206 tmr->cmp &= ~(0xFFFF << timerOffset);
207 tmr->cnt &= ~(0xFFFF << timerOffset);
208
209 tmr->ctrl0 |= (MXC_F_TMR_CTRL0_CLKEN_A << timerOffset);
210 while (!(tmr->ctrl1 & (MXC_F_TMR_CTRL1_CLKRDY_A << timerOffset))) {}
211
212 tmr->ctrl0 |= (cfg->mode << timerOffset);
213 tmr->ctrl0 |= ((cfg->pol << MXC_F_TMR_CTRL0_POL_A_POS) << timerOffset);
214 tmr->ctrl0 |= ((cfg->pres << MXC_F_TMR_CTRL0_CLKDIV_A_POS) << timerOffset);
215 tmr->ctrl1 |= ((clk_src << MXC_F_TMR_CTRL0_CLKDIV_A_POS) << timerOffset);
216 tmr->cnt = (0x1 << timerOffset);
217 tmr->cmp = (cfg->cmp_cnt << timerOffset);
218
219 return E_NO_ERROR;
220 }
221
afe_timer_interrupt_handler(void)222 static void afe_timer_interrupt_handler(void)
223 {
224 uint32_t flags = MXC_TMR_GetFlags(g_afe_timer_inst);
225
226 if (flags & MXC_F_TMR_INTFL_IRQ_A) {
227 // AFE Timer Interrupt
228 AFE_TMR_ClearFlags_16(g_afe_timer_inst, AFE_SPI_TIMER);
229
230 g_afe_spi_timer_complete = 1;
231
232 if (afe_irq_callback) {
233 afe_irq_callback(E_ABORT);
234 }
235 } else if (flags & MXC_F_TMR_INTFL_IRQ_B) {
236 // HART Timer Interrupt
237 AFE_TMR_ClearFlags_16(g_afe_timer_inst, HART_TIMER);
238
239 g_afe_hart_timer_complete = 1;
240
241 if (hart_irq_callback) {
242 hart_irq_callback(E_ABORT);
243 }
244 }
245 }
246
afe_timer_validate_id(mxc_tmr_regs_t * tmr)247 static int afe_timer_validate_id(mxc_tmr_regs_t *tmr)
248 {
249 uint8_t tmr_id = 0;
250 MXC_ASSERT((tmr_id = MXC_TMR_GET_IDX(tmr)) >= 0);
251
252 #if (TARGET_NUM == 32675)
253 if (tmr_id >= MAX32675_FIRST_LP_TIMER_INSTANCE_NUMBER) {
254 return E_NOT_SUPPORTED;
255 }
256 #elif (TARGET_NUM == 32680)
257 if (tmr_id >= MAX32680_FIRST_LP_TIMER_INSTANCE_NUMBER) {
258 return E_NOT_SUPPORTED;
259 }
260 #else
261 #error "Selected TARGET is not known to have an AFE\n"
262 #endif
263
264 g_afe_timer_inst = tmr;
265
266 return E_NO_ERROR;
267 }
268
afe_timer_choose_prescaler(void)269 static int afe_timer_choose_prescaler(void)
270 {
271 uint32_t timer_input_clk = 0;
272 uint32_t scaled_clk = 0;
273 int32_t scaled_diff_prev = 0;
274 int32_t scaled_diff_curr = 0;
275
276 g_timer_prescaler = 0;
277
278 SystemCoreClockUpdate(); // Ensure Clock is up to date
279 timer_input_clk = PeripheralClock;
280
281 // Don't support input clock less than 1Mhz
282 if (timer_input_clk < 1000000) {
283 return E_NOT_SUPPORTED;
284 }
285
286 scaled_clk = timer_input_clk / 1000000;
287
288 // Prescaler formula is input_clk/(2^prescaler) I.E. prescaler of 0 is div 1.
289 for (g_timer_prescaler = 0; g_timer_prescaler < MXC_V_TMR_CTRL0_CLKDIV_A_DIV_BY_4096;
290 g_timer_prescaler++) {
291 if (scaled_clk <= (1 << g_timer_prescaler)) {
292 break;
293 }
294 }
295
296 // Should be close now, choose current prescaler or previous one based on diff to 1Mhz
297 scaled_diff_curr = scaled_clk - (1 << g_timer_prescaler);
298 scaled_diff_prev = scaled_clk - (1 << (g_timer_prescaler - 1));
299
300 // Get absolute value
301 if (scaled_diff_curr < 0) {
302 scaled_diff_curr *= -1;
303 }
304 if (scaled_diff_prev < 0) {
305 scaled_diff_prev *= -1;
306 }
307
308 if (scaled_diff_curr > scaled_diff_prev) {
309 // Previous scaler was closer, use it
310 g_timer_prescaler--;
311 }
312
313 return E_NO_ERROR;
314 }
315
afe_timer_config(mxc_tmr_regs_t * tmr)316 int afe_timer_config(mxc_tmr_regs_t *tmr)
317 {
318 mxc_tmr_cfg_t afe_tmr_cfg;
319 mxc_tmr_cfg_t hart_tmr_cfg;
320 int status = E_NO_ERROR;
321
322 // We require TO detection for SPI transactions with AFE,
323 // and for accurately timed callbacks for HART UART transmitter.
324 // So we will split a system timer into two 16 bit timers.
325 // Doing so necessitates use of NON LP timers, and setting
326 // the prescaler to allow for proper timer range.
327
328 // The AFE timer (Timer A) will need to time a range from about 800us-10ms.
329 // The HART UART timer (Timer B) will need to time a range from about 1600us-19ms.
330 // Due to having only 16 bits each for counting, we will target for the
331 // prescaled input clock to be ~1MHz which should provide adequate timer
332 // range for both timers. @1MHz input clock each tick is 1us giving a max
333 // timer value of 65.5ms.
334
335 // First ensure specified timer is of correct type, that is NON LP timer.
336 status = afe_timer_validate_id(tmr);
337 if (status != E_NO_ERROR) {
338 return status;
339 }
340
341 // Based on System Clock frequency choose divider to achieve input clock
342 // closest to 1MHz.
343 // NOTE: Always using PCLK to simplify configurations.
344 status = afe_timer_choose_prescaler();
345 if (status != E_NO_ERROR) {
346 return status;
347 }
348
349 // Setup AFE Timer driver configuration
350 afe_tmr_cfg.pres = (mxc_tmr_pres_t)g_timer_prescaler;
351 afe_tmr_cfg.mode = TMR_MODE_ONESHOT;
352 afe_tmr_cfg.bitMode = AFE_SPI_TIMER;
353 afe_tmr_cfg.clock = MXC_TMR_APB_CLK;
354 afe_tmr_cfg.cmp_cnt = 0;
355 afe_tmr_cfg.pol = 1;
356
357 // Note: MXC_TMR_INIT does not properly handle split 16 bit modes
358 // Calling it any way here to handle baseline initialization
359 status = MXC_TMR_Init(g_afe_timer_inst, &afe_tmr_cfg, FALSE);
360 if (status != E_NO_ERROR) {
361 return status;
362 }
363
364 // Actual 16bit configuration
365 status = AFE_TMR_Config_16(g_afe_timer_inst, &afe_tmr_cfg);
366 if (status != E_NO_ERROR) {
367 return status;
368 }
369
370 // Setup HART Timer driver configuration
371 hart_tmr_cfg.pres = (mxc_tmr_pres_t)g_timer_prescaler;
372 hart_tmr_cfg.mode = TMR_MODE_ONESHOT;
373 hart_tmr_cfg.bitMode = HART_TIMER;
374 hart_tmr_cfg.clock = MXC_TMR_APB_CLK;
375 hart_tmr_cfg.cmp_cnt = 0;
376 hart_tmr_cfg.pol = 1;
377
378 // Actual 16bit configuration
379 status = AFE_TMR_Config_16(g_afe_timer_inst, &hart_tmr_cfg);
380 if (status != E_NO_ERROR) {
381 return status;
382 }
383
384 // Overwrite default Timer IRQ Vector with ours
385 MXC_NVIC_SetVector(MXC_TMR_GET_IRQ(MXC_TMR_GET_IDX(g_afe_timer_inst)),
386 afe_timer_interrupt_handler);
387 NVIC_EnableIRQ(MXC_TMR_GET_IRQ(MXC_TMR_GET_IDX(g_afe_timer_inst)));
388
389 return status;
390 }
391
afe_timer_calc_ticks(uint32_t microseconds,uint16_t * ticks)392 static int afe_timer_calc_ticks(uint32_t microseconds, uint16_t *ticks)
393 {
394 // Bounds check for MAX timeout and convert to actual ticks
395 uint64_t timer_tick_period_ns = 0;
396 uint64_t nanoseconds = microseconds * 1000;
397 uint64_t ratioed_ticks = 0;
398
399 timer_tick_period_ns = ((1 << g_timer_prescaler) * 1000) / (PeripheralClock / 1000000);
400
401 ratioed_ticks = nanoseconds / timer_tick_period_ns;
402
403 // Bounds check the results
404 if (ratioed_ticks > UINT16_MAX) {
405 // Timeout longer than supported with current prescaler
406 *ticks = 0;
407 return E_OVERFLOW;
408 }
409
410 if (ratioed_ticks == 0) {
411 // Unexpectedly resulting timeout count is 0
412 *ticks = 0;
413 return E_UNKNOWN;
414 }
415
416 *ticks = ratioed_ticks;
417 return E_NO_ERROR;
418 }
419
afe_timer_delay_async(mxc_tmr_bit_mode_t timer_selection,uint32_t timeout_us,afe_timeout_complete_t cb)420 int afe_timer_delay_async(mxc_tmr_bit_mode_t timer_selection, uint32_t timeout_us,
421 afe_timeout_complete_t cb)
422 {
423 uint16_t calculated_ticks = 0;
424 int status = E_NO_ERROR;
425
426 if ((timer_selection != AFE_SPI_TIMER) && (timer_selection != HART_TIMER)) {
427 return E_BAD_PARAM;
428 }
429
430 if (timeout_us == 0) {
431 return E_BAD_PARAM;
432 }
433
434 status = afe_timer_calc_ticks(timeout_us, &calculated_ticks);
435 if (status != E_NO_ERROR) {
436 return status;
437 }
438
439 // TMR Driver does not provide low level access for 16 bit mode
440 AFE_TMR_Stop_16(g_afe_timer_inst, timer_selection);
441
442 // Reset count every time, otherwise it will creep up and incur a false timeout
443 AFE_TMR_SetCount_16(g_afe_timer_inst, timer_selection, 1);
444 AFE_TMR_SetCompare_16(g_afe_timer_inst, timer_selection, calculated_ticks);
445 AFE_TMR_ClearFlags_16(g_afe_timer_inst, timer_selection);
446
447 // Set up interrupts, and completion irq globals
448 if (timer_selection == AFE_SPI_TIMER) {
449 afe_irq_callback = cb;
450 g_afe_spi_timer_complete = 0;
451 } else {
452 hart_irq_callback = cb;
453 g_afe_hart_timer_complete = 0;
454 }
455
456 AFE_TMR_EnableInt_16(g_afe_timer_inst, timer_selection);
457 AFE_TMR_Start_16(g_afe_timer_inst, timer_selection);
458
459 return E_SUCCESS;
460 }
461
afe_timer_delay_check(mxc_tmr_bit_mode_t timer_selection)462 int afe_timer_delay_check(mxc_tmr_bit_mode_t timer_selection)
463 {
464 if ((timer_selection != AFE_SPI_TIMER) && (timer_selection != HART_TIMER)) {
465 return E_BAD_PARAM;
466 }
467
468 if (timer_selection == AFE_SPI_TIMER) {
469 if (g_afe_spi_timer_complete) {
470 return E_NO_ERROR;
471 }
472
473 return E_BUSY;
474 } else {
475 if (g_afe_hart_timer_complete) {
476 return E_NO_ERROR;
477 }
478
479 return E_BUSY;
480 }
481 }
482
afe_timer_delay_abort(mxc_tmr_bit_mode_t timer_selection)483 int afe_timer_delay_abort(mxc_tmr_bit_mode_t timer_selection)
484 {
485 if ((timer_selection != AFE_SPI_TIMER) && (timer_selection != HART_TIMER)) {
486 return E_BAD_PARAM;
487 }
488
489 AFE_TMR_Stop_16(g_afe_timer_inst, timer_selection);
490
491 if (timer_selection == AFE_SPI_TIMER) {
492 if (afe_irq_callback) {
493 afe_irq_callback(E_ABORT);
494 afe_irq_callback = NULL;
495 }
496 } else {
497 if (hart_irq_callback) {
498 hart_irq_callback(E_ABORT);
499 hart_irq_callback = NULL;
500 }
501 }
502
503 return E_SUCCESS;
504 }
505