cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F303 ADC calibration doesn't end

margce
Associate III
Posted on December 18, 2017 at 05:02

Hello everyone,

I'm staring a new project with a STM32F303VC, I want to use the ADC peripheral but having trouble getting the Calibration to end. Below is the code that I execute just after the board has initialised, I'm running with a 16Mhz external oscillator and using the PLL to get 72Mhz system clock.

The system freezes waiting for the calibration to end here,  while(

ADC_GetCalibrationStatus(

ADC1

) != RESET );

Even if I don't run the calibration, the ADC doesn't work. It's like I'm missing some sort of clock, or something else. I've looked at the example for the STD libraries but can't notice anything else I might be missing.

Has anyone experience such issue?

Thanks,

Martin

void target_adc_init( void )

{

  uint32_t delay;

  ADC_InitTypeDef ADC_InitStructure;

  ADC_CommonInitTypeDef ADC_CommonInitStructure;

  DMA_InitTypeDef  DMA_InitStructure;

  NVIC_InitTypeDef NVIC_InitStructure;

  /* Configure ADC peripherals -------------------------------------------*/

  // Configure the ADC clocks

  RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div2);

 

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE);

 

// Enable DMA clocks

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  /* Calibrate ADC ----------------------------------------------------*/

  ADC_VoltageRegulatorCmd(

ADC1

, ENABLE);

  // Insert delay >= 10 µs

  delay = 1000;

  while(--delay);

  ADC_SelectCalibrationMode(

ADC1

, ADC_CalibrationMode_Single);

  ADC_StartCalibration(

ADC1

);

 

while( ADC_GetCalibrationStatus(

ADC1

) != RESET );

  // ADC Common configuration

  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;

  ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode;

  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;

  ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_OneShot;

  ADC_CommonInitStructure.ADC_TwoSamplingDelay = 0;

  ADC_CommonInit(

ADC1

, &ADC_CommonInitStructure);

  /* Configure ADC ----------------------------------------------------*/

  ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Enable;

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

  ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0;

  ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None;

  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

  ADC_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Disable;

  ADC_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable;

  ADC_InitStructure.ADC_NbrOfRegChannel = 5;

  ADC_Init(

ADC1

, &ADC_InitStructure);

  /* Configure DMA ----------------------------------------------------*/

  DMA_DeInit(

ADC1

);

  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1->DR;

  DMA_InitStructure.DMA_MemoryBaseAddr = adc_samples;

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

  DMA_InitStructure.DMA_BufferSize = 5;

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

  DMA_InitStructure.DMA_Priority = DMA_Priority_High;

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  DMA_Init(

ADC1

, &DMA_InitStructure);

  // Enable DMA Channel Transfer Complete interrupt

  DMA_ITConfig(

ADC1

, DMA_IT_TC, ENABLE);

  //Enable DMA1 channel IRQ Channel

  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

    

  RCC_AHBPeriphClockCmd(

       BATTERY_TEMP_RCC_GPIO |

       CHARGER_TM1_RCC_GPIO | CHARGER_TM2_RCC_GPIO |

       CHARGER_TS1_RCC_GPIO | CHARGER_TS2_RCC_GPIO |

       INV_TEMP_RCC_GPIO

       , ENABLE);

    GPIO_InitStructure.GPIO_Mode = BATTERY_TEMP_MODE;

    GPIO_InitStructure.GPIO_PuPd = BATTERY_TEMP_PUPD;

    GPIO_InitStructure.GPIO_Pin = (BATTERY_TEMP_PIN | CHARGER_TM1_PIN | CHARGER_TM2_PIN | CHARGER_TS1_PIN | CHARGER_TS2_PIN);

    GPIO_Init(BATTERY_TEMP_GPIO, &GPIO_InitStructure);

    ADC_RegularChannelConfig(BATTERY_TEMP_ADC, BATTERY_TEMP_ADC_CHANNEL, 1, ADC_SampleTime_7Cycles5);

    // Charger Master temperature #1

    ADC_RegularChannelConfig(CHARGER_TM1_ADC, CHARGER_TM1_ADC_CHANNEL, 2, ADC_SampleTime_7Cycles5);

    // Charger Master temperature #2

    ADC_RegularChannelConfig(CHARGER_TM2_ADC, CHARGER_TM2_ADC_CHANNEL, 3, ADC_SampleTime_7Cycles5);

    // Charger Slave #1 temperature

    ADC_RegularChannelConfig(CHARGER_TS1_ADC, CHARGER_TS1_ADC_CHANNEL, 4, ADC_SampleTime_7Cycles5);

    // Charger Slave #2 temperature

    ADC_RegularChannelConfig(CHARGER_TS2_ADC, CHARGER_TS2_ADC_CHANNEL, 5, ADC_SampleTime_7Cycles5);

    // Inverter temperature

    GPIO_InitStructure.GPIO_Pin = INV_TEMP_PIN;

    GPIO_Init(INV_TEMP_GPIO, &GPIO_InitStructure);

    ADC_RegularChannelConfig(INV_TEMP_ADC, INV_TEMP_ADC_CHANNEL, 1, ADC_SampleTime_7Cycles5);

 

  // ADC DMA Enable

  ADC_DMAConfig(ADC1, ADC_DMAMode_Circular);

  ADC_DMACmd(

ADC1

, ENABLE);

  // Enable ADC

  ADC_Cmd(

ADC1

, ENABLE);

  // Wait for ADRDY

  while(

ADC1

, ADC_FLAG_RDY));

  // Enable DMA

  DMA_Cmd(

ADC1

, ENABLE );

  // Start ADC Software Conversion

  ADC_StartConversion(

ADC1

);

}

