cancel
Showing results for 
Search instead for 
Did you mean: 

USART DMA FIFO error and multi level interrupt problem-STM32F4-discovery

vitez
Associate II
Posted on October 05, 2013 at 16:11

Hello everybody,

I try to use USART2 with DMA, but I have two problems. Now the code just sends back the received word. The memory is word based so I use the DMA controller packing/unpacking feature. My first problem is everytime when a transfer occures the FEIF6 bit of the DMA1 HISR register is set. I have tried send only one bytes when the memory was byte based as well, but this flag have been set as well. By the way, the device sends the data back perfectly I just do not understand why this bit is set.

As you can see the memory is word based, so one communication cycle includes four UART transfer. A timer guards that this cycle can't stuck in. My second problem is if the timer generates an interrupt the execution never jumps to DMA1_Strem5_IRQHandler from the timer interrupt body, although it has a higher priority and the TCIF flag have been set. It seem the multi-level interrupt doesn't work properly.

I would be very gratefull if someone could help me! These issues make me crazy...

#define PERIPH_BUFF_SIZE 1 


typedef
uint32_t PeripheralBufferType; 

PeripheralBufferType Periph_InputData[PERIPH_BUFF_SIZE]; 

PeripheralBufferType Periph_OutputData[PERIPH_BUFF_SIZE]; 

#define SafeUartTransfer() while(USART_GetFlagStatus(USART2,USART_FLAG_TC)!=SET);\ 

USART_ClearFlag(USART2,USART_FLAG_TC);\ 

DMA_Cmd(DMA1_Stream6,ENABLE); 

bool
transferInProgress=
false
; 

bool
USART_DMA_frame_error=
false
; 

void
TIM2_IRQHandler() 

{ 

if
(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET) 

{ 

TIM_ClearITPendingBit(TIM2,TIM_IT_Update); 

if
(transferInProgress) 

{ 

USART_DMA_frame_error=
true
; 

DMA_Cmd(DMA1_Stream5,DISABLE); 

DMA_Cmd(DMA1_Stream5,ENABLE); 

while
(USART_DMA_frame_error); 

transferInProgress=
false
; 

++USART_DMA_frame_error_cnt; 

STM_EVAL_LEDToggle(LED6); 

} 

else
if
(DMA_GetCurrDataCounter(DMA1_Stream5)!=PERIPH_BUFF_SIZE*
sizeof
(PeripheralBufferType)) 

transferInProgress=
true
; 

} 


} 


void
DMA1_Stream5_IRQHandler() 

{ 

if
(DMA_GetITStatus(DMA1_Stream5,DMA_IT_TCIF5)) 

{ 

transferInProgress=
false
; 

DMA_ClearITPendingBit(DMA1_Stream5,DMA_IT_TCIF5); 

DMA_ClearITPendingBit(DMA1_Stream5,DMA_IT_HTIF5); 

if
(!USART_DMA_frame_error) 

{ 

InputAction(); 

for
(
int
j=0;j<PERIPH_BUFF_SIZE;++j) 

{ 

Periph_OutputData[j]=Periph_InputData[j]; 

} 

STM_EVAL_LEDToggle (LED5); 

DMA_Cmd(DMA1_Stream5,ENABLE); 

SafeUartTransfer(); 

} 

else

USART_DMA_frame_error=
false
; 

} 

} 

void
DMA1_Stream6_IRQHandler() 

{ 

if
(DMA_GetITStatus(DMA1_Stream6,DMA_IT_TCIF6)) 

{ 

DMA_ClearITPendingBit(DMA1_Stream6,DMA_IT_TCIF6); 

DMA_ClearITPendingBit(DMA1_Stream6,DMA_IT_HTIF6); 

if
(DMA_GetFlagStatus(DMA1_Stream6,DMA_IT_FEIF6)==SET) 

STM_EVAL_LEDOn(LED6); 

else

STM_EVAL_LEDOff(LED6); 

DMA_ClearITPendingBit(DMA1_Stream6,DMA_IT_FEIF6); 

} 

} 


