Author Topic: Need a suggestion on best way to implement a 10ms timeout  (Read 8701 times)

Offline tdrobnak

  • Newbie
  • *
  • Posts: 28
    • View Profile
Need a suggestion on best way to implement a 10ms timeout
« 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.

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3239
    • View Profile
    • uTasker
Re: Need a suggestion on best way to implement a 10ms timeout
« Reply #1 on: November 01, 2019, 12:57:50 AM »
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

Offline tdrobnak

  • Newbie
  • *
  • Posts: 28
    • View Profile
Re: Need a suggestion on best way to implement a 10ms timeout
« Reply #2 on: November 01, 2019, 08:17:28 PM »
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.
 

Offline tdrobnak

  • Newbie
  • *
  • Posts: 28
    • View Profile
Re: Need a suggestion on best way to implement a 10ms timeout
« Reply #3 on: November 04, 2019, 08:05:41 PM »
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.


Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3239
    • View Profile
    • uTasker
Re: Need a suggestion on best way to implement a 10ms timeout
« Reply #4 on: November 05, 2019, 12:25:56 AM »
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