2013-10-05 07:11 AM
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
2013-10-06 07:25 AM
2013-10-06 09:01 AM
Consider what code is actually being generated, and if it would be appropriate to use ''volatile'' variables?
2013-10-07 10:09 AM
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;
}
2013-10-07 10:09 AM
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.
2013-10-07 11:02 AM
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 */
2013-10-07 01:50 PM
Hi,
The source that you attached is the original one. I had the same. but if you callNVIC_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. LaszloDefinitely 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 */
2013-10-07 06:57 PM
I've pushed this into the moderators