AnsweredAssumed Answered

STM32F429, HAL, TIM+ADC+DMA + (mem2mem)

Question asked by moore.daniel.001 on Sep 30, 2016
Latest reply on Oct 1, 2016 by moore.daniel.001
Hi,

These forums have been so helpful for me, but I cant seem to find the answer to a problem that has me up for days. Here's what I am trying to achieve using the HAL:

ADC1, ADC2, ADC3 simultaneously sampling through TIM8 update->TRGO. This seems to be working fine. I also need to sample a location in memory and put it into a sample buffer simultaneously with the ADC samples. I know a mem2mem dma is off the table because it will not be gates by TIM8.

I have tried to achieve this through the following:

void Analog_periphStateInitDMA(void)
{
  __DMA2_CLK_ENABLE();
   
  /*##-3- Configure the DMA streams ##########################################*/
  if (NULL != sAnalog.tim.hdma[TIM_DMA_ID_UPDATE].Instance)  // Only preform the DeInit if needed
    HAL_DMA_DeInit(&sAnalog.tim.hdma[TIM_DMA_ID_UPDATE]);
   
  sAnalog.tim.hdma[TIM_DMA_ID_UPDATE].Instance = DMA2_Stream7;
  sAnalog.tim.hdma[TIM_DMA_ID_UPDATE].Init.Channel = DMA_CHANNEL_7;
  IRQn_Type dmaIRQ = DMA2_Stream7_IRQn;
   
  sAnalog.tim.hdma[TIM_DMA_ID_UPDATE].Init.Direction           = DMA_PERIPH_TO_MEMORY;
  sAnalog.tim.hdma[TIM_DMA_ID_UPDATE].Init.PeriphInc           = DMA_PINC_DISABLE;
  sAnalog.tim.hdma[TIM_DMA_ID_UPDATE].Init.MemInc              = DMA_MINC_ENABLE;
  sAnalog.tim.hdma[TIM_DMA_ID_UPDATE].Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
  sAnalog.tim.hdma[TIM_DMA_ID_UPDATE].Init.MemDataAlignment    = DMA_MDATAALIGN_HALFWORD;
  sAnalog.tim.hdma[TIM_DMA_ID_UPDATE].Init.Mode                = DMA_NORMAL;
  sAnalog.tim.hdma[TIM_DMA_ID_UPDATE].Init.Priority            = DMA_PRIORITY_HIGH;
  sAnalog.tim.hdma[TIM_DMA_ID_UPDATE].Init.FIFOMode            = DMA_FIFOMODE_ENABLE;
  sAnalog.tim.hdma[TIM_DMA_ID_UPDATE].Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_1QUARTERFULL;
  sAnalog.tim.hdma[TIM_DMA_ID_UPDATE].Init.MemBurst            = DMA_MBURST_SINGLE;
  sAnalog.tim.hdma[TIM_DMA_ID_UPDATE].Init.PeriphBurst         = DMA_PBURST_SINGLE;
  HAL_DMA_Init(&sAnalog.tim.hdma[TIM_DMA_ID_UPDATE]);
   
  /* Associate the initialized DMA handle to the the ADC handle */
  __HAL_LINKDMA(&sAnalog.tim.htim, hdma[TIM_DMA_ID_UPDATE],      sAnalog.tim.hdma[TIM_DMA_ID_UPDATE]);
  __HAL_LINKDMA(&sAnalog.tim.htim, hdma[TIM_DMA_ID_CC1],         sAnalog.tim.hdma[TIM_DMA_ID_UPDATE]);
  __HAL_LINKDMA(&sAnalog.tim.htim, hdma[TIM_DMA_ID_CC2],         sAnalog.tim.hdma[TIM_DMA_ID_UPDATE]);
  __HAL_LINKDMA(&sAnalog.tim.htim, hdma[TIM_DMA_ID_CC3],         sAnalog.tim.hdma[TIM_DMA_ID_UPDATE]);
  __HAL_LINKDMA(&sAnalog.tim.htim, hdma[TIM_DMA_ID_CC4],         sAnalog.tim.hdma[TIM_DMA_ID_UPDATE]);
  __HAL_LINKDMA(&sAnalog.tim.htim, hdma[TIM_DMA_ID_COMMUTATION], sAnalog.tim.hdma[TIM_DMA_ID_UPDATE]);
  __HAL_LINKDMA(&sAnalog.tim.htim, hdma[TIM_DMA_ID_TRIGGER],     sAnalog.tim.hdma[TIM_DMA_ID_UPDATE]);
   
  HAL_NVIC_SetPriority(dmaIRQ, 0, 0);  // Configure the NVIC for DMA
  HAL_NVIC_EnableIRQ(dmaIRQ);
}
void Analog_configureADC(ADCSelect adcSel, void *pDst, uint32_t numSamps)
{
  if (ADC_PERIPH_STATE == adcSel)
  {   
    Analog_periphStateInitDMA();
    HAL_DMA_Start_IT(&sAnalog.tim.hdma[TIM_DMA_ID_UPDATE], (uint32_t)&gPeriphState, (uint32_t)pDst, numSamps);
     
    __HAL_TIM_ENABLE_DMA(&sAnalog.tim.htim, TIM_DMA_ID_TRIGGER);
     
    NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
    NVIC_ClearPendingIRQ(ADC_IRQn);
    return;
  }
  ... // set up the other ADCs
  return
}
 
