STM32F4 (I2S) - how to properly configure DMA1_Stream7_IRQHandler priority?

robbo1975 wrote on Monday, September 05, 2016:

Hi
Last week I started porting Helix mp3 decoder to FreeRTOS enviroment and I stuck on DMA1_Stream7_IRQHandler. Inside the interrupr routine I release transmission complete semaphore by xSemaphoreGiveFromISR (xSemaphoreTC, &xHigherPriorityTaskWoken). Calling of this function causes permanent stuck inside vPortValidateInterruptPriority( void ). I know the problem is related to the priorities, but i can’t solve it by myself. Is there any helping hand? By the way, i’m rookie to FreeRTOS. :slight_smile:

Dma configuration code

void DMA1_Stream7_cfg ()
{
	DMA_InitTypeDef DMA_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_DMA1, ENABLE);

	DMA_DeInit (DMA1_Stream7);
	DMA_InitStructure.DMA_Channel = DMA_Channel_0;
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & SPI3->DR;
	DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;

	DMA_InitStructure.DMA_Memory0BaseAddr = 0;
	DMA_InitStructure.DMA_BufferSize = 0;

	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
	DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
	DMA_Init (DMA1_Stream7, &DMA_InitStructure);

	/* Config the DMA Stream IRQ Channel */
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream7_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init (&NVIC_InitStructure);
	/* Enable DMA request after last transfer (Single-ADC mode) */
	DMA_ITConfig (DMA1_Stream7, DMA_IT_TC, ENABLE);
	NVIC_EnableIRQ (DMA1_Stream7_IRQn);
}

DMA Irq

void DMA1_Stream7_IRQHandler ()
{
	BaseType_t xHigherPriorityTaskWoken;
	xHigherPriorityTaskWoken = pdFALSE;

	if (DMA_GetITStatus (DMA1_Stream7,DMA_IT_TCIF7) != RESET)
	{
		DMA_ClearITPendingBit (DMA1_Stream7, DMA_IT_TCIF7);
       /* and after that kernel hangs in vPortValidateInterruptPriority( void ) */
        xSemaphoreGiveFromISR (xSemaphoreTC, &xHigherPriorityTaskWoken);
		wait = 0;
	}
	portYIELD_FROM_ISR (xHigherPriorityTaskWoken);
}

and code fired transmission

	if (buff_ready)
			{
				DMA1_Stream7->NDTR = buff_len;
				DMA1_Stream7->M0AR = (uint32_t) buff;
				DMA1_Stream7->CR |= DMA_SxCR_EN;
				buff_nr ^= 1;
				
				while (xSemaphoreTake (xSemaphoreTC, (TickType_t) 20) == pdFALSE)
				{
					vTaskDelay(1);
				}

Regards
Krzysztof Sroka

rtel wrote on Monday, September 05, 2016:

I suspect your problem will be with this line:

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =
configMAX_SYSCALL_INTERRUPT_PRIORITY;

which is using an unshifted priority value (the priority bits are
already set in the most significant bits) - whereas you probably need to
use an unshifted value (whereas the priority bits are set in the least
significant bits). See the following link for more details:

DMA1_Stream7_IRQHandler

In this handler it would be more efficient to use a direct to task
notification than a semaphore.

robbo1975 wrote on Monday, September 05, 2016:

So that any use of NVIC_Init () will cause mess up with priorities?

Regards
Krzysztof Sroka

rtel wrote on Monday, September 05, 2016:

I’m not sure what more I can say over what I already mentioned in my
last email as I have already pointed out the line in your code that I
think is wrong. Perhaps you should grep NVIC_InitTypeDef in the
FreeRTOS/demo directory to see examples of how the structure is being
used (be careful to see how the FreeRTOS code is actually using it,
rather than uses within the ST code itself).

robbo1975 wrote on Monday, September 05, 2016:

Heh, the most confusing thing is that I have the same mechanism used in my previus project. The diference is is only in peripherials, where data was transferred form ADC to ram buffer.

void DMA2_Stream0_IRQHandler (void)
{
	BaseType_t xHigherPriorityTaskWoken;

	xHigherPriorityTaskWoken = pdFALSE;

	if (DMA_GetITStatus (DMA2_Stream0, DMA_IT_TCIF0))
	{
		DMA_ClearITPendingBit (DMA2_Stream0, DMA_IT_TCIF0);
		TIM_Cmd (TIM2, DISABLE);
		xSemaphoreGiveFromISR (xSemaphore, &xHigherPriorityTaskWoken);
		GPIO_ToggleBits( GPIOD, GPIO_Pin_8);
	}

	if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TEIF0))
	{
		DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TEIF0);
		xSemaphoreGiveFromISR (xSemaphore, &xHigherPriorityTaskWoken);
	}
	portYIELD_FROM_ISR (xHigherPriorityTaskWoken);
}

and init

    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 13;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 13;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init (&NVIC_InitStructure);

Code above works perfectly. Weird…

Regards
Krzysztof Sroka

robbo1975 wrote on Monday, September 05, 2016:

I have tested now pri and subpri set to 13. Nothing changes.

Regards
Krzysztof Sroka

rtel wrote on Monday, September 05, 2016:

I have tested now pri and subpri set to 13. Nothing changes.

Please read the page I linked to in my first reply, and look at the
examples in the download. This is still wrong.

robbo1975 wrote on Monday, September 05, 2016:

Mea culpa… I had incorrectly defined parameters configKERNEL_INTERRUPT_PRIORITY and configMAX_SYSCALL_INTERRUPT_PRIORITY in FreeRTOSConfig.h. :confused:
Thank you very much for help! I’m tired of this and I read without understanding the content…
Finally everything work ok.

Regards
Krzysztof Sroka