0

I have an STM32F769I-EVAL configured to receive 8 bit parallel data based on code from ST's 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 (see pg 261) this should not be possible, I assume I have mis-configured a setting somewhere but I am at a loss as far as how to proceed. What steps can I take to solve this?

DMA configuration:

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);

}

Code from main:

/* 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);
anOkCoder
  • 333
  • 4
  • 11
  • 1
    The STlib HAL is just bloatware without any benefit. Use direct register programming. That way you can inspect the status registers directly and check what the flags mean. Use the debugger for closer inspection. – too honest for this site Mar 25 '17 at 03:33
  • Does ST's HAL change the values in the status registers from what they would be if I wrote my own drivers? I can see the status registers in the debugger and that the aforementioned error flags are set in the DMA_HISR interrupt status register but I don't know what else I should be looking for to resolve the issue I'm seeing. – anOkCoder Mar 25 '17 at 18:51
  • I don't work with the HAL since I had a first peek at that mess. As it claims to be a "Hardware **Abstraction** Layer", I'd assume it does. However, it complicates debugging and the code. Wrap your hardware accesses in a semantic driver instead (it is good practice anyway, HAL or not). – too honest for this site Mar 25 '17 at 19:16

1 Answers1

2

The error was caused by a FIFO overrun condition while receiving data. Increasing the FIFO threshold value from 1/4 to full stops the transfer errors from occurring.

The cortex-M7 introduces a data and instruction cache which may cause issues with DMA transfers but I could confirm that this was not the case, further information here.

anOkCoder
  • 333
  • 4
  • 11