STM32 DMA 传输错误同时设置 FIFO 和传输错误标志
STM32 DMA transfer error both FIFO and transfer error flags set
我有一个 STM32F769I-EVAL 配置为根据来自 ST AN4666. What I expect to happen is: the clock from my input device triggers the input capture DMA and writes data to SDRAM until my OC timer interrupt disables the transfer. At that point I can manipulate the data in SDRAM and transfer it elsewhere. However, after the hardware is configured and the input capture enabled I get a DMA transfer error. The value for errorcode (6) in the HAL_DMA_IRQHandler function shows that both FIFO and transfer error flags are set. According to my understanding of the datasheet 的代码接收 8 位并行数据(参见第 261 页)这应该是不可能的,我假设我在某处配置错误但是至于如何进行,我不知所措。我可以采取什么步骤来解决这个问题?
DMA 配置:
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_InitStruct;
static DMA_HandleTypeDef hdma_tim;
/* TIMx clock enable */
TIMx_CLK_ENABLE();
/* Enable DMA clock */
DMAx_CLK_ENABLE();
/* Enable TIM input GPIO clock */
TIMx_CHy_GPIOCLK_ENABLE();
/* Configure input of TIMx_CHy on AF */
GPIO_InitStruct.Pin = TIMx_CHy_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF_TIMx;
HAL_GPIO_Init(TIMx_CHy_PORT, &GPIO_InitStruct);
/* Set the parameters to be configured */
hdma_tim.Init.Channel = DMA_CHANNEL;
hdma_tim.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_tim.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE ; /* Reading in GPIO PC[7:0]*/
hdma_tim.Init.MemDataAlignment = DMA_MDATAALIGN_WORD ;
hdma_tim.Init.Mode = DMA_NORMAL; /* double memory buffer used */
hdma_tim.Init.Priority = DMA_PRIORITY_HIGH;
hdma_tim.Init.FIFOMode = DMA_FIFOMODE_ENABLE; /* using FIFO mode since memory datasize=32bit and GPIO=8bits in our case */
hdma_tim.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; /* flushing FIFO at each 32bit reception (4 data) */
hdma_tim.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_tim.Init.PeriphBurst = DMA_PBURST_SINGLE;
/* Set hdma_tim instance */
hdma_tim.Instance = DMA_STREAM;
/* Link hdma_tim to hdma[CC1] */
__HAL_LINKDMA(htim, hdma[TIMx_DMA_ID], hdma_tim);
/* Initialize TIMx DMA handle */
HAL_DMA_Init(htim->hdma[TIMx_DMA_ID]);
/* NVIC configuration for TIMx output compare interrupt */
HAL_NVIC_SetPriority(TIMx_IRQn, 0, 2);
HAL_NVIC_EnableIRQ(TIMx_IRQn);
/* Configure the NVIC for DMA */
/* NVIC configuration for DMA transfer complete interrupt */
HAL_NVIC_SetPriority(TIMx_DMA_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIMx_DMA_IRQn);
}
主要代码:
/* Initialize SDRAM */
BSP_SDRAM_Init();
/* Configure the Data GPIO in input mode */
Data_GPIO_Config();
/* Set Timers instance */
TimHandle.Instance = TIMx;
/* Initialize global Timer parameters */
TimHandle.Init.Period = MAX_COUNTER;
TimHandle.Init.Prescaler = TIMx_PRESCALER - 1;
TimHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.RepetitionCounter = 0;
if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
//Initialize Timer "OC" channel for OC mode
sOConfig.OCMode = TIM_OCMODE_TIMING/*TIM_OCMODE_TOGGLE*/;
sOConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
sOConfig.Pulse = NB_COUNTER_CYCLE;
sOConfig.OCNPolarity = TIM_OCPOLARITY_HIGH;
sOConfig.OCFastMode = TIM_OCFAST_DISABLE;
sOConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
sOConfig.OCIdleState = TIM_OCIDLESTATE_RESET;
if (HAL_TIM_OC_ConfigChannel(&TimHandle, &sOConfig, TIMx_CHANNEL_OC) != HAL_OK)
{
//Configuration Error
Error_Handler();
}
/* Initialize Timer "IC" channel for IC mode */
sICConfig.ICPolarity = CLK_LATCHING_DATA_EDGE;
sICConfig.ICSelection = TIM_ICSELECTION_DIRECTTI;
sICConfig.ICPrescaler = TIM_ICPSC_DIV1;
sICConfig.ICFilter = TIM_IC_FILTER; /* filter the clock signal over/undershoot */
if (HAL_TIM_IC_ConfigChannel(&TimHandle, &sICConfig, TIMx_CHANNEL_IC) != HAL_OK)
{
/* Configuration Error */
Error_Handler();
}
/* Set the DMA memory0 conversion complete callback */
TimHandle.hdma[TIMx_DMA_ID]->XferCpltCallback = TransferComplete;
/* Set the DMA memory1 conversion complete callback */
TimHandle.hdma[TIMx_DMA_ID]->XferM1CpltCallback = TransferComplete;
/* Set the DMA error callback */
TimHandle.hdma[TIMx_DMA_ID]->XferErrorCallback = TransferError ;
/* Update second memory address */
second_mem_address = (uint32_t)((SDRAM_BANK_ADDR + WRITE_READ_ADDR) + (DMA_MEM_BUFF_SIZE));
/* Start DMA multi buffer transfer */
if (HAL_DMAEx_MultiBufferStart_IT(TimHandle.hdma[TIMx_DMA_ID], GPIOx_IDR, (SDRAM_BANK_ADDR + WRITE_READ_ADDR), second_mem_address, DMA_MEM_BUFF_SIZE) != HAL_OK)
{
/* Transfer Error */
Error_Handler();
}
__HAL_TIM_ENABLE_DMA(&TimHandle, TIMx_DMA_CC);
/* Enable the TIMx OC channel interrupt */
__HAL_TIM_ENABLE_IT(&TimHandle, TIMx_IT_OC);
/* Enable the TIMX OC channel */
TIM_CCxChannelCmd(TimHandle.Instance, TIMx_CHANNEL_OC, TIM_CCx_ENABLE);
/* Enable the TIMx IC channel */
TIM_CCxChannelCmd(TimHandle.Instance, TIMx_CHANNEL_IC, TIM_CCx_ENABLE);
HAL_TIM_OC_Start(&TimHandle, TIMx_CHANNEL_OC); // enable counter
/* processing while Timeout not reached */
while (timeout_flag == 0);
该错误是由接收数据时的 FIFO 溢出情况引起的。将 FIFO 阈值从 1/4 增加到完全停止发生传输错误。
cortex-M7 引入了数据和指令缓存,这可能会导致 DMA 传输出现问题,但我可以确认情况并非如此,更多信息 here。
我有一个 STM32F769I-EVAL 配置为根据来自 ST AN4666. What I expect to happen is: the clock from my input device triggers the input capture DMA and writes data to SDRAM until my OC timer interrupt disables the transfer. At that point I can manipulate the data in SDRAM and transfer it elsewhere. However, after the hardware is configured and the input capture enabled I get a DMA transfer error. The value for errorcode (6) in the HAL_DMA_IRQHandler function shows that both FIFO and transfer error flags are set. According to my understanding of the datasheet 的代码接收 8 位并行数据(参见第 261 页)这应该是不可能的,我假设我在某处配置错误但是至于如何进行,我不知所措。我可以采取什么步骤来解决这个问题?
DMA 配置:
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_InitStruct;
static DMA_HandleTypeDef hdma_tim;
/* TIMx clock enable */
TIMx_CLK_ENABLE();
/* Enable DMA clock */
DMAx_CLK_ENABLE();
/* Enable TIM input GPIO clock */
TIMx_CHy_GPIOCLK_ENABLE();
/* Configure input of TIMx_CHy on AF */
GPIO_InitStruct.Pin = TIMx_CHy_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF_TIMx;
HAL_GPIO_Init(TIMx_CHy_PORT, &GPIO_InitStruct);
/* Set the parameters to be configured */
hdma_tim.Init.Channel = DMA_CHANNEL;
hdma_tim.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_tim.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE ; /* Reading in GPIO PC[7:0]*/
hdma_tim.Init.MemDataAlignment = DMA_MDATAALIGN_WORD ;
hdma_tim.Init.Mode = DMA_NORMAL; /* double memory buffer used */
hdma_tim.Init.Priority = DMA_PRIORITY_HIGH;
hdma_tim.Init.FIFOMode = DMA_FIFOMODE_ENABLE; /* using FIFO mode since memory datasize=32bit and GPIO=8bits in our case */
hdma_tim.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; /* flushing FIFO at each 32bit reception (4 data) */
hdma_tim.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_tim.Init.PeriphBurst = DMA_PBURST_SINGLE;
/* Set hdma_tim instance */
hdma_tim.Instance = DMA_STREAM;
/* Link hdma_tim to hdma[CC1] */
__HAL_LINKDMA(htim, hdma[TIMx_DMA_ID], hdma_tim);
/* Initialize TIMx DMA handle */
HAL_DMA_Init(htim->hdma[TIMx_DMA_ID]);
/* NVIC configuration for TIMx output compare interrupt */
HAL_NVIC_SetPriority(TIMx_IRQn, 0, 2);
HAL_NVIC_EnableIRQ(TIMx_IRQn);
/* Configure the NVIC for DMA */
/* NVIC configuration for DMA transfer complete interrupt */
HAL_NVIC_SetPriority(TIMx_DMA_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIMx_DMA_IRQn);
}
主要代码:
/* Initialize SDRAM */
BSP_SDRAM_Init();
/* Configure the Data GPIO in input mode */
Data_GPIO_Config();
/* Set Timers instance */
TimHandle.Instance = TIMx;
/* Initialize global Timer parameters */
TimHandle.Init.Period = MAX_COUNTER;
TimHandle.Init.Prescaler = TIMx_PRESCALER - 1;
TimHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.RepetitionCounter = 0;
if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
//Initialize Timer "OC" channel for OC mode
sOConfig.OCMode = TIM_OCMODE_TIMING/*TIM_OCMODE_TOGGLE*/;
sOConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
sOConfig.Pulse = NB_COUNTER_CYCLE;
sOConfig.OCNPolarity = TIM_OCPOLARITY_HIGH;
sOConfig.OCFastMode = TIM_OCFAST_DISABLE;
sOConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
sOConfig.OCIdleState = TIM_OCIDLESTATE_RESET;
if (HAL_TIM_OC_ConfigChannel(&TimHandle, &sOConfig, TIMx_CHANNEL_OC) != HAL_OK)
{
//Configuration Error
Error_Handler();
}
/* Initialize Timer "IC" channel for IC mode */
sICConfig.ICPolarity = CLK_LATCHING_DATA_EDGE;
sICConfig.ICSelection = TIM_ICSELECTION_DIRECTTI;
sICConfig.ICPrescaler = TIM_ICPSC_DIV1;
sICConfig.ICFilter = TIM_IC_FILTER; /* filter the clock signal over/undershoot */
if (HAL_TIM_IC_ConfigChannel(&TimHandle, &sICConfig, TIMx_CHANNEL_IC) != HAL_OK)
{
/* Configuration Error */
Error_Handler();
}
/* Set the DMA memory0 conversion complete callback */
TimHandle.hdma[TIMx_DMA_ID]->XferCpltCallback = TransferComplete;
/* Set the DMA memory1 conversion complete callback */
TimHandle.hdma[TIMx_DMA_ID]->XferM1CpltCallback = TransferComplete;
/* Set the DMA error callback */
TimHandle.hdma[TIMx_DMA_ID]->XferErrorCallback = TransferError ;
/* Update second memory address */
second_mem_address = (uint32_t)((SDRAM_BANK_ADDR + WRITE_READ_ADDR) + (DMA_MEM_BUFF_SIZE));
/* Start DMA multi buffer transfer */
if (HAL_DMAEx_MultiBufferStart_IT(TimHandle.hdma[TIMx_DMA_ID], GPIOx_IDR, (SDRAM_BANK_ADDR + WRITE_READ_ADDR), second_mem_address, DMA_MEM_BUFF_SIZE) != HAL_OK)
{
/* Transfer Error */
Error_Handler();
}
__HAL_TIM_ENABLE_DMA(&TimHandle, TIMx_DMA_CC);
/* Enable the TIMx OC channel interrupt */
__HAL_TIM_ENABLE_IT(&TimHandle, TIMx_IT_OC);
/* Enable the TIMX OC channel */
TIM_CCxChannelCmd(TimHandle.Instance, TIMx_CHANNEL_OC, TIM_CCx_ENABLE);
/* Enable the TIMx IC channel */
TIM_CCxChannelCmd(TimHandle.Instance, TIMx_CHANNEL_IC, TIM_CCx_ENABLE);
HAL_TIM_OC_Start(&TimHandle, TIMx_CHANNEL_OC); // enable counter
/* processing while Timeout not reached */
while (timeout_flag == 0);
该错误是由接收数据时的 FIFO 溢出情况引起的。将 FIFO 阈值从 1/4 增加到完全停止发生传输错误。
cortex-M7 引入了数据和指令缓存,这可能会导致 DMA 传输出现问题,但我可以确认情况并非如此,更多信息 here。