2014-10-07 12:10 PM
I have a STM32F207ZG-SK board, and I want to configure pin B0 and A6 to read analog values from another board.
Did I do the setup for pin B0 and A6 correctly? I checked to see if it has ADC and it does, so I just changed certain areas of the code. The code was originally for Pin A0 and C5.
GPIO.B0 --> ADC12_IN8 --> ADC 1 or 2, and channel 8
GPIO.A6 --> ADC12_IN6 --> ADC 1 or 2, and channel 6The code was originally for GPIO.A0 and GPIO.C5. GPIO.B0 is replacing GPIO.A0 and GPIO.A6 is replacing GPIO.C5. I have highlighted the changes that I have made in the code below , but still the code doesn't work, and I don't know what I am missing.The data sheet is locatedhttp://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/CD00237391.pdf
. Below is the code: /****** Setup and Initialization*****/GPIO_InitTypeDef GPIO_InitStructure;ADC_InitTypeDef ADC_InitStructure;DMA_InitTypeDef DMA_InitStructure;ADC_CommonInitTypeDef ADC_CommonInitStructure; __IO Int16U Adcdata[2];__IO float Adc1=0;__IO float Adc2=0;float Adc1_ref=0;float Adc2_ref=0;__IO uint16_t Adc1con=0;__IO uint16_t Adc2con=0; ENTR_CRT_SECTION(); if(SysTick_Config(SystemCoreClock/10000)) { while (1); } EXT_CRT_SECTION(); &sharpdefine ADC_CCR_ADDRESS ((uint32_t)0x40012308);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2| RCC_AHB1Periph_GPIOB
| RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOE, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2 |RCC_APB2Periph_ADC1 , ENABLE);DMA_StructInit(&DMA_InitStructure); DMA_DeInit(DMA2_Stream0); //Set DMA registers to default valuesDMA_InitStructure.DMA_Channel = DMA_Channel_0;DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_CCR_ADDRESS; //Source address*/DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&Adcdata; //Destination address*/DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;DMA_InitStructure.DMA_BufferSize = 2; //Buffer sizeDMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //source size - 16bitDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // destination size = 16bDMA_InitStructure.DMA_Mode = DMA_Mode_Circular;DMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;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); //Initialize the DMADMA_Cmd(DMA2_Stream0, ENABLE);/*GPIO.B
0 Initialize*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init(GPIOB
, &GPIO_InitStructure);
/*GPIO.A6
Initialize*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6
;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init(GPIOA
, &GPIO_InitStructure);
/*ADC1 Common Init*/ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_6Cycles;ADC_CommonInit(&ADC_CommonInitStructure);/*ADC1 Initialize*/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_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_NbrOfConversion = 1; /* parallel so it is doing one conversion for one channel and one conversion for the other ADC channel*/ADC_Init(ADC1, &ADC_InitStructure);//ADC1 PB
0
ADC_RegularChannelConfig(ADC1, ADC_Channel_8
, 1, ADC_SampleTime_56Cycles);
/*ADC2 Common Initialization*/ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;ADC_CommonInit(&ADC_CommonInitStructure);/*ADC2 Initialization*/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_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_NbrOfConversion = 1; //parallel ADC's for both channels. This is for each oneADC_Init(ADC2, &ADC_InitStructure);/*ADC2 regular TRIMER_CHANNEL configuration*/ADC_RegularChannelConfig(ADC2, ADC_Channel_6
, 1, ADC_SampleTime_56Cycles);
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);/* Enable ADCs */ADC_Cmd(ADC1, ENABLE);ADC_Cmd(ADC2, ENABLE);/*Enable DMA for ADC1*/ADC_DMACmd(ADC1, ENABLE);/*Turn on Backlight*/GLCD_Backlight(BACKLIGHT_ON);GLCD_SetFont(&Terminal_9_12_6,0x000F00,0x00FF0);GLCD_SetWindow(10,116,131,131);ADC_SoftwareStartConv(ADC1);Adc1=(((float)Adcdata[0]) * 3.3)/4096; //read voltage value from ADC1Adc2=(((float)Adcdata[1]) * 3.3)/4096; //read voltage value from ADC2 #dma #stm32f2 #gpio #adc2014-10-07 01:34 PM
Common stuff needs to be done once, only. You're not scanning, and the trigger/fields within the ADC configuration are not completely set up, so might contain random data. Probably also want to wait for the ADC to complete the conversion.
I'd do it this way// STM32 ADC IQ Sample (PB0, PA6) STM32F4 Discovery - sourcer32@gmail.com
// pins probably clash, should be workable on F207 or F407 parts
#include ''stm32f4_discovery.h''
/**************************************************************************************/
void RCC_Configuration(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* ADC Channel 6 -> PA6 ADC12_IN6
ADC Channel 8 -> PB0 ADC12_IN8
*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/**************************************************************************************/
void ADC_Configuration(void)
{
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_InitTypeDef ADC_InitStructure;
/* ADC Common Init - COMMON - Do it once, do it first */
ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; // 2 half-words one by one, 1 then 2
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 1 Channel
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // Continuous Conversions
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; // Ignored
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Init(ADC2, &ADC_InitStructure); // Mirror on ADC2
/* ADC1 regular channel 8 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_56Cycles); // PB0
/* ADC2 regular channel 6 configuration */
ADC_RegularChannelConfig(ADC2, ADC_Channel_6, 1, ADC_SampleTime_56Cycles); // PA6
/* Enable DMA request after last transfer (Multi-ADC mode) */
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Enable ADC2 */
ADC_Cmd(ADC2, ENABLE);
}
/**************************************************************************************/
#define BUFFERSIZE 800 // I+Q maximal x2 HT/TC at half rate
__IO uint16_t ADCDualConvertedValues[BUFFERSIZE]; // Filled as pairs ADC1, ADC2
static void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCDualConvertedValues[0];
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x40012308; // CDR_ADDRESS; Packed ADC1, ADC2
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = BUFFERSIZE; // Count of 16-bit words
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_Enable;
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);
/* Enable DMA Stream Half / Transfer Complete interrupt */
DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE);
/* DMA2_Stream0 enable */
DMA_Cmd(DMA2_Stream0, ENABLE);
}
/**************************************************************************************/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the DMA Stream IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**************************************************************************************/
void DMA2_Stream0_IRQHandler(void) // Called at maximal sample rate, LED Toggles at half
{
/* Test on DMA Stream Half Transfer interrupt */
if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0))
{
/* Clear DMA Stream Half Transfer interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_HTIF0);
/* Turn LED3 off: Half Transfer */
STM_EVAL_LEDOff(LED3);
// Add code here to process first half of buffer (ping)
}
/* Test on DMA Stream Transfer Complete interrupt */
if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0))
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
/* Turn LED3 on: End of Transfer */
STM_EVAL_LEDOn(LED3);
// Add code here to process second half of buffer (pong)
}
}
/**************************************************************************************/
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
DMA_Configuration();
ADC_Configuration();
STM_EVAL_LEDInit(LED3); /* Configure LEDs to monitor program status */
STM_EVAL_LEDOn(LED3); /* Turn LED3 on, toggling means it working, needs scope */
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConv(ADC1);
while(1); // Don't want to exit
}
/**************************************************************************************/
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d
'', file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
/**************************************************************************************/
2014-10-08 05:25 AM
2014-10-08 06:26 AM
Thank-you for your reply clive1.
I'm still getting 0.0 as my values for Adc1 and Adc2, any ideas why?So I placed my reading for Adc1 and Adc2 in the interrupts. I'm fairly new to this. Thank-you so much for your patience.2014-10-08 08:26 AM
I'm still getting 0.0 as my values for Adc1 and Adc2, any ideas why?
Is the computation broken? What integer values are you observing in the acquisition buffer? Use a debugger, look at the Memory View.
2014-10-08 11:40 AM
2014-10-08 12:44 PM
You have one channel, you're not scanning, ie going between multiple channels in sequence.
Dual means two (2), not three (3), you'll want a triple mode and review the behaviour of the common data register.Local variables on the stack contain random junk, this may cause initialization issues, or odd behaviour.MultiMode re-enables itself once started. Enable DMA if it suits you.2014-10-08 05:49 PM
Hi clive1,
Thanks again for your response. I found two errors that I did, thanks to your comments :)1. ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_RegSimult;2. RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_ADC3, ENABLE);3. Used the same GPIOA but the first call was to pin 6 and then I made another call again to pin 0, so I decided to use PB0 instead of PA6. But for Adc1 I am still reading 0.0, but Adc2 and Adc3 are fine. Any ideas?Where do you go to check the CDR_ADDRESS for ADC1, ADC2, and ADC3?I have created [DEAD LINK /public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/STM32Discovery/ADC%20Triple%20Mode%20with%20DMA%20-%20Blank%20for%20ADC1%20Only&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F&TopicsView=https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Discovery/AllItems.aspx¤tviews=2]another post for this question since it is off topic and may confuse additional users reading this post. Note, for ADC_DeInit and one time initialization solved the problem for this post. Your kindness and guidance is greatly appreciated. Hopefully, I will gain enough knowledge about this micro so that I can pass it on to other people.