This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C Timer as source of HWI interrupt priority (TI-RTOS) and CPU load question

Other Parts Discussed in Thread: TM4C129ENCPDT, SYSBIOS

Hello,


I have TM4C129ENCPDT and a project of sinewave inverter with some peripherals.

I am generating the sinewave by means of a periodic HWI timer-called function.

My problem is, however, that I miss about 30% of the samples because there are other HWI sources with the same priority which is 224. Here highest number is the lowest priority. Thus, my sinewave is inaccurate which causes problem in mainly hitting saturation of the output transformer and increased THD.

I can lower the priority of the hwiCAN (which handles received CAN-bus messages) but then, of course, I miss even more sinewave PWM samples. What I need is to lower the priority of the timer I use to call the sinewave generator.

The timer is specified in the .cfg file>

// Create sineTimer as source of Hwi
var timerParams = new Timer.Params();
timerParams.startMode = Timer.StartMode_AUTO;
timerParams.runMode = Timer.RunMode_CONTINUOUS;
timerParams.period = 72; // in microseconds
Program.global.sineTimer = Timer.create(Timer.ANY, "&sinetimer", timerParams);

Also, the other weird thing is that the HWI consumes about 32% of the CPU time, the other 2 tasks about 0.3% and 1%  but the total CPU load is about 46%.

