2017-12-17 08:02 PM
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,
Martinvoid 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
);}
Solved! Go to Solution.
2017-12-18 04:40 PM
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
2017-12-17 11:06 PM
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.
2017-12-18 12:24 AM
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.
2017-12-18 12:32 AM
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' ?
2017-12-18 12:36 AM
Oh hehe... Yes I meant that the NVIC interrupt does NOT get executed.
2017-12-18 01:09 AM
Some time ago since I messed with ADC/DMA the last time, but this doesn't seem right:
DMA_Init(ADC1, &DMA_InitStructure);
2017-12-18 04:24 PM
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
2017-12-18 04:40 PM
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