cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F746 low-layer driver issue: ADC DMA TIM2 trigger

M G_2
Associate III
Posted on July 05, 2018 at 16:49

Dear Community,

I am trying to migrate some code of a STM32F4 series µC relying on the StandardPeripheralLib to STM32F7 “low layerâ€� driver concept. Unfortunately the LL-Driver concept is not that identical to StanPeriphLib as I've expected – so with a little help from UM1905 I’ve guessed how to initialize the stuff. With some periphery it worked well however the subsequent code to initialize ADC1 and DMA2 in such a kind that each conversion of  ADC1 is triggered by TIM2 and subsequently transferred via DMA2 to a buffer is not working while the original code based on StandardPeripheralLib worked well on STM32F4. I tried so far to test the example 

“ADC_SingleConversion_TriggerTimer_DMA� (STM32F767Zi)

which is unfortunatelly also not working. Then I've tried to compare the Register entries of DMA2 and ADC1 obtained from a working STM32F4 with that of the non working STM32F7 with the result that some entries are identical and others are not. I would be glad if someone could give a hint how to solve the problem. 

[Code]

void ADC1_Init() {

  LL_DMA_InitTypeDef       DMA_InitStructure;

  LL_GPIO_InitTypeDef      GPIO_InitStructure;

// LL_NVIC_InitTypeDef    NVIC_InitStructure1;

 LL_ADC_InitTypeDef       ADC_InitStructure;

 LL_ADC_REG_InitTypeDef   ADC_REG_InitStructure;

 

  LL_ADC_CommonInitTypeDef ADC_CommonInitStructure;

  

  // Enable ADCx, DMA and GPIO clocks ****************************************

//  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2|RCC_AHB1Periph_GPIOA, ENABLE);   Enable GPIO Clock

  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);

  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA2); 

// RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC1)

  // DMA2 Stream0 channel0 configuration ************************************** 

   //DMA_DeInit(DMA2_Stream1);

 

  DMA_InitStructure.Channel =  LL_DMA_CHANNEL_0;   

 

 

 DMA_InitStructure.MemoryOrM2MDstAddress = (uint32_t)&ADC1_Buffer; //   DMA_Memory0BaseAddr =

 DMA_InitStructure.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD; //  LL_DMA_MemoryDataSize_HalfWord; //DMA_MemoryDataSize =

 DMA_InitStructure.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;

 //DMA_InitStructure.DMA_BufferSize = BLOCK_SIZE;

 

 DMA_InitStructure.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; // DMA_PeripheralInc =DMA_PeripheralInc_Disable;

  DMA_InitStructure.PeriphOrM2MSrcAddress  = LL_ADC_DMA_GetRegAddr(ADC1, LL_ADC_DMA_REG_REGULAR_DATA);

  DMA_InitStructure.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD ;

  DMA_InitStructure.Direction  = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;// LL_DMA_DIR_PeripheralToMemory;

 

  DMA_InitStructure.Mode  =  LL_DMA_MODE_NORMAL;//DMA_Mode_Normal ;

  DMA_InitStructure.Priority = LL_DMA_PRIORITY_HIGH; // Priority_High;

  DMA_InitStructure.FIFOMode = LL_DMA_FIFOMODE_DISABLE; // DMA_FIFOMode_Disable;        

  DMA_InitStructure.FIFOThreshold = LL_DMA_FIFOTHRESHOLD_1_2; // FIFO threshold half full configuration // DMA_FIFOThreshold_HalfFull;

  DMA_InitStructure.MemBurst = LL_DMA_MBURST_SINGLE;    // DMA_MemoryBurst_Single;

  DMA_InitStructure.PeriphBurst = LL_DMA_MBURST_SINGLE; // DMA_PeripheralBurst_Single;

 DMA_InitStructure.NbData = BLOCK_SIZE;

 

  LL_DMA_Init(DMA2, LL_DMA_STREAM_0, &DMA_InitStructure);

  LL_DMA_EnableStream(LL_DMA_STREAM_0, ENABLE);

  

  

  

  // Configure ADC1 pin as analog input ***********************

 GPIO_InitStructure.Mode       = LL_GPIO_MODE_ANALOG;

  GPIO_InitStructure.Speed      = LL_GPIO_SPEED_FREQ_LOW;

  GPIO_InitStructure.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;

  GPIO_InitStructure.Pull       = LL_GPIO_PULL_NO;

 

 GPIO_InitStructure.Pin        = LL_GPIO_PIN_2;

 if(LL_GPIO_Init(GPIOD, &GPIO_InitStructure) != SUCCESS) while(1); // stuck here until the cows come home

 

 //DMA NVIR*************************************************************

// NVIC_InitStructure1.NVIC_IRQChannel = DMA2_Stream0_IRQn;

// NVIC_InitStructure1.NVIC_IRQChannelPreemptionPriority = ADC1_prio ;

// NVIC_InitStructure1.NVIC_IRQChannelSubPriority = ADC1_subPrio;

// NVIC_InitStructure1.NVIC_IRQChannelCmd = ENABLE;

