cancel
Showing results for 
Search instead for 
Did you mean: 

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

drmoore
Associate II
Posted on September 30, 2016 at 23:07

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. #tim-adc-dma-mem #stm32f429 #hal
1 REPLY 1
drmoore
Associate II
Posted on October 01, 2016 at 11:11

Sorry for posting on the wrong topic. I don't see where to delete the post. If you're interested in the solution, I posted it [DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/STM32F429%2c%20HAL%2c%20TIM%2bADC%2bDMA%20%2b%20%28mem2mem%29&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&TopicsView=https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/AllItems.aspx&currentviews=8]here.