We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hello I’m new to the STM32 world and I’m making some experiments with the STM32F4 Discovery Board.
I would like to measure the VBAT and Temperature sensor signals using the ADC1 and the DMA, continously scanning both the channels. The results I obtain are quite in the expected values …but I can see no significant changes for example varying the temperature applied to the microcontroller case. I suspect that the ADC stops the conversions or the DMA stops the transferring. I’m getting slightly insane with the ADC and DMA initialization. I use the STM32F4xx DSP and Standard Peripherals Library and the MDK 4.6 32K Version (for the moment, then I will buy the complete license). Is there anybody willing to give me some advice? Here below you will find the code I use.
Thank you Antonio (Milano - Italy)
/* Includes ------------------------------------------------------------------*/ #include "stm32f4xx.h" /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ #define ADC1_DR_ADDRESS ((uint32_t)0x4001204C) #define V25 0.760 #define AVG_SLOPE 25.0 #define BUFFERLENGHT 2 /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ __IO uint16_t ADC1ConvertedValue[BUFFERLENGHT]; __IO uint32_t ADC1ConvertedVoltage0 = 0; __IO uint32_t ADC1ConvertedVoltage1 = 0; __IO float Vsense = 0.0; __IO float TCelsius = 0.0; __IO float VBATVoltage = 0.0; /* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ void ADC1_DMA_Config(void) { ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; DMA_InitTypeDef DMA_InitStructure; /* Enable ADC1, DMA2 clocks *************************************************/ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); /* DMA2 Stream0 channel0 configuration **************************************/ DMA_DeInit(DMA2_Stream0); DMA_InitStructure.DMA_Channel = DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC1ConvertedValue; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = BUFFERLENGHT; 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_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream0, &DMA_InitStructure); DMA_Cmd(DMA2_Stream0, ENABLE); /* ADC Common Init **********************************************************/ ADC_DeInit(); ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; ADC_CommonInit(&ADC_CommonInitStructure); /* ADC1 Init ****************************************************************/ ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_ExternalTrigConv = 0; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = BUFFERLENGHT; ADC_Init(ADC1, &ADC_InitStructure); /* Enable ADC1 DMA */ ADC_DMACmd(ADC1, ENABLE); /* ADC1 regular channel18 (VBAT) & channel16 (TempSensor) configuration *****/ ADC_RegularChannelConfig(ADC1, ADC_Channel_Vbat, 1, ADC_SampleTime_480Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_TempSensor, 2, ADC_SampleTime_480Cycles); /* Enable VBAT channel: channel18 */ ADC_VBATCmd(ENABLE); /* Enable TempSensor and Vrefint channels: channel16 and channel17 */ ADC_TempSensorVrefintCmd(ENABLE); /* Enable DMA request after last transfer (Single-ADC mode) */ ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); /* Enable ADC1 */ ADC_Cmd(ADC1, ENABLE); } int main(void) { SystemCoreClockUpdate(); /* Get Core Clock Frequency */ if (SysTick_Config(SystemCoreClock / 1000)) { /* SysTick 1 msec interrupts */ while (1); /* Capture error */ } /* ADC1 Channel Temperature Sensor & VBAT measurement configuration */ ADC1_DMA_Config(); /* Start ADC1 Software Conversion */ ADC_SoftwareStartConv(ADC1); while (1) { /* The VBAT pin is internally connected to a bridge divider by 2 */ ADC1ConvertedVoltage1 = (uint32_t)(ADC1ConvertedValue[0] * 2) * 3300 / 0xfff; VBATVoltage = (float)(ADC1ConvertedVoltage1 / 1000.0); ADC1ConvertedVoltage0 = (uint32_t)(ADC1ConvertedValue[1] * 3300 / 0xfff); Vsense = (float)(ADC1ConvertedVoltage0 / 1000.0); TCelsius = ((Vsense - V25) / AVG_SLOPE) + 25.0 ; } }
First try to use ADC without DMA.
Use the basic example software at STM32F4xx_DSP_StdPeriph_Lib_V1.0.0\Project\STM32F4xx_StdPeriph_Examples\ADC\VBAT_Measurement.
(you can download this STM32F4xx_DSP_StdPeriph_Lib somewhere from the STM32F4 page).
Try to change VBAT to TEMP (should be very straight forward).
And to get better understanding I would strongly recommend you to try to program the registers directly - just re-write the init code in the "VBAT_Measurement" example such, that you initialize the ADC registers directly - these are about 20 registers, but you have to somehow understand them to understand the ADC (check the register description in the Ref Manual register by register - in principle it is sufficient to read these register descriptions carefully, they contain all).
ADC in such an advanced processor always is quite complicated, because you can adapt it to so many different sort of applications, so it has to be extremely flexible (and STM32F4 ADC definitely IS extremely flexible).