void
USART2GPIOInit() 

{ 

GPIO_InitTypeDef InitStructure; 

//enable peripherial clock 

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 


GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2); 

GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2); 



InitStructure.GPIO_Mode=GPIO_Mode_AF; 

InitStructure.GPIO_OType=GPIO_OType_PP; 

InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL; 

InitStructure.GPIO_Speed=GPIO_Speed_25MHz; 

InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_3; 

GPIO_Init(GPIOA,&InitStructure); 

} 

void
USART2Init() 

{ 

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); 


USART_InitTypeDef InitStructure; 



InitStructure.USART_BaudRate=115200; 

InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None; 

InitStructure.USART_Mode=USART_Mode_Rx | USART_Mode_Tx; 

InitStructure.USART_Parity=USART_Parity_No; 

InitStructure.USART_StopBits=USART_StopBits_1; 

InitStructure.USART_WordLength=USART_WordLength_8b; 


USART_Init(USART2,&InitStructure); 

} 


void
USART2DMAAndIRQInitRx() 

{ 

DMA_InitTypeDef DMAInitStructure; 

NVIC_InitTypeDef NVIC_InitStructure; 


RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE); 


DMA_DeInit(DMA1_Stream5 ); 

while
(DMA_GetCmdStatus(DMA1_Stream5 ) != DISABLE); 


DMAInitStructure.DMA_BufferSize=PERIPH_BUFF_SIZE*
sizeof
(PeripheralBufferType);
//because it depends on the pripheral data size 

DMAInitStructure.DMA_Channel=DMA_Channel_4; 

DMAInitStructure.DMA_DIR= DMA_DIR_PeripheralToMemory; 

DMAInitStructure.DMA_FIFOMode=DMA_FIFOMode_Enable; 

DMAInitStructure.DMA_FIFOThreshold=DMA_FIFOThreshold_1QuarterFull; 

DMAInitStructure.DMA_Memory0BaseAddr=(uint32_t) &Periph_InputData; 

DMAInitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single; 

DMAInitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Word; 

DMAInitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable; 

DMAInitStructure.DMA_Mode=DMA_Mode_Normal; 

DMAInitStructure.DMA_PeripheralBaseAddr=(uint32_t)&USART2->DR; 

DMAInitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single; 

DMAInitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte; 

DMAInitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable; 

DMAInitStructure.DMA_Priority=DMA_Priority_Medium; 


DMA_Init(DMA1_Stream5,&DMAInitStructure); 



DMA_ITConfig (DMA1_Stream5, DMA_IT_TC, ENABLE); 
// Transfer complete interrupt mask 


NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn; 

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 

NVIC_Init (&NVIC_InitStructure); 


USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE); 


DMA_ClearFlag(DMA1_Stream5, DMA_FLAG_TCIF5 ); 

DMA_Cmd(DMA1_Stream5,ENABLE); 

} 

void
USART2DMAAndIRQInitTx() 

