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.

TM4C1294KCPDT: ARM Cortex M4v7 Sub Priority bit feilds

Guru 55913 points
Part Number: TM4C1294KCPDT
Other Parts Discussed in Thread: LM3S8971

It would seem ARM Cortex M4v7 programmers guide priority bit fields are missing from how TI has implemented TM4C1294 NVIC Priority/Sub priority groups. 

Specifically the sub priority fields (0-7) for each group priority (0-7) in a 3 bit split configured REG58 (APINT) are missing from datasheet. ARM Cortex M4v7 NVIC supports up to 256 priority levels for each interrupt. The sub priority bit fields (nibble) for each primary grouping (0-7) interrupt source that ARM programmers guide shows are missing in TI datasheet. Datasheet Table 3-9 row 1 (0x0-0x4) is incorrect to suggest only 1 sub priority can exist in 3 bit split as that would violate ARM Cortex M4v7 (proven) NVIC architecture.

For clarity of issue I added grouping bit split (Notes) M4v7 NVIC is capable to decode next to the Tivaware (hw_nvic.h) NVIC_APINT defines. It would seem the interrupt sub priority interrupt fields 3 bit split for 0x00000200  [2:0] Tivaware does not set sub priority levels, 8 interrupt priority level bits (0x0-0x7), e.g. priority groupings 0x00-0xE0. ARM M4v7 Core NVIC supports primary priority groupings and levels of interrupt priority within this case 0-7 groupings 0x0-0xE0. That is not being configured by IntPrioritySet() which only sets the Sub priority interrupt bit field to act only as a primary grouping and that will never work properly in M4v7 NVIC schema. It seems someone at TI has mistaken how NVIC works as ARM Cortex documents suggest it should.

We need 8 priority groups 0x0-0xE0 (5:3 split) with minimum 8 sub priory levels (0-7) within each grouping. It seems Tivaware IntPrioritySet() limits NVIC to 1 group with 8 sub priorities in conflict with table 3-9. It seems we can't make the call but one time to IntPriorityGroupingSet(2 or 4) again each one restricts us to only one group, not 8 separate groups as table 3-9 indicates.    

Accordingly what seems to occur as a result of asserting higher priority interrupt groupings they incorrectly speed up lower priority tail chaining relative to the higher priority asserts with that group. 

