Skip to main content
margce
Associate II
December 18, 2017
Solved

STM32F303 ADC calibration doesn't end

  • December 18, 2017
  • 7 replies
  • 2251 views
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

);

}

    This topic has been closed for replies.
    Best answer by margce
    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

     

    7 replies

    AvaTar
    Senior III
    December 18, 2017
    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.

    margce
    margceAuthor
    Associate II
    December 18, 2017
    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.

    AvaTar
    Senior III
    December 18, 2017
    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' ?

    margce
    margceAuthorBest answer
    Associate II
    December 19, 2017
    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