{ 

DMA_InitTypeDef DMAInitStructure; 

NVIC_InitTypeDef NVIC_InitStructure; 


DMA_DeInit(DMA1_Stream6 ); 


while
(DMA_GetCmdStatus(DMA1_Stream6 ) != DISABLE); 


DMAInitStructure.DMA_BufferSize=PERIPH_BUFF_SIZE*
sizeof
(PeripheralBufferType); 

DMAInitStructure.DMA_Channel=DMA_Channel_4; 

DMAInitStructure.DMA_DIR= DMA_DIR_MemoryToPeripheral; 

DMAInitStructure.DMA_FIFOMode=DMA_FIFOMode_Enable; 

DMAInitStructure.DMA_FIFOThreshold=DMA_FIFOThreshold_1QuarterFull; 

DMAInitStructure.DMA_Memory0BaseAddr=(uint32_t) &Periph_OutputData; 

DMAInitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single; 

DMAInitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Word; 

DMAInitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable; 

DMAInitStructure.DMA_Mode=DMA_Mode_Normal; 

DMAInitStructure.DMA_PeripheralBaseAddr=(uint32_t)&USART2->DR; 

DMAInitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single; 

DMAInitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte; 

DMAInitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable; 

DMAInitStructure.DMA_Priority=DMA_Priority_Medium; 


DMA_Init(DMA1_Stream6,&DMAInitStructure); 

DMA_ITConfig (DMA1_Stream6, DMA_IT_TC, ENABLE); 
// Transfer complete interrupt mask 


NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn; 

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 

NVIC_Init (&NVIC_InitStructure); 


USART_DMACmd(USART2,USART_DMAReq_Tx,ENABLE); 


DMA_ClearFlag(DMA1_Stream6, DMA_FLAG_TCIF6 ); 


} 


/** 

* @brief Initiates timer 2 * @param None 

* @retval None 

*/

void
TMR2Init() 

{ 

TIM_TimeBaseInitTypeDef def; 

NVIC_InitTypeDef NVIC_InitStructure; 


SystemCoreClockUpdate(); 

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); 


def.TIM_ClockDivision=0; 

def.TIM_CounterMode=TIM_CounterMode_Down; 

def.TIM_Period=SystemCoreClock/2-1; 

def.TIM_RepetitionCounter=0; 

def.TIM_Prescaler=0; 

TIM_TimeBaseInit(TIM2,&def); 



TIM_ClearITPendingBit(TIM2,TIM_IT_Update); 

TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); 


NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn; 

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; 

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; 

NVIC_InitStructure.NVIC_IRQChannelSubPriority=1; 

NVIC_Init(&NVIC_InitStructure); 


TIM_Cmd(TIM2,ENABLE); 


} 


void
main() 

{ 

NVIC_SetPriorityGrouping(NVIC_PriorityGroup_3); 

TMR2Init(); 

USART2GPIOInit(); 

USART2Init(); 

USART2DMAAndIRQInitRx(); 

USART2DMAAndIRQInitTx(); 

USART_Cmd(USART2,ENABLE); 

while
(1); 


}

#usart-fifo-dma-interrupt
7 REPLIES 7
vitez
Associate II
Posted on October 06, 2013 at 16:25

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6Zx&d=%2Fa%2F0X0000000br7%2FeTqhLqBa0f.h0y8AE0fx8nJ392OR_nUrNmqc6wWMvrQ&asPdf=false
Posted on October 06, 2013 at 18:01

Consider what code is actually being generated, and if it would be appropriate to use ''volatile'' variables?

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
vitez
Associate II
Posted on October 07, 2013 at 19:09

Hello again,

Thanks for the answer, it inspired me to watch the asm code... There is a bug inside the core_cm4.h header in the NVIC_SetPriorityGrouping function. The problem is the PriorityGroupTmp register have masked inappropriately hence the priority group information (inside the core AIRCR register)remains zero regardless from the PriorityGroup parameter. The result is the multiple level interrupt handler of the core can't be used. Please see below the solution. By the way I wonder that problem haven't emerged former...I belived the multilevel interrupt is commonly used...

__STATIC_INLINE 
void
NVIC_SetPriorityGrouping(uint32_t PriorityGroup) 
{ 
uint32_t reg_value; 
uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x0700); 
/* only values 0..7 are used */
reg_value = SCB->AIRCR; 
/* read old register configuration */
reg_value &= ~(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk); 
/* clear bits to change */
reg_value = (reg_value | 
((uint32_t)0x5FA << SCB_AIRCR_VECTKEY_Pos) | 
PriorityGroupTmp); 
/* Insert write key and priorty group */
SCB->AIRCR = reg_value; 
}