Thanks in advance for any clue.

  • Hello user4016414

    I have asked one of my colleagues to assist you

    Regards
    Amit
  • So why are you not using the highest priority or maybe second highest for your sinewave?

    user4016414 said:
    timerParams.period = 72; // in microseconds

    user4016414 said:
    Also, the other weird thing is that the HWI consumes about 32% of the CPU time

    At 120MHz, 72uS is around 8500 clocks so 32% --> 2700 clocks for your interrupt. Hard to judge w/o knowing more details but easily believable.

    Your highest frequency processes/interrupts should have your highest priority. Look up rate monotonic analysis. Unless you have something running faster than 72uS it should have your highest priority

    Robert

  • Dear Robert, thanks for your reply. No, I do not have anything faster than this 14kHz PWM update HWI.

    Maybe I wasn't clear enough - I know I need to increase the HWI priority, but the question is How? I tried something like TimerParams.priority = ? But it produced an error.

    And the other problem with  CPU usage - yes 31% usage by HWI is OK, but why the total usage is over 45% when other tasks need only about 2% altogether? What takes up another ~13%?

    Thanks in advance for help. It is very appreciated.

  • user4016414 said:
    I know I need to increase the HWI priority, but the question is How?

    AH, sorry about that.

    I don't know TI-RTOS but there was a recent thread dealing with problems with high priority interrupts

    https://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/p/505335/1844584#pi239031350

    Maybe there are some hints in there.

    user4016414 said:
    And the other problem with  CPU usage - yes 31% usage by HWI is OK, but why the total usage is over 45% when other tasks need only about 2% altogether? What takes up another ~13%?

    Well depending on how it's measured there is likely RTOS overhead and maybe sections of application code that do not get assigned to the appropriate bins. Or it may not be real.

    Robert

  • Dear Robert


    I found other threads about this in the meantime and here they suggest I could initialize a *hwiParams field in the timerParams structure to assign the resulting Hwi an interrupt I like.

    here, someone uses this syntax:

        hwiParams.priority = 0;       //zero latency interrupt, priority 0
        TimerParams.hwiParams = &hwiParams;
    

    but he uses it in the main file, not the .cfg file as I do. When I do that in the .cfg file

    // Create sineTimer as source of Hwi
    var timerParams = new Timer.Params();
    var timerhwiParams = new Hwi.Params();
    timerParams.startMode = Timer.StartMode_AUTO;
    timerParams.runMode = Timer.RunMode_CONTINUOUS;
    timerParams.period = 72; // in us. musi byt dvojnasobok PWMPeriod (mame count up-down mode)
    timerhwiParams.priority = 128;
    timerParams.hwiParams = &timerhwiParams;
    Program.global.sineTimer = Timer.create(Timer.ANY, "&sinetimer", timerParams);

    , I get an Syntax Error on the line

    timerParams.hwiParams = &timerhwiParams;

    When I tried to remove the &, the syntax error is gone, but then I obviously get

    ti.sysbios.family.arm.lm4.Timer.Params#1: incompatible assignment to hwiParams : xdc.services.intern.xsr.Value$Obj@171ef12::ti.sysbios.hal.Hwi.Params#1

    because hwiParams inside timerParams needs to be a pointer, as specified here.

    Any clue, please?

  • I don't anything about TI-RTOS's configuration utility so my only thought would be to set it up in code. I think there is a forum on TI-RTOS where you might find more information.

    It is possible you cannot do this from the config utility and must do it in code.

    Robert
  • user4016414 said:
    but he uses it in the main file, not the .cfg file as I do. When I do that in the .cfg file

    I haven't tried it, but http://processors.wiki.ti.com/index.php/SYS/BIOS_for_Stellaris_Devices#HOW_TOs appears to show the syntax of how to set the timer priority in a .cfg file.

  • I do not see on that page anything about timer priority. Only Hwi priority setting is described, that also works for me.
    This must not be that hard... simply why does the compiler produce a Syntax Error when assigning timerParams.hwiParams = &timerhwiParams ?
  • Hold on, are you trying to modify the priority of the OS timer? If so I'd suggest you don't do that and use one of the many available other timers on the micro.

    If you are using one of the other timers then surely that does what you want?

    Robert
  • user4016414 said:
    simply why does the compiler produce a Syntax Error when assigning timerParams.hwiParams = &timerhwiParams ?

    Placing double quotes around the &timerhwiParams suppresses the Syntax Error:

    timerParams.hwiParams = "&timerhwiParams";
    

    However, with that syntax error corrected then other errors are reported.

    I am trying to understand how to translate the C timer creation code into the format to insert in the .cfg file.

  • Thanks Chester, It could have caught my attention to how my "&sinetimer" is being created. I tried to enquote it, and I get an error:

    &hwiParams: no element named 'arg'

    However, I found out how to do the priority change the other way. I found out I need to change the priority of TIMER0A (int. number 35) from TImers and Hwi in ROV, as there is a timer of 8640 cycles which is 72us at 120MHz. So I changed it  in the code:

    IntPrioritySet(INT_TIMER0A, 128);

    And it seemingly works:


    However, it did not affect the performance at all. I still lose about 30% of sinewave samples.

    Too bad I can not simply use the the execution graph in RTOS Analyzer, as the HWI takes up too much time and I lose too many samples.

  • A couple of thoughts

    Have you tried instrumenting the interrupt with pin toggles? The idea is to verify or otherwise the interrupt jitter and length.

    I think you are using managed interrupts. These would be subject to latency from the RTOS. Have you considered unmanaged interrupts?

    You're running a lot faster than the RTOS clock. I think your priority is still way too low.

    Robert
  • user4016414 said:
    Thanks Chester, It could have caught my attention to how my "&sinetimer" is being created. I tried to enquote it, and I get an error:

    &hwiParams: no element named 'arg'

    I found the following code in the .cfg script sets the HWI priority without generating compile errors:

    // Create sineTimer as source of Hwi
    var timerParams = new ti_sysbios_family_arm_lm4_Timer.Params();
    var timerhwiParams = new m3Hwi.Params();
    timerParams.startMode = ti_sysbios_family_arm_lm4_Timer.StartMode_AUTO;
    timerParams.runMode = ti_sysbios_family_arm_lm4_Timer.RunMode_CONTINUOUS;
    timerParams.period = 72; // in microseconds
    timerhwiParams.priority = 128;
    timerhwiParams.arg = Program.global.sineTimer;
    timerParams.hwiParams = timerhwiParams;
    Program.global.sineTimer = ti_sysbios_family_arm_lm4_Timer.create(Timer.ANY, "&sinetimer", timerParams);
    

    Note that the .cfg script doesn't take the address of timerhwiParams, but the actual object. I haven't tried running the code, but looking at the C code which is auto-generated from the .cfg script shows the HWI priority has been set to the requested value of 128.

    [The auto-generated code is in the project under <configuration>/configPkg/package/cfg/<project_name>_pem4f.c]

  • user4016414 said:
    Too bad I can not simply use the the execution graph in RTOS Analyzer, as the HWI takes up too much time and I lose too many samples.

    Which debugger are you using?

    If you have a debugger which supports SWO trace, such as a XDS110 or XDS200, you can use the Interrupt Profiling Configuration to traces interrupt entries and exits and time spent in each interrupt where the trace data is collected by hardware. i.e. without software overhead. See Trace Analyzer User’s Guide

  • user4016414 said:
    I am generating the sinewave by means of a periodic HWI timer-called function.

    What does the HWI timer-called function have to do to generate the sinewave?

    If the HWI timer-called function is writing to a peripheral, wondering if possible to get more deterministic timing if DMA triggered from a timer could be used to generate the sinewave.

    e.g. could a buffer of samples to be output to a peripheral be prepared some time in advance, which DMA could output at regular intervals?

  • Thanks Chester,
    tried your script. But I get an error that m3Hwi is undefined, probably you assigned something to it upper in the .cfg file?
    I tried it without m3, and it does not produce an error but neither sets the correct priority. It stays at 224.
    I tried to decrease the priority number even to zero with IntPrioritySet(), but no change unless I set it to zero (so that I would get a zero-latency, right? ) , but then I get an exception, even before I hit the "play" button in CCS:

    ti.sysbios.family.arm.m3.Hwi: line 1087: E_hardFault: FORCED
    ti.sysbios.family.arm.m3.Hwi: line 1199: E_usageFault: NOCP: Attempting to use co-processor
    Exception occurred in background thread at PC = 0x0000f8ac.
    Core 0: Exception occurred in ThreadType_Swi.
    Swi name: {unknown-instance-name}, handle: 0x2002f550.
    Swi stack base: 0x2002f7f8.
    Swi stack size: 0x800.
    R0 = 0x00000020  R8  = 0x20021d9c
    R1 = 0x10000000  R9  = 0xf0003000
    R2 = 0xf0003000  R10 = 0xf0009c00
    R3 = 0xf0009c00  R11 = 0x2002e684
    R4 = 0x2002eea8  R12 = 0x2002e684
    R5 = 0x2002e5d0  SP(R13) = 0x2002ff08
    R6 = 0x2002e5dc  LR(R14) = 0x0000f899
    R7 = 0x00000001  PC(R15) = 0x0000f8ac
    PSR = 0x01000000
    ICSR = 0x10423803
    MMFSR = 0x00
    BFSR = 0x00
    UFSR = 0x0008
    HFSR = 0x40000000
    DFSR = 0x00000001
    MMAR = 0xe000ed34
    BFAR = 0xe000ed38
    AFSR = 0x00000000
    Terminating execution...
    

    The HWI-called function does calculate the current sinewave position and instantaneous value based on elapsed time from the start of current AC period, checks if there is no overcurrent, etc. and updates new PWM to the generator.

    It was a good idea to instrument it with GPIO pins. But there are not many left on my chip. I tried to benchmark it with Timestamp_get32(); at the very start and end of the HWI and view it via webserver. It looks good, function takes 3091 CPU cycles at 120MHz, that is 25us. That would correspond to about 30% CPU usage by HWI. It seems to me that the interrupt is just not invoked everytime by the timer.

    I use XDS100 v2 debugger.

  • user4016414 said:
    tried your script. But I get an error that m3Hwi is undefined, probably you assigned something to it upper in the .cfg file?

    The definition of m3Hwi is:

    var m3Hwi = xdc.useModule('ti.sysbios.family.arm.m3.Hwi');
    

    In my case the example I started with already had m3Hwi defined, and I only previously posted the manually added lines.

    I have run the example in the debugger, and confirmed that the Hwi priority reported is 128:

    user4016414 said:
    I use XDS100 v2 debugger.

    That doesn't have SWO trace capability.

    user4016414 said:
    I tried to decrease the priority number even to zero with IntPrioritySet(), but no change unless I set it to zero (so that I would get a zero-latency, right? ) , but then I get an exception, even before I hit the "play" button in CCS:

    Does your sinetimer interrupt handler make any SYS/BIOS calls?

    I think there are restrictions on what SYS/BIOS functions a zero-latency ISR can make, but can't remember the details at the moment.

  • user4016414 said:
    It was a good idea to instrument it with GPIO pins. But there are not many left on my chip.

    Too bad, even one would give you more information than you can easily get from a timer.

    user4016414 said:
    It seems to me that the interrupt is just not invoked everytime by the timer.

    One of the things that can happen is drift so that over a period of time you lose an interrupt. Excessive jitter could cause you to miss one as well. I'd suspect the latter with the OS occasionally locking out the interrupt for a relatively prolonged period relative to your frequency.

    These are easy to see with a pin, particularly if you have a scope with the ability to trigger on pulse width. Also you get mins and maxes with a storage scope and most (all?) modern scopes provide that function. Harder to get these with a timer but possible.

    Robert

  • user4016414 said:
    I tried to decrease the priority number even to zero with IntPrioritySet(), but no change unless I set it to zero (so that I would get a zero-latency, right? ) , but then I get an exception, even before I hit the "play" button in CCS:

    Using my .cfg script modifications to set a HWI priority of zero, to get a zero-latency timer interrupt also got an exception.

    From debugging realized the reason is that when create a SYS/BIOS timer the SYS/BIOS function Timer_isrStub() is hooked to service the timer interrupt, where Timer_isrStub() handles the timer interrupt status bits and rollover and then calls the user registered tick function.

    Timer_isrStub() takes an argument which is a pointer to the Timer_Object for which timer instance is being serviced. When the HWI priority isn't zero-latency Timer_isrStub() is called from the SYS/BIOS HWI dispatcher and the Timer_Object argument is valid.

    When the HWI priority is zero-latency the Timer_isrStub() is called directly as a hardware interrupt and the Timer_Object argument is undefined. This leads to an exception when attempts to de-reference an invalid Timer_Object pointer. The following screen shot shows Timer_isrStub() being called as zero-latency interrupt with the timer as an invalid pointer 0x1 which leads to an exception when step the next instruction:

    What this means is that if you need a zero-latency timer interrupt then need to service the interrupt directly rather than using a SYS/BIOS timer.

  • Dear Robert, I implemented some benchmarking to the ISR routine and it takes 20us normally and 27us at a new period zero crossing. I do not understand why should SYSBIOS miss these. It easily fits into 72us time window.  Even when now its priroity is 128, highest priority from all HWIs ..

    Will try that thing with gpio instrumentation. Yes I have a scope that will do that.

  • user4016414 said:
    I do not understand why should SYSBIOS miss these. It easily fits into 72us time window.  Even when now its priroity is 128, highest priority from all HWIs

    Robert previously suggested the possibility that interrupts are being disabled for longer than the 72us time window.

    Can you list which SYB/BIOS function(s) your program calls at run time, to be able to determine which SYS/BIOS function(s) may be disabling interrupts?

  • Thanks Chester. And sorry for the delay.

    I think I do not anymore use any SYS/BIOS APIs in the runtime, except PWM_setDuty() but disabling this does not change anything. There are some System_printf() and System_flush() but only at the startup to show some things on console, but only at the startup - I already removed them from runtime some time ago.


    Could some driver function disable HWI? Here is a complete list of driver functions I use in the code:

    httpSendStatusLine
    httpSendClientStr
    
    efs_createfile
    efs_destroyfile
    
    GPIOPinRead
    GPIOPinWrite
    SysCtlDelay //only at startup
    
    PWM_Params_init
    PWM_open
    PWMGenConfigure
    PWMPulseWidthSet
    PWMSyncTimeBase //only at startup
    PWMSyncUpdate //only at startup
    
    PWM_setDuty
    
    ADCSequenceDisable
    ADCHardwareOversampleConfigure
    ADCSequenceConfigure
    ADCSequenceStepConfigure
    ADCSequenceEnable
    ADCIntClear
    ADCProcessorTrigger
    ADCIntStatus
    ADCSequenceDataGet
    
    Semaphore_pend
    Semaphore_post
    Task_sleep
    
    CANMessageSet
    CANMessageGet
    
    sinf
    fabsf
    IntPrioritySet //only at startup
    
    FlashUserGet //only at startup
    


    Any thoughts?

    Thanks

  • user4016414 said:
    Could some driver function disable HWI? Here is a complete list of driver functions I use in the code:

    I haven't performed a complete check, but looking at the source code for the Semaphore_pend and Semaphore_post functions in ti_rtos_tivac_2_16_01_14\products\bios_6_45_02_31\packages\ti\sysbios\knl\Samaphore.c show that interrupts are disabled and the re-enabled by calls to Hwi_disable() and Hwi_restore().

    I haven't attempted to measure how long interrupts are disabled during calls to Semaphore_pend() and Semaphore_post().

    Other SYS/BIOS functions which involve inter-task communication are likely to also disable interrupts.

  • Thanks Chester. I use the semaphore in the ADC measurements to ensure only one task accesses the ADC at a time. I measure various things which I need every 5ms (instantaneous battery current, voltage, output current...), some every 500ms (temperatures) .. So you suggest some other way to do this? Or, else, how can I implement the NMI with a timer, instead of my current approach?