boolean Analog_setupTimer(uint32_t irqPeriod)
{
  //uint32_t timFreq = HAL_RCC_GetPCLK1Freq() * 2;
   
  const uint32_t timFreq = 90000000;
  sAnalog.tim.htim.Instance = TIM8;
  sAnalog.tim.htim.Init.ClockDivision     = TIM_CLOCKDIVISION_DIV1;
  sAnalog.tim.htim.Init.CounterMode       = TIM_COUNTERMODE_UP;
  sAnalog.tim.htim.Init.Period            = irqPeriod * (timFreq / (1000 * 1000));
  sAnalog.tim.htim.Init.Prescaler         = 0;
  sAnalog.tim.htim.Init.RepetitionCounter = 0;
  sAnalog.tim.htim.Channel                = HAL_TIM_ACTIVE_CHANNEL_1;
  HAL_TIM_Base_Init(&sAnalog.tim.htim);
   
  TIM_ClockConfigTypeDef clockDef;
  clockDef.ClockSource    = TIM_CLOCKSOURCE_INTERNAL;
  clockDef.ClockPolarity  = TIM_CLOCKPOLARITY_BOTHEDGE;
  clockDef.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1;
  clockDef.ClockFilter    = 0;
  HAL_TIM_ConfigClockSource(&sAnalog.tim.htim, &clockDef);
   
  TIM_MasterConfigTypeDef sMasterConfig;
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&sAnalog.tim.htim, &sMasterConfig);
   
  return TRUE;
}
 
boolean Analog_startSampleTimer(uint32_t sampRate)
{
  Analog_setupTimer(sampRate);
  HAL_TIM_Base_Start(&sAnalog.tim.htim);
  //HAL_TIM_Base_Start_IT(&sAnalog.tim.htim);
   
   
  return SUCCESS;
}

The 3 ADCs sample just fine and in lock-step with the timer. The mem2mem (periphState) stream will never move, even when I manually generate EGR->UG triggers -- the ADCs do transfer when I do that.

Am I going about this the right way -- using the DMA triggered off of TIM8 to copy gPeriphState to the sample buffer? Is the DMA going to have a problem since I am telling it that its a peripheral, but its really a memory location -- I thought DMA2 has access to main memory.

Would you recommend I try triggering off of the ADCs instead? I tried this and didn't get anywhere.

Can you pick out a bug that is causing this not to work? This is my first project with the HAL and it has been a huge learning curve. I have run into behavior that I didn't expect before.

Thank you so much for your help in advance -- this is driving me crazy.

Outcomes