STM32F103 priorities to handle nested interrupts

0

I could find a problem related to NVIC_Init in STM32F10x library related to priorities to handle nested interrupts. We know that any interrupt with a priority value equal or higher than BASEPRI ( 11 in our case) can call FromISR() FreeRTOS API functions.

FreeRTOS uses 15 level ( the lowest priority).

#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY    15

In other words, FreeRTOS allows us to call API fuctions ( see xQueueSendToBackFromISR) from ISR with 15-11 priority. When we initialize the NVIC we use level #11

#define    WRTU2_DMA1_SPI2_IRQ_PRIORITY     (configLIBRARY_KERNEL_INTERRUPT_PRIORITY-4*)
    /* DMA1 Channel4 interrupt setting */
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = WRTU2_DMA1_SPI2_IRQ_PRIORITY;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = WRTU2_DMA1_SPI2_IRQ_PRIORITY;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

So, we should be OK. But the problem exists. I decided to check NVIC_Init.

According to the information from STM32 datasheet the priority register is 0xe000e40e ( NVIC channel 14 belongs to DMA1_Channel4 interrupts).

And I could read 0x00 from that register after NVIC was initialized. It means NVIC channel #14 has the highest priority in the system.

And it causes all problems.

I added the simplest fix NVIC->IP[DMA1_Channel4_IRQn] = 0xF0; And the system does not fail anymore. So, our current problem is solved.

Of course, I tried to analyze what happens in NVIC_Init

**
  * @brief  Initializes the NVIC peripheral according to the specified
  *         parameters in the NVIC_InitStruct.
  * @param  NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains
  *         the configuration information for the specified NVIC peripheral.
  * @retval None
  */
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
{
  uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;

  /* Check the parameters */
  assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));
  assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));  
  assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));

  if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)
  {
    /* Compute the Corresponding IRQ Priority --------------------------------*/    
    tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
    tmppre = (0x4 - tmppriority);
    tmpsub = tmpsub >> tmppriority;

    tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
    tmppriority |=  NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
    tmppriority = tmppriority << 0x04;

    NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;

    /* Enable the Selected IRQ Channels --------------------------------------*/
    NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
      (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
  }
  else
  {
    /* Disable the Selected IRQ Channels -------------------------------------*/
    NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
      (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
  }
}

So, I added the similar test code to my application to see how it converts all values

uint32_t NVIC_IRQChannelPreemptionPriority=0xFF,NVIC_IRQChannelSubPriority=0xFF;
int32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;
tprintf("\n\rSCB->AIRCR=0x%08x",SCB->AIRCR);

 tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
 tprintf("\n\rtmppriority=0x%08x",tmppriority);
tmppre = (0x4 - tmppriority);
tmpsub = tmpsub >> tmppriority;

 tprintf("\n\rtmppre=0x%08x",tmppre);
 tprintf("\n\rtmpsub=0x%08x",tmpsub);


tmppriority = (uint32_t)NVIC_IRQChannelPreemptionPriority << tmppre;
tmppriority |=  NVIC_IRQChannelSubPriority & tmpsub;
tmppriority = tmppriority << 0x04;
tprintf("\n\rtmppriority=0x%08x",tmppriority);    

There is a log

SCB->AIRCR=0xfa050000
tmppriority=0x00000007
tmppre=0xfffffffd
tmpsub=0x00000000
tmppriority=0x00000000

Note, even I specify 0xFF for both input parameters it returns 0x00.

I am really surprised about that behavior. This is a library function.

People use it for many years. So, I am really confused I can find find the problem in that function.

Maybe it is related to Application interrupt and reset control register (SCB_AIRCR) Address offset: 0x0C Reset value: 0xFA05 0000 Required privilege: Privileged The AIRCR provides priority grouping control for the exception model, endian status for data accesses, and reset control of the system.

Note, in the library sources I can see #define AIRCR_VECTKEY_MASK ((uint32_t)0x05FA0000)

So, it looks like we have some kind of BIG vs LITTLE ENDIAN byte order in the 16-bit nibble.

Do you have any suggestion or knowledge about the problem?

c
interrupt
stm32
freertos
asked on Stack Overflow Dec 10, 2018 by erenbasturk • edited Dec 10, 2018 by erenbasturk

1 Answer

0

I found the problem, the problem is I should use NVIC_SetPriorityGrouping(3); as 3 for the cortex-m3.

then it provides 4-bit preemptive priority and 0 bit for subpriority. At final when I initiliase like that it works as I expected.

  /* DMA1 Channel4 interrupt setting */
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 11;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
answered on Stack Overflow Dec 12, 2018 by erenbasturk

User contributions licensed under CC BY-SA 3.0