vitez
Associate II
Posted on October 07, 2013 at 19:09

I forgot to mention this only can results a problem when you use NVIC_PriorityGroup_x macros as params in function call. If you use numbers between 0...7 according to the core datasheet, the function works properly without the modification.

Posted on October 07, 2013 at 20:02

Definitely some discontinuity here, different core_cm4.h apparently,

* @file core_cm4.h
* @brief CMSIS Cortex-M4 Core Peripheral Access Layer Header File
* @version V3.20
* @date  February 2013
/** \brief Set Priority Grouping
The function sets the priority grouping field using the required unlock sequence.
The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field.
Only values from 0..7 are used.
In case of a conflict between priority grouping and available
priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set.
\param [in] PriorityGroup Priority grouping field.
*/
__STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
{
uint32_t reg_value;
uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07); /* only values 0..7 are used */
reg_value = SCB->AIRCR; /* read old register configuration */
reg_value &= ~(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk); /* clear bits to change */
reg_value = (reg_value |
((uint32_t)0x5FA << 
SCB_AIRCR_VECTKEY_Pos
) |
(PriorityGroupTmp << 8)); /* Insert write key and priorty group */
SCB->AIRCR = reg_value;
}

* @file misc.h
* @author MCD Application Team
* @version V1.2.0
* @date 11-September-2013
* @brief This file contains all the functions prototypes for the miscellaneous
* firmware library functions (add-on to CMSIS functions).
#define NVIC_PriorityGroup_0 ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
4 bits for subpriority */
#define NVIC_PriorityGroup_1 ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
3 bits for subpriority */
#define NVIC_PriorityGroup_2 ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
2 bits for subpriority */
#define NVIC_PriorityGroup_3 ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
1 bits for subpriority */
#define NVIC_PriorityGroup_4 ((uint32_t)0x300) /*!< 4 bits for pre-emption priority
0 bits for subpriority */

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
vitez
Associate II
Posted on October 07, 2013 at 22:50

Hi,

The source that you attached is the original one. I had the same. but if you call

NVIC_SetPriorityGrouping(

NVIC_PriorityGroup_x

)

it does not set the AIRCE reg correctly because

PriorityGroupTmp

will be zero. That is why I modified the function body. Laszlo

Definitely some discontinuity here, different core_cm4.h apparently,

* @file core_cm4.h
* @brief CMSIS Cortex-M4 Core Peripheral Access Layer Header File
* @version V3.20
* @date  February 2013
/** \brief Set Priority Grouping
The function sets the priority grouping field using the required unlock sequence.
The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field.
Only values from 0..7 are used.
In case of a conflict between priority grouping and available
priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set.
\param [in] PriorityGroup Priority grouping field.
*/
__STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
{
uint32_t reg_value;
uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07); /* only values 0..7 are used */
reg_value = SCB->AIRCR; /* read old register configuration */
reg_value &= ~(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk); /* clear bits to change */
reg_value = (reg_value |
((uint32_t)0x5FA << 
SCB_AIRCR_VECTKEY_Pos
) |
(PriorityGroupTmp << 8)); /* Insert write key and priorty group */
SCB->AIRCR = reg_value;
}

* @file misc.h
* @author MCD Application Team
* @version V1.2.0
* @date 11-September-2013
* @brief This file contains all the functions prototypes for the miscellaneous
* firmware library functions (add-on to CMSIS functions).
#define NVIC_PriorityGroup_0 ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
4 bits for subpriority */
#define NVIC_PriorityGroup_1 ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
3 bits for subpriority */
#define NVIC_PriorityGroup_2 ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
2 bits for subpriority */
#define NVIC_PriorityGroup_3 ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
1 bits for subpriority */
#define NVIC_PriorityGroup_4 ((uint32_t)0x300) /*!< 4 bits for pre-emption priority
0 bits for subpriority */

Posted on October 08, 2013 at 03:57

I've pushed this into the moderators

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..