STM32 Ошибка передачи DMA и FIFO и установлены флаги ошибки передачи

У меня есть STM32F769I-EVAL, настроенный на получение 8-битных параллельных данных на основе кода из ST AN4666. Я ожидаю, что произойдет следующее: часы с моего устройства ввода запускают DMA захвата ввода и записывают данные в SDRAM, пока мое прерывание таймера OC не отключит передачу. На этом этапе я могу манипулировать данными в SDRAM и передавать их в другое место. Однако после настройки оборудования и включения захвата ввода я получаю ошибку передачи DMA. Значение для errorcode (6) в функции HAL_DMA_IRQHandler показывает, что установлены как FIFO, так и флаги ошибок передачи. В соответствии с моим пониманием таблицы данных (см. Стр. 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);

1 ответ

Решение

Ошибка была вызвана переполнением FIFO при получении данных. Увеличение порогового значения FIFO с 1/4 до полного предотвращает возникновение ошибок передачи.

Cortex-M7 представляет кэш данных и команд, который может вызвать проблемы с передачей DMA, но я могу подтвердить, что это не так, дополнительную информацию здесь.

Другие вопросы по тегам