µTasker Forum
µTasker Forum => NXPTM M522XX, KINETIS and i.MX RT => Topic started by: tdrobnak on October 31, 2019, 10:12:48 PM
-
I am using a Kinetis microcontroller and I would like to know what is the preferred way to add a timeout after waiting 10ms for the I2C queue have enough room for the next message to send. I have read both uTasker documents "Global Software and Hardware Timers" and "uTasker - Hardware Timers". Based on the documentation and uTasker code, it looks like the best way to go is to use a hardware timer since the global timer tick resolution is 50ms and I need a 10ms timeout. It looks like the FlexTimer is the hardware timer to use with a Kinetis microcontroller. Would the correct settings be:
void
flexTimer1Delay (unsigned long timerDelayInUsec)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
static TIMER_INTERRUPT_SETUP timer_setup = {0}; // interrupt configuration parameters
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
timer_setup.int_type = TIMER_INTERRUPT;
timer_setup.int_priority = PRIORITY_TIMERS;
timer_setup.int_handler = flexTimer1DelayIntHandler;
timer_setup.timer_reference = (_TIMER_1 | 0); // timer module 1, channel 0;
timer_setup.timer_mode = (TIMER_SINGLE_SHOT | TIMER_US_VALUE); // single shot us timer
timer_setup.timer_value = timerDelayInUsec; // 100? delay
fnConfigureInterrupt((void *) &timer_setup); // enter interrupt and start timer
}
I do not see TIMER_SINGLE_SHOT or TIMER_US_VALUE used in the kinetis FlexTimer code, so I am uncertain of what to set the timer_mode to. Any suggestions on how to set this timer up for a 10ms timeout to call the int_handler function would be appreciated.
Thank you.
-
Hi
You can use PIT, FlexTimer or LPTMR.
There are references for each in ADC_Timers.h.
The flex timer (this is considered to be the "general purpose timer" in the Kinetis and so its interface is compatible with other general purpose ones) is controlled like this:
static TIMER_INTERRUPT_SETUP timer_setup = {0}; // interrupt configuration parameters
timer_setup.int_type = TIMER_INTERRUPT;
timer_setup.int_priority = PRIORITY_TIMERS; // interrupt priority
timer_setup.int_handler = timer_int; // user interrupt callback
timer_setup.timer_reference = 0; // FlexTimer/TPM 0 [in the case of Kinetis]
timer_setup.timer_mode = TIMER_SINGLE_SHOT;
//timer_setup.timer_mode = TIMER_PERIODIC;
timer_setup.timer_value = TIMER_MS_DELAY(10); // 10ms delay
fnConfigureInterrupt((void *)&timer_setup); // configure timer interrupt for timer test
whereby either a single-shot or a periodic mode can be selected.
Regards
Mark
-
Thank you, Mark for your confirmation that the Kinetis part is compatible with the general purpose timer setup.
I set up the timer for a 10ms timer interrupt using:
timer_setup.int_handler = flexTimer1DelayIntHandler;
timer_setup.timer_value = TIMER_MS_DELAY(10); // timer delay until interrupt
When I measure the time from the call to fnConfigureInterrupt((void *) &timer_setup) until the callbck_interrupt, flexTimer1DelayIntHandler, I measure exactly 16us on the oscilloscope. Changing the value in the TIMER_MS_DELAY() (for example: 1000) does not change the 16us interrupt time.
I have stepped through the kinetis_FLEXTIMER.h code and noticed that after the iPrescaler is determined, the updated uDelay is directly assigned to the ptrFlexTimer->FTM_MOD register. Should it not be assigned to "ulDelay+ptrFlexTimer->FTM_CNT" since the FTM_CNT cannot be assumed to be zero except after reset. I changed this, but it had no effect in changing the 16us time in servicing the interrupt.
Do you have any suggestions on why I get such a short timeout? I have gone through the program code and the iPrescaler, ulDelay, and assignments look correct for a 10ms timeout but what I measure on the oscilloscope shows this not to be true.
-
I have determined why I am not getting the 10ms delay after it being set with fnConfigureInterrupt(). It is due to the architecture of the Kinetis KE part.
It was found that a timeout of the desired time TIMER_MS_DELAY(10) was occurring 16us (immediately after the fnConfigureInterrupt() call. This interrupt time did not change when the desired interrupt time was changed. Stepping through the code of fnConfigureInterrupt(), in file, kinetis_FlexTIMER.h, showed that bits FTM_SC_TOF and FTM_SC_TOIE were not being cleared/set. The reason for this is due to incorrect bit mask definitions for FTM_SC_TOIE and FTM_SC_TOF in file kinetis.h. These two definitions need to be changed for a KE1xZ device according to their datasheet (see attachment).
In file kinetis.h, they are defined as
#define FTM_SC_TOIE 0x00000040 // timer overflow interrupt enable
#define FTM_SC_TOF 0x00000080 // timer overflow flag (write '1' to clear)
They need to be defined for KE1xZ devices as:
#define FTM_SC_TOIE 0x00000100 // timer overflow interrupt enable
#define FTM_SC_TOF 0x00000200 // timer overflow flag (write '1' to clear)
The other improvement that can be made is to add the present FTM_CNT to the FTM_MOD value since FTM_CNT is not zero after the first call to fnConfigureInterrupt().
Change from:
ptrFlexTimer->FTM_MOD = ulDelay;
To:
ptrFlexTimer->FTM_MOD = ptrFlexTimer->FTM_CNT + ulDelay;
Once this is done, the correct delay time will occur.
-
Hi
Many thanks for correcting this since I didn't realise that the KE14/15/16 and 18 have a FlexTimer which is slightly extended (and the flags not compatible!).
I have prepared the same changes for the flags for each of these devices so that their interrupts work as they should do:
#if defined KINETIS_KE14 || defined KINETIS_KE15 || defined KINETIS_KE16 || defined KINETIS_KE18
#define FTM_SC_RIE 0x00000400 // reload interrupt enable
#define FTM_SC_RF 0x00000800 // reload flag (write '1' to clear)
#define FTM_SC_TOIE 0x00000100 // timer overflow interrupt enable
#define FTM_SC_TOF 0x00000200 // timer overflow flag (write '1' to clear)
#define FTM_SC_PWMEN0 0x00010000 // channel 0 PWM enable
#define FTM_SC_PWMEN1 0x00020000 // channel 1 PWM enable
#define FTM_SC_PWMEN2 0x00040000 // channel 2 PWM enable
#define FTM_SC_PWMEN3 0x00080000 // channel 3 PWM enable
#define FTM_SC_PWMEN4 0x00100000 // channel 4 PWM enable
#define FTM_SC_PWMEN5 0x00200000 // channel 5 PWM enable
#define FTM_SC_PWMEN6 0x00400000 // channel 6 PWM enable
#define FTM_SC_PWMEN7 0x00800000 // channel 7 PWM enable
#if defined KINETIS_K_FPU
#define FTM_SC_FLTPS_1 0x00000000 // filter prescaler 1
#define FTM_SC_FLTPS_2 0x01000000 // filter prescaler 2
#define FTM_SC_FLTPS_3 0x02000000 // filter prescaler 3
#define FTM_SC_FLTPS_4 0x03000000 // filter prescaler 4
#define FTM_SC_FLTPS_5 0x04000000 // filter prescaler 5
#define FTM_SC_FLTPS_6 0x05000000 // filter prescaler 6
#define FTM_SC_FLTPS_7 0x06000000 // filter prescaler 7
#define FTM_SC_FLTPS_8 0x07000000 // filter prescaler 8
#define FTM_SC_FLTPS_9 0x08000000 // filter prescaler 9
#define FTM_SC_FLTPS_10 0x09000000 // filter prescaler 10
#define FTM_SC_FLTPS_11 0x0a000000 // filter prescaler 11
#define FTM_SC_FLTPS_12 0x0b000000 // filter prescaler 12
#define FTM_SC_FLTPS_13 0x0c000000 // filter prescaler 13
#define FTM_SC_FLTPS_14 0x0d000000 // filter prescaler 14
#define FTM_SC_FLTPS_15 0x0e000000 // filter prescaler 15
#define FTM_SC_FLTPS_16 0x0f000000 // filter prescaler 16
#define FTM_SC_USED_MASK 0x0fff3fff // mask of non-reserved bits in the register
#else
#define FTM_SC_USED_MASK 0x00ff3fff // mask of non-reserved bits in the register
#endif
#else
#define FTM_SC_TOIE 0x00000040 // timer overflow interrupt enable
#define FTM_SC_TOF 0x00000080 // timer overflow flag (write '1' to clear)
#define FTM_SC_USED_MASK 0x00000fff // mask of non-reserved bits in the register
#endif
As for the CNT values, the code usually sets the counter to zero before setting the match but it also wasn't doing it for these chips. I changed it like this:
#if (!defined KINETIS_KL && !defined KINETIS_KE) || (defined KINETIS_KE06 || defined KINETIS_KE14 || defined KINETIS_KE15 || defined KINETIS_KE16 || defined KINETIS_KE18)
ptrFlexTimer->FTM_CNTIN = 0; // counter start value
ptrFlexTimer->FTM_CNT = 0; // {7} cause the counter to be set to zero
#endif
whereby I also needed to make a similar change to the
typedef struct stFLEX_TIMER_MODULE
struct
so that these are available:
#if defined KINETIS_KL || (defined KINETIS_KE && !defined KINETIS_KE06 && !defined KINETIS_KE14 && !defined KINETIS_KE15 && !defined KINETIS_KE16 && !defined KINETIS_KE18)
I am hoping that this will then ensure all KE parts to operate correctly with repect to the single-shot and periodic timer interrupt.
Regards
Mark