// NVIC_Init(&NVIC_InitStructure1);

 

  NVIC_SetPriority(DMA2_Stream0_IRQn, ADC1_prio); // DMA IRQ lower priority than ADC IRQ

  NVIC_EnableIRQ(DMA2_Stream0_IRQn);

 

 //DMA_ITConfig(DMA2_Stream0, DMA_IT_TC , ENABLE);

 LL_DMA_EnableIT_TC(DMA2,LL_DMA_CHANNEL_0);

 

 //DMA_Cmd(DMA2_Stream0, ENABLE);

 LL_DMA_EnableStream(DMA2,LL_DMA_STREAM_0);

  

  

  

  // ADC Common Init **********************************************************

  ADC_CommonInitStructure.Multimode  = LL_ADC_MULTI_INDEPENDENT; // LL_ADC_MODE_INDEPENDENT; // ADC_Mode_Independent;

  ADC_CommonInitStructure.CommonClock = LL_ADC_CLOCK_SYNC_PCLK_DIV2; // ADC_Prescaler_Div2;

 ADC_CommonInitStructure.MultiDMATransfer = LL_ADC_MULTI_REG_DMA_EACH_ADC; // each ADC uses its own channel - consider this as disabled ADC_DMAAccessMode_Disabled

 ADC_CommonInitStructure.MultiTwoSamplingDelay = LL_ADC_MULTI_TWOSMP_DELAY_5CYCLES;

  LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStructure);

  // ADC1 Init ****************************************************************

  ADC_InitStructure.Resolution = LL_ADC_RESOLUTION_12B; //  ADC_Resolution = ADC_Resolution_12b;

  ADC_InitStructure.SequencersScanMode = DISABLE;  // just on channel -> otherwise if more than one channel shall be multiplexed this needs to be enabled

  ADC_InitStructure.DataAlignment =  LL_ADC_DATA_ALIGN_RIGHT;

 LL_ADC_Init(ADC1, &ADC_InitStructure);

 

 

  ADC_REG_InitStructure.ContinuousMode = DISABLE;

 ADC_REG_InitStructure.DMATransfer = LL_ADC_REG_DMA_TRANSFER_LIMITED;

 ADC_REG_InitStructure.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE ;

 ADC_REG_InitStructure.SequencerLength = LL_ADC_INJ_SEQ_SCAN_DISABLE ;

 ADC_REG_InitStructure.TriggerSource = LL_ADC_REG_TRIG_EXT_TIM2_CH2;

 LL_ADC_REG_Init(ADC1, &ADC_REG_InitStructure);

 // Note:On this STM32 (STM32F746) serie, setting of external trigger edge is performed using function

  LL_ADC_REG_StartConversionExtTrig(ADC1, LL_ADC_REG_TRIG_EXT_TIM2_CH2);

 

  // ADC1 regular channel7 configuration **************************************

  //ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_3Cycles); //channel2 == PA2 !

 LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_2, LL_ADC_SAMPLINGTIME_3CYCLES);

 

 // Enable DMA request after last transfer (Single-ADC mode)

  //ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

 LL_DMA_EnableIT_TC(DMA2,LL_DMA_CHANNEL_0);

  // Enable ADC3 DMA

  //ADC_DMACmd(ADC1, ENABLE);

  LL_DMA_EnableStream(DMA2,LL_DMA_STREAM_0);

 

  //ADC_Cmd(ADC1, ENABLE);

  LL_ADC_Enable(ADC1);

 

  //ADC_SoftwareStartConv(ADC1);

  LL_ADC_REG_StartConversionSWStart(ADC1);

 

}

[~Code]

3 REPLIES 3
M G_2
Associate III
Posted on July 06, 2018 at 16:27

Dear Community,

I’ve further investigated the problem by directly comparing the registers of a working code in STM32F407 with those of the not working code in STM32F746. The result is so far only one major difference in ADC1 register CR2 and SQR3. The code is not able to set DDS,  DMA and ADON nor it sets SQR3_SQ1->0x02. If I do this manually then I can see that DMA2 SONDTR counts to zero and in ADC1 SR OVR-> true and STRT->true and the TC Interrupt is fired as it is supposed to do. 

 If someone knows which command of the LL Driver-Concept can be used to set the mentioned registers then  please feel free to post here.

LMI2
Lead
Posted on July 07, 2018 at 15:04

There is or atleast has been migration manuals between CPU families. Have you tried to search for them.

M G_2
Associate III
Posted on July 09, 2018 at 13:39

Hi - and thankyou for responding. I’ve found AN4660 for a migration F42/43 to F7 and it looks like DMA and ADC should be fully compatible (as expected). However it does not cover how in detail I’ve to change my periphery initialization procedures.

Meanwhile I’ve further investigated the LL Library and found that in \stm32f7xx_ll_adc.c following procedure to set the CR-> DDS bit might not work because

either I haven’t understood what the author has intended or the author has simply forgotten to also include the DDS bit

:

 MODIFY_REG(ADCx-&gtCR2,

                 ADC_CR2_EXTSEL

               | ADC_CR2_EXTEN

               | ADC_CR2_CONT

               | ADC_CR2_DMA

               | ADC_CR2_DDS

              ,

                (ADC_REG_InitStruct-&gtTriggerSource & ADC_CR2_EXTSEL)

               | ADC_REG_InitStruct-&gtContinuousMode

               | ADC_REG_InitStruct-&gtDMATransfer

              )

Thus I’ve wrote my own function to set DDS. After starting the ADC using LL_ADC_REG_StartConversionSWStart(ADC1) nothing happens – only if I manually trigger the SWTART bit in debugger conversion takes place until the TC is fired. Looks like other members of our community have already faced a similar problem (

https://community.st.com/0D50X00009XkY6vSAF

). I hoped to find at least one of the µC’Timers that might work – interestingly if I include TIM1 into my list of timers the LL_ADC_REG_TRIG_EXT_TIM2_TRGO event is able to trigger the ADC. Thus I concluded that all Timer might be better  initialised  using  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_ALL) -  In this case Timer2 will also be able to trigger ADC1 using

LL_ADC_REG_TRIG_EXT_TIM2_TRGO

in STM32F746.

Hope this helps some of us.