//*****************************************************************************
//
// The following are defines for the bit fields in the NVIC_APINT register.
//
//*****************************************************************************
#define NVIC_APINT_VECTKEY_M    0xFFFF0000  // Register Key
#define NVIC_APINT_VECTKEY      0x05FA0000  // Vector key
#define NVIC_APINT_ENDIANESS    0x00008000  // Data Endianess
#define NVIC_APINT_PRIGROUP_M   0x00000700  // INT Priority Grouping     Pri[Bits]  SubPri[Bits]
#define NVIC_APINT_PRIGROUP_7_1 0x00000000  // Priority group 7.1 split, ARM [7:1]    [0]
#define NVIC_APINT_PRIGROUP_6_2 0x00000100  // Priority group 6.2 split, ARM [7:2]   [1:0]
#define NVIC_APINT_PRIGROUP_5_3 0x00000200  // Priority group 5.3 split, ARM [7:3]   [2:0]
#define NVIC_APINT_PRIGROUP_4_4 0x00000300  // Priority group 4.4 split, ARM [7:4]   [3:0]
#define NVIC_APINT_PRIGROUP_3_5 0x00000400  // Priority group 3.5 split, ARM [7:5]   [4:0]
#define NVIC_APINT_PRIGROUP_2_6 0x00000500  // Priority group 2.6 split, ARM [7:6]   [5:0]
#define NVIC_APINT_PRIGROUP_1_7 0x00000600  // Priority group 1.7 split, ARM  [7]     [6:0]
#define NVIC_APINT_PRIGROUP_0_8 0x00000700  // Priority group 0.8 split, ARM  [0]     [7:0]
#define NVIC_APINT_SYSRESETREQ  0x00000004  // System Reset Request
#define NVIC_APINT_VECT_CLR_ACT 0x00000002  // Clear Active NMI / Fault
#define NVIC_APINT_VECT_RESET   0x00000001  // System Reset

  • The ARM documentation is describing a feature that is not in the NVIC of the TM4C parts. The NVIC on the TM4C parts only uses the upper three bits to determine one of eight priority levels as described in the datasheet and the TivaWare Peripheral Driver Library User's Guide.
  • I believe there is a cure for interrupt sub priority grouping conundrum.

    Seemingly the mistake; APINT REG58 informs NVIC of constrained split order indicated in the 8 bit fields of INT Priority (0-113) as indicated ARM B3.4.9. The TM4C datasheet shows lower bits in each byte as reserved but should contain the sub priority level nibble also defined by REG58. IntPrioritySet() only configures upper 3 bits for each group 0-7. Never sets the interrupt priority level (0-7) in the lower nibble bits [2:0] of the byte split as indicted REG58.

    Even if TM4C129 NVIC implementation restricts group priority to only 3 bits it still has to set the Interrupt SUB priority level (0-7) for the 8 groups indicated by the upper bits of the byte. The lower nibble of INTA, INTB, INTC, INTD are not being set as B3.4.9 indicates. The 8 groupings are indicated by the 3 upper bits and level by the split as indicated by REG58, also in the lower nibble [2:0] of each interrupt byte (REG24 - REG52). Effectively IntPrioritySet() configures groups (0x0-0xE0) and fails to set any sub priority interrupt levels (0-7) in Tivaware 3:5 split. Instead Table 3-9 would have you believe NVIC orders interrupts sub priority by it's bit weight only. That simply does not work and tail chaining fights back by preempting pends out of perceived hierarchy order.

  • HI Bob,

    TM4C129 NVIC still has to abide by the ARM programmers guide. Otherwise disclose all information that pertains to changes made to NVIC that conflict with ARM M4v7 documentation! Table 3-9 does not properly disclose any such information and instead appears to have misunderstood how NVIC functions in Bit Field splitting of interrupt priority order.

    TI can not change how NVIC handles interrupt sub priority order within groups as defined by ARM Cortex documentation relative to the subject matter. So it seems the TM4C1294 datasheet table 3-9 incorrectly conveys how NVIC interrupt priority groupings should be as defined by ARM Cortex M4v7 programmers guide. Deny as you will there is a big fish issue here that deserves better answers and seeming fixes to Tivaware IntPrioritySet() function.
  • Hi Bob,

    I was typing when you posted and crossed each other.

    Bob Crosby said:
    The ARM documentation is describing a feature that is not in the NVIC of the TM4C parts

    No where in ARM Cortex M4v7 guides are NVIC grouping order (AIRCR) specified as being specifically a feature, REG58 attempts to deceive. Besides REG58 only specifies the split for the lower nibbles of each byte in Interrupt Priority registers. It does not say vendors can change the bit field from the way ARM has specified the layout in their silicon. The interrupt priority registers are specified as belonging to ARM interrupt architecture, not the vendors. Seemingly TM4C1294 peripherals added to AHB by vendors can only use/access the registers existing in the ARM core silicon.

  • Bob Crosby said:
    The NVIC on the TM4C parts only uses the upper three bits to determine one of eight priority levels as described in the datasheet and the TivaWare Peripheral Driver Library User's Guide.

    That would seemingly never set NVIC interrupt sub priority levels for each peripheral and in the process it only sets group (0-7) priority upper nibble. NVIC tail changing can not properly order pends of lower priority groups as higher priority group peripheral interrupts partake AHB arbitration periods, stumbles like drunken sailor. Surely not a perceived configuration by some mad scientist to circumvent NVIC interrupt priority handling as designed by ARM.

    Again each interrupt has 256 levels of priority by M4v7 NVIC design and 224 is the highest binary value, 3 bits REG58 limits 8 groupings via upper nibble of interrupt priority field. Yet never assigns any interrupt priority bits [2:0] lower nibble of each byte field. Obviously the datasheet writer or someone has misunderstood the interrupt priority level field bits [2:0] still has to be programmed as ARM cortex programmers guide indicates. Seemingly TI can't reserve the interrupt priority field bit space contrary to NVIC design or it does not function as intended.

    Below are interrupt priority groupings for NVIC 5:3 split as described by ARM Cortex M4v7 programmers guide. Seemingly how Tivaware should set primary group and sub interrupt priority orders for TM4C1294 but does not configure lower nibble. The INT bit weights don't work for 1 sub priority interrupts (table 3-9) when tail chaining pends across contexts of the same priority group. So it must be Tivaware configuration related issue as we all know the ARM M4v7 NVIC silicon is flawless.

    0x00 - 0x07 | 0x20 - 0x27 | 0x04 - 0x47 | 0x60 - 0x67 | 0x80 - 0x87 | 0xA0 - 0xA7 | 0xC0 - 0xC7 | 0xE0 - 0xE7

  • BP101,

    TI did not change the ARM NVIC. ARM changed it. The TM4C devices were designed before the latest M4 NVIC was available. You are looking at the wrong ARM document. See: http://infocenter.arm.com/help/topic/com.arm.doc.dui0553b/DUI0553.pdf section 4.2.7.

    If you expand the NVIC portion of the register window and write 0xFF to one of the bytes of the NVIC_PRIn registers, you will see it reads back as 0xE0. Only the three most significant bits of the priority register are implemented in this NVIC. This is just as we documented in the datasheet and what is supported in the TivaWare drivers. 

    If you require additional priority levels, or the use of sub-priorities, you need to get an M4 from a different supplier.

  • Bob Crosby said:
    You are looking at the wrong ARM document

    Hi Bob,

    I think that is not true since CCS compiler has M4v7 (version 7) CPU, compile all projects for (TM4C1294).  IOT project example comes on EVM Launch Pad also shows M4v7 core. If NVIC was a different version inside TM4C1294 example projects should have some other ARM version number other than M4v7. Yet every example project indicates ARM M4v7 being the Core and that is the ARM document pages I have indicated this/other threads.

    The problem seems to be the low bits of Tivaware [3:5] split can not be RAZ and [7:5] split don't really exist M4v7 ARM Cortex. Table 3-9 row 1 has incorrect exception ordering for M4v7 core, exception number sub priority properly works via 1 group only, not 8 via crazy idea to RAZ lower nibble. ARM seems to leave out detail Tail Chaining will not correctly preempt via multiple primary groups if we RAZ sub priory bits [4:0]. With so many peripheral interrupts TM4c1294 is it not prudent to have multiple Primary groups (0-7) with (0-7) sub priority exception handling?

    Row 1 table 3-9 shows NONE sub priority bits and contradicts with 1 sub priory. NVIC seemingly will not produce correct synchronous application interrupt handling of APB arbitration with multiple group priority and exception number being 1 sub priority. Perhaps the primary issue multiple primary groups 0x00-0xE0 and 1 sub priority has unordered Asynchronous preemptions from higher priority groups preempting original Tail Chaining in lower priority groups, 1st order calls to MSP. That seemingly occurs result of multiple primary groups and RAZ lower order nibble [4:0] in [3:5] splits not [7:5] that don't even exist in TM4C1294 with ARM Cortex M4v7.

  • Hi Bob,

    Notice I keep saying [3:5] Tivaware 2.1.1.71 (hw_nvic.h) had not been updated to indicate M4v7 binary split points. That further confuses the entire issue, define notes conflict TM4C1294 datasheet table 3-9. The ARM document link you posted has more info about group priority preemptions bit field split, page 4-18. I'm not disputing TI has chosen to only allow upper 3 bits table 3-9 but the lower nibble of the binary split seems prudent for TM4C1294 126 interrupts and NVIC to properly assert synchronous preemptions for application instruction decode via MSP ordering. Perhaps ARM is not aware truncating lower sub priority bits of binary split causes mayhem APB arbitration as multiple vendor peripherals are preempting for synchronous CPU time via 120MHz SYSCLK ticks?

    Seemingly NVIC is not properly ordering MSP playback for Primary group tail chaining preemptions when NONE Sub Priority being defined via bits (yellow box) [7:5].  It would seem only one primary group can exist for 1 sub priority to maintain MSP order and not incorrectly accelerate NVIC preemptions in the process. If that is an artifact of instruction decode bursting or read ahead, something ain't working quite right in a multi primary group scenario.   Note: Changed above post to [3:5] split to keep consistent RAZ [4:0] sub priority bits Tivaware example projects

      

  • If table 4-18 (Note red) is true then why 1 sub priority, table 3-9 above? Seemingly that is a false narrative, does not properly work M4v7 with 23 peripheral exceptions. This issue seems to involve M4v7 NVIC handling of peripheral exceptions succeeding without sub priority bit splits [4:0] field being defined, especially for GPTM, PWM0, ADC0.

    Seemingly peripherals have NVIC latency issues revolving around subpriority exception ordering and APB arbitration timing keeping reasonably synchronous 120MHz SYSCLK and or CPU instruction decode. Seemingly 20-120Hz CCP edge count interrupts in 500ms intervals should never be an issue for M4v7 NVIC. Yet it fails and may randomly fault the MCU when CCP edge counts and enabling GPTM Oneshot that shares a single variable between to priority ordered exception contexts. Teacher always tells us to Single file through door way on a fire drill.
  • Let me try explaining the NVIC.

    ARM created an NVIC that supports a configurable number of bits, up to 8, to determine the priority and sub-priority. In the TI implementation for the TM4C parts, we implemented the NVIC with 3 bits for the priority level, bits 7 through 5. Bits 4 through 0 always read 0. That gives you 8 different priority levels. Those 8 levels can be configured by the NVIC_APINT register to be 8 priority levels with each level having a single sub level. (This may be what is confusing you. A single sub level is saying that within that priority group, all of the interrupts are at the same level. Just like not having a sub-priority.) The other three options are 4:2,  four priority groups and two sub-priority groups; 2:4, two priority groups and four sub-priority groups; or 1:8, all interrupts at the same priority level, but 8 different sub-priority groups.

    When multiple interrupts are pending, interrupts from a lower priority group number will go first. They will preempt an interrupt service routine with a higher priority group number. If two pending interrupts are in the same priority group, the request from the lower sub-priority group number will be taken first. An interrupt request will not preempt an interrupt routine that is in the same priority group even if its sub-priority number is lower.  When two interrupt requests are in the same sub-priority group, the request with the lowest exception number will be taken first.

    So what does that mean. In the default configuration (8:1), An interrupt with a lower priority number can preempt an interrupt service routine from an interrupt at a higher priority number. Interrupts at the same priority are executed in order of the exception number, the lowest number being the highest priority. The exception number can be found by looking at the hw_ints.h file in TivaWare.  For this part, GPIOA is number 16, GPIOB is number 17, GPIOC is number 18, GPIOD is number 19 ... . By default, all are at priority level 0. If interrupts from GPIOA and GPIOB come at the same time, the interrupt from GPIOA will be serviced first since it has the lower number. That interrupt routine will finish and tail (not return to the main code) into the interrupt routine for GPIOB.

    Now lets say that we want to make GPIOB a higher priority interrupt that can preempt a GPIOA interrupt routine. Then call:

        IntPrioritySet(INT_GPIOA, 1u << 5u);
    

    This will set GPIOA interrupts to priority level 1, leaving GPIOB interrupts at priority level 0. Note that we have to do the "<< 5" because the three bits implemented for priority are bits 7:6.  Of course you could use a define to make the "1u << 5u" more readable such as:

    #define INT_PRIORITY_LEVEL1 (1u<<5u)
    

    Now lets say I want GPIOC to be serviced before GPIOA, but not to preempt it. However, I still want GPIOB to preempt either one. This is where I use sub-priorities. I used #define for readability, but notice that GPIOA is set to level 3, GPIOC is set to level 2 and GPIOB is left at level 0. Since the least significant bit is for sub-priorities, levels 2 and 3 are now in the same priority, but different sub-priorities:

    #define INT_PRI1_SUB0 ((1u<<6u) | (0u<<5u))
    #define INT_PRI1_SUB1 ((1u<<6u) | (1u<<5u))
    
        // 2 bits priority, 1 bits sub-priority 4:2
        IntPriorityGroupingSet(2u);
        IntPrioritySet(INT_GPIOA, INT_PRI1_SUB1);
        IntPrioritySet(INT_GPIOC, INT_PRI1_SUB0);
    

     I hope this clears it up.

  • Hi Bob,

    Bob Crosby said:
    Those 8 levels can be configured by the NVIC_APINT register to be 8 priority levels with each level having a single sub level. (This may be what is confusing you. A single sub level is saying that within that priority group, all of the interrupts are at the same level

    Not really confusing it just don't seem to work as described and lower priority groups with much slower interrupts 20-200Hz speed up when the faster interrupt priorities somehow speed up NVIC. That messes with preset times between interrupt context used to determine edge (count/times) in the same priority groups with 1 subpriority, the exception number is not regulating the nesting speed synchronous with the application. This grouping method is the same we used with M3 NVIC in the Stellaris but with more priority groups. However the timers in question and interrupt context exceptions exist at the same lower priority level 0x40. Only the faster peripherals such as PWM0 and ADC0 and 1 Sequencer exist at 1 priority level higher 0x20.

    To increase priority control in systems with interrupts, the NVIC supports priority grouping. This divides each interrupt priority register entry into two fields:

    • an upper field that defines the group priority

    • a lower field that defines a subpriority within the group.

    Only the group priority determines preemption of interrupt exceptions. When the processor is executing an interrupt exception handler, another interrupt with the same group priority as the interrupt being handled does not preempt the handler, 

    "That has been proven untrue as Edge counter exception was disabled and still allowed re-entry before it was re-enabled 500ms later by TBILR load value in a conjoining context, GPTM0B with GPTM03 Oneshot also 1st synchronized."

    If multiple pending interrupts have the same group priority, the subpriority field determines the order in which they are processed. If multiple pending interrupts have the same group priority and subpriority, the interrupt with the lowest IRQ number is processed first.

    The problem of each timer mode speeding up may not be related to NVIC priority handling. Again even the edge times of GPTM and Systick are not keeping reasonably consistent handler execution as nothing new is occurring. 

    Bob Crosby said:
    Since the least significant bit is for sub-priorities, levels 2 and 3 are now in the same priority, but different sub-priorities:

    Yet there are NONE sub priory bits in the 7:5 split (bxxx.NONE) only the 8 priority groups and 1 sub priority are interrupt exception numbers in the priority split groups, Table 3-9. So your saying 2u grouping 1 extra sub priority bit but the application has nearly 26 interrupts and split (bxx.y), e.g. 0x80/0xE0 will never work for 7 other priority groups with many more exceptions. Again is not hard to imagine TM4C1294 M4v7 would RAZ the lower nibble [4:0] when there are 126 interrupts? How could that have happened or maybe what I am describing below has nothing to do with NVIC? I don't believe we can switch between several bit splits in RE58 and maintain 8 priority groups, sadly makes your 2u split point a bit obscure in this issue.

    Posted new issue for edge time capture failures:

     

     

  • BTW: Your 4:0 two priorities INT_PRI_SUB0 = 0x80 and INT_PRI_SUB1= 0xE0. Also part of the 7:5 split  8 primary groups. Two priority 1 sub bit for 126 interrupts is indeed sad.  Again 26 interrupts 8 groups 7:5 split is the topology interrupt exception ordering. This ain't no example application, it is a real world device and edge counts/times seem impossible to maintain. 

  • As you can see there are many more than simply 2u sub priorities. And to further dispute 16-32 sub priorities would have produced superior NVIC handling results over that of 1 sub priory (bxxx.NONE). My vote is for 16 minimum even better 32 - why not when each exception can assert 256 levels of priority?

    Seemingly TM4C1294 M4v7 has foolishly limited AIRCR PRIGROUP field split to 3 bits by the addition of embedded code by factory. Someone higher up the chain is unaware simple minded 3 bit split causes issues with NVIC nesting and tail chaining limited 1 sub priory handling. This case 5 enabled GPTM all competing for CPU time slice and keeping NVIC nesting and MSP stacking order synchronous to/with AHB arbitration of application code in those handlers.
  • Back tracking reveals Stellaris LM3S8971 M3 Cortex NVIC had the very same priority grouping as Tiva M4v7 Cortex NVIC. Again very strange the exact same limitation of interrupt subpriority field bits [7:5] , though TM4C1294 has 3x the number of peripherals.

    The deception making priority order suspect was edge counts always produce exact match count results (GPTM_TnR) regardless the frequency at CCP input. Otherwise the acceleration of edge count interrupts accelerates as a result of frequency change from higher priority groups asserting interrupts. Thus AHB frequency noise either internally or externally seems the issue with count acceleration and source of noise input pins of intrusion remains opaque.