2016-08-08 09:34 AM
I am trying to set up DMA access for the ADC channels on the STM32F303 Discovery. I have done this successfully on the STM32F4, and have been trying to transfer it over, but unfortunately the names of a lot of things in the libraries are named differently on the two chips, which makes this task somewhat difficult. The main thing I seem to be missing is the following function, which is present in the F4 libraries but not those of the F303:
ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);My code compiles on the F303, but my DMA memory address always returns 0 in the debugger, regardless of the voltage on the ADC. Is the problem the missing function, and if so what would be the equivalent on the F303? Here is my code, please let me know if you see any problems:&sharpdefine ADC3_DR_ADDRESS ((uint32_t)&ADC3->DR)__IO uint16_t ADC3ConvertedValue = 0;__IO uint16_t ADC3ManualConvo = 0;__IO uint16_t calibration_value = 0;__IO uint32_t TimingDelay = 0;static void ADC3_DMAInit(void);void Delay(__IO uint32_t nTime);int main(void){ /*!< At this stage the microcontroller clock setting is already configured, this is done through SystemInit() function which is called from startup file (startup_stm32f30x.s) before to branch to application main. To reconfigure the default setting of SystemInit() function, refer to system_stm32f30x.c file */ ADC3_DMAInit(); ADC_StartConversion(ADC3); while (1) { //tried manual conversion, also returns 0 // while(ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC) == RESET); //ADC3ManualConvo = ADC_GetConversionValue(ADC3); }}static void ADC3_DMAInit(void){ DMA_InitTypeDef DMA_InitStructure; ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; GPIO_InitTypeDef GPIO_InitStructure; // Enable DMA2, GPIOC and ADC34 clock RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC34, ENABLE); DMA_DeInit(DMA2_Channel5); DMA_InitStructure.DMA_PeripheralBaseAddr = ADC3_DR_ADDRESS; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC3ConvertedValue; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 1; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; 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(DMA2_Channel5, &DMA_InitStructure); // Enable DMA2 Channel3 DMA_Cmd(DMA2_Channel5, ENABLE); // Enable GPIO Pins GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOB, &GPIO_InitStructure); ADC_StructInit(&ADC_InitStructure); ADC_VoltageRegulatorCmd(ADC3, ENABLE); Delay(10); ADC_SelectCalibrationMode(ADC3, ADC_CalibrationMode_Single); ADC_StartCalibration(ADC3); while(ADC_GetCalibrationStatus(ADC3) != RESET ); calibration_value = ADC_GetCalibrationValue(ADC3); ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_OneShot; ADC_CommonInitStructure.ADC_TwoSamplingDelay = 0; ADC_CommonInit(ADC3, &ADC_CommonInitStructure); 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 = 1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_Init(ADC3, &ADC_InitStructure); /* ADC1 regular channel7 configuration */ ADC_RegularChannelConfig(ADC3, ADC_Channel_1, 1, ADC_SampleTime_7Cycles5); //ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE); //ADC3->CR2 |= (uint32_t)ADC_CR2_DDS; /* Enable ADC1 */ ADC_Cmd(ADC3, ENABLE);}void Delay(__IO uint32_t nTime){ TimingDelay = nTime; while(TimingDelay != 0);} #adc #stm32f303 #dma2016-08-08 10:08 AM
Based on previous examples posted, I'd say this would be how to get it done after the ADC_Init(), and ADC_RegularChannelConfig() stuff.
...
/* Configures the ADC DMA */
ADC_DMAConfig(ADC3, ADC_DMAMode_Circular);
/* Enable the ADC DMA */
ADC_DMACmd(ADC3, ENABLE);
/* Enable ADC */
ADC_Cmd(ADC3, ENABLE);
/* wait for ADC ADRDY */
while(!ADC_GetFlagStatus(ADC3, ADC_FLAG_RDY));
/* Enable the DMA channel */
DMA_Cmd(DMA2_Channel5, ENABLE);
/* Start ADC Software Conversion */
ADC_StartConversion(ADC3);
2016-08-08 10:58 AM
Hey I tried changing my function as you described. ADC is still not working with DMA access. I noticed when debugging that my program was getting stuck in the while(ADC_GetCalibrationStatus(ADC3) != RESET ) and the while(!ADC_GetFlagStatus(ADC3, ADC_FLAG_RDY)) loops. I tried commenting them out and the program run, but no conversion took place.
Does the fact that those while statements are looping forever give any hint as to what might be going on? Or is there something I am still doing wrong in my function?static void ADC3_DMAInit(void){ DMA_InitTypeDef DMA_InitStructure; ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; GPIO_InitTypeDef GPIO_InitStructure; // Enable DMA2, GPIOC and ADC34 clock RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC34, ENABLE); DMA_DeInit(DMA2_Channel5); DMA_InitStructure.DMA_PeripheralBaseAddr = ADC3_DR_ADDRESS; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC3ConvertedValue; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 1; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; 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(DMA2_Channel5, &DMA_InitStructure); // Enable DMA2 Channel3 //DMA_Cmd(DMA2_Channel5, ENABLE); // Enable GPIO Pins GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOB, &GPIO_InitStructure); ADC_StructInit(&ADC_InitStructure); /* ADC_VoltageRegulatorCmd(ADC3, ENABLE); Delay(10); ADC_SelectCalibrationMode(ADC3, ADC_CalibrationMode_Single); ADC_StartCalibration(ADC3); while(ADC_GetCalibrationStatus(ADC3) != RESET ); calibration_value = ADC_GetCalibrationValue(ADC3);*/ ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_OneShot; ADC_CommonInitStructure.ADC_TwoSamplingDelay = 0; ADC_CommonInit(ADC3, &ADC_CommonInitStructure); 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 = 1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_Init(ADC3, &ADC_InitStructure); /* ADC1 regular channel7 configuration */ ADC_RegularChannelConfig(ADC3, ADC_Channel_1, 1, ADC_SampleTime_7Cycles5); //ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE); //ADC3->CR2 |= (uint32_t)ADC_CR2_DDS; /* Enable ADC3 */ ADC_DMAConfig(ADC3, ADC_DMAMode_Circular); ADC_DMACmd(ADC3, ENABLE); ADC_Cmd(ADC3, ENABLE); //while(!ADC_GetFlagStatus(ADC3, ADC_FLAG_RDY)); DMA_Cmd(DMA2_Channel5, ENABLE); ADC_StartConversion(ADC3);}2016-08-08 11:29 AM
I'm not actively using F3 parts, does it slave off ADC12 or require other clocks to be enabled?
/* Configure the ADC clocks */
RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div1);
RCC_ADCCLKConfig(RCC_ADC34PLLCLK_Div1);
/* Enable ADC1/2/3/4 clocks */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12 | RCC_AHBPeriph_ADC34, ENABLE);
2016-08-08 11:39 AM
Yes, that was it, now that I added in the clock config function, it works. Thanks!
RCC_ADCCLKConfig(RCC_ADC34PLLCLK_Div1);