1 ACCEPTED SOLUTION

Accepted Solutions
margce
Associate III
Posted on December 19, 2017 at 01:40

Since I wasn't getting interruptions from the DMA I decided to enable the DMA_IT_HT and DMA_IT_TE as well. I then noticed that Transfer Error interrupt was getting triggered. Based on the reference manual, as soon as there is an error the DMA gets disabled automatically.

Error management

A DMA transfer error can be generated by reading from or writing to a reserved address

space. When a DMA transfer error occurs during a DMA read or a write access, the faulty

channel is automatically disabled through a hardware clear of its EN bit in the corresponding

Channel configuration register (DMA_CCRx). The channel's transfer error interrupt flag

(TEIF) in the DMA_IFR register is set and an interrupt is generated if the transfer error

interrupt enable bit (TEIE) in the DMA_CCRx register is set.

So, I checked the DMA initialisation and saw the error, the peripheral base address was trying to read from the incorrect address as ADC1->DR returns the content of DR not its address.

DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1->DR;

I changed it to 

DMA_InitStructure.DMA_PeripheralBaseAddr = &ADC1->DR;

And now it's working.

Thanks for the help!

Martin

 

View solution in original post

7 REPLIES 7
AvaTar
Lead
Posted on December 18, 2017 at 08:06

Almost identical code works for me - except the delay after turning on the voltage regulator is longer.

I have 100.000 instead of 1000, but didn't experiment much as I remember.

Posted on December 18, 2017 at 08:24

Hi thanks for comment, I tried increasing the loop wait before posting but didn't have any impact.

After I posted the message I was debbuging the code and noticed that before enabling the Voltage Regulator ADC1.CR was loaded with some incorrect values. I added a ADC_Deinit before running the initialization and now calibration ends correctly.

The problem I have now is that although everything else starts, the interrupt I configured for DMA1_Channel1 does get executed.

Posted on December 18, 2017 at 08:32

The problem I have now is that although everything else starts, the interrupt I configured for DMA1_Channel1 does get executed.

Did you perhaps mean 'does NOT get executed' ?

Posted on December 18, 2017 at 08:36

Oh hehe... Yes I meant that the NVIC interrupt does NOT get executed.

Posted on December 18, 2017 at 09:09

Some time ago since I messed with ADC/DMA the last time, but this doesn't seem right:

  DMA_Init(ADC1, &DMA_InitStructure);

Posted on December 19, 2017 at 00:24

Sorry... that's happens when I just copy & paste and check quickly... that's not correct what I have in my code is 

DMA_Cmd(

DMA1_Channel1

, ENABLE ); but still not working

margce
Associate III
Posted on December 19, 2017 at 01:40

Since I wasn't getting interruptions from the DMA I decided to enable the DMA_IT_HT and DMA_IT_TE as well. I then noticed that Transfer Error interrupt was getting triggered. Based on the reference manual, as soon as there is an error the DMA gets disabled automatically.

Error management

A DMA transfer error can be generated by reading from or writing to a reserved address

space. When a DMA transfer error occurs during a DMA read or a write access, the faulty

channel is automatically disabled through a hardware clear of its EN bit in the corresponding

Channel configuration register (DMA_CCRx). The channel's transfer error interrupt flag

(TEIF) in the DMA_IFR register is set and an interrupt is generated if the transfer error

interrupt enable bit (TEIE) in the DMA_CCRx register is set.

So, I checked the DMA initialisation and saw the error, the peripheral base address was trying to read from the incorrect address as ADC1->DR returns the content of DR not its address.

DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1->DR;

I changed it to 

DMA_InitStructure.DMA_PeripheralBaseAddr = &ADC1->DR;

And now it's working.

Thanks for the help!

Martin