cancel
Showing results for 
Search instead for 
Did you mean: 

Switching pin between ADC and General IO

ebommer
Associate II
Posted on April 09, 2014 at 18:53

Hi All,

What I would like to do is when I receive a CAN bus message with data equal to ''12'' I will configure GPIOB Pin 0 to an Analog input, and when the data is 11 it will be reconfigured to an General purpose I/O. 

&sharpdefine ADC1_DR_Address    ((uint32_t)0x4001244C)

__IO uint16_t ADCConvertedValue[5];  

void Port_Config(void)

{

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); 

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA| RCC_APB2Periph_GPIOB, ENABLE);

  

/* Configure PA.0,1,2,3 as analog input -------------------------*/

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Configure PB.0 as Output   -------------------------*/

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

  GPIO_Init(GPIOB, &GPIO_InitStructure);

  /* DMA1 channel1 configuration -------------------------------*/

  DMA_DeInit(DMA1_Channel1);

  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;

  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue;

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

  DMA_InitStructure.DMA_BufferSize = 4;

  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(DMA1_Channel1, &DMA_InitStructure);

  

  /* Enable DMA1 channel1 */

  DMA_Cmd(DMA1_Channel1, ENABLE);

  

  /* ADC1 configuration -----------------------------------------*/

  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

  ADC_InitStructure.ADC_ScanConvMode = ENABLE;

  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

  ADC_InitStructure.ADC_NbrOfChannel = 4;

  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC1 regular channel 00 configuration */ 

  ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);

  /* ADC1 regular channel 01 configuration */ 

  ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);

  /* ADC1 regular channel 02 configuration */ 

  ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);

  /* ADC1 regular channel 03 configuration */ 

  ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);

  /* Enable ADC1 DMA */

  ADC_DMACmd(ADC1, ENABLE);

  

  /* Enable ADC1 */

  ADC_Cmd(ADC1, ENABLE);

  /* Enable ADC1 reset calibration register */   

  ADC_ResetCalibration(ADC1);

  /* Check the end of ADC1 reset calibration register */

  while(ADC_GetResetCalibrationStatus(ADC1));

  /* Start ADC1 calibration */

  ADC_StartCalibration(ADC1);

  /* Check the end of ADC1 calibration */

  while(ADC_GetCalibrationStatus(ADC1));

     

  /* Start ADC1 Software Conversion */ 

  ADC_SoftwareStartConvCmd(ADC1, ENABLE);

}

So far in my attempts when I add an additional A/D, all of my conversions that used to work stop working.

init main(void)

{

......

// if(CAN message = 11,  GPIOB Pin 0 conf. as an General Purpose I/O)

 case 11:                        

 /* Configure PB0 Out On */

 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

 GPIO_Init(GPIOB, &GPIO_InitStructure);

                        

 GPIO_WriteBit(GPIOB,GPIO_Pin_0,Bit_SET);

 CAN_AppTX.data[0] = 0x01;

break;

//if(CAN message = 12,  GPIOB Pin 0 configured as an analog Input)

 case 12:                        

 /* Configure PB0 A/D */                 

 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

 GPIO_Init(GPIOB, &GPIO_InitStructure);

 ADC_InitStructure.ADC_NbrOfChannel = 5;

 ADC_Init(ADC1, &ADC_InitStructure);

                     

 ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 5,  ADC_SampleTime_55Cycles5);

 ADC_Cmd(ADC1, ENABLE);

 ADC_SoftwareStartConvCmd(ADC1, ENABLE);

                        

 DMA_InitStructure.DMA_BufferSize = 5;

 DMA_Init(DMA1_Channel1, &DMA_InitStructure);

 DMA_Cmd(DMA1_Channel1, ENABLE);

........

}

Thank you for any help.

  

#stm32-adc
6 REPLIES 6
Posted on April 09, 2014 at 19:06

void Port_Config(int mode)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); 
ADC_DeInit(ADC1);
DMA_DeInit(DMA1_Channel1);
/* Configure PA.0,1,2,3 as analog input -------------------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure PB.0 as Output or Analogue -------------------------*/
if (mode == 11)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* DMA1 channel1 configuration -------------------------------*/
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = (mode == 11) ? 4 : 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(DMA1_Channel1, &DMA_InitStructure);
/* Enable DMA1 channel1 */
DMA_Cmd(DMA1_Channel1, ENABLE);
/* ADC1 configuration -----------------------------------------*/
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = (mode == 11) ? 4 : 5;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel 00 configuration */ 
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
/* ADC1 regular channel 01 configuration */ 
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);
/* ADC1 regular channel 02 configuration */ 
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);
/* ADC1 regular channel 03 configuration */ 
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);
if (mode == 11)
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 5, ADC_SampleTime_55Cycles5);
/* Enable ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Enable ADC1 reset calibration register */ 
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
/* Start ADC1 calibration */
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));
/* Start ADC1 Software Conversion */ 
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
ebommer
Associate II
Posted on April 09, 2014 at 19:24

Thanks clive1.

I didn't think about that, I could just call my port configuration function anytime I want to reconfigure my IO, even if its just changing a single pin.

Posted on April 09, 2014 at 19:54

I felt this would be a more robust and predictable method of switching over assuming you have the DMA/ADC at some random state when reconfiguring.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
ebommer
Associate II
Posted on April 09, 2014 at 21:20

I have added your suggestions and it works.  I am having a little strange behavior though.  

When I start up 

ADCConvertedValue[0] = GPIOA.Pin0,

ADCConvertedValue[1] = GPIOA.Pin1,

ADCConvertedValue[2] = GPIOA.Pin2,

ADCConvertedValue[3] = GPIOA.Pin3,

after I reconfigure the port the assignment seems to change in the array.

ADCConvertedValue[0] = GPIOB.Pin0,

ADCConvertedValue[1] = GPIOA.Pin0,

ADCConvertedValue[2] = GPIOA.Pin1,

ADCConvertedValue[3] = GPIOA.Pin2,

ADCConvertedValue[3] = GPIOA.Pin3,

I would of expected GPIOB.Pin0 would be 

ADCConvertedValue[3] since the rank equal 5.

I am using the debugger in Keil over JTAG to monitor the array.  

As a difference from your program suggestion I left the pin configuration in the main loop.

From Main

...

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

GPIO_Init(GPIOB, &GPIO_InitStructure);

                    

ADC_Config(8);

CAN_AppTX.data[0] = 0x03;           

void ADC_Config(unsigned char x)

{   

  /* DMA1 channel1 configuration ------------------------------------*/

  DMA_DeInit(DMA1_Channel1);

  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;

  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue;

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

  DMA_InitStructure.DMA_BufferSize = (NumberOfAD == 4) ? 4 : 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(DMA1_Channel1, &DMA_InitStructure);

  

  /* Enable DMA1 channel1 */

  DMA_Cmd(DMA1_Channel1, ENABLE);

  

  /* ADC1 configuration ------------------------------------------*/

  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

  ADC_InitStructure.ADC_ScanConvMode = ENABLE;

  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

  ADC_InitStructure.ADC_NbrOfChannel = (NumberOfAD == 4) ? 4 : 5;

  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC1 regular channel 00 configuration */ 

  ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);

  /* ADC1 regular channel 01 configuration */ 

  ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);

  /* ADC1 regular channel 02 configuration */ 

  ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);

  /* ADC1 regular channel 03 configuration */ 

  ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);

  if(NumberOfAD != 4)

  {

    ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 5, ADC_SampleTime_55Cycles5);

  }

  /* Enable ADC1 DMA */

  ADC_DMACmd(ADC1, ENABLE);

  

  /* Enable ADC1 */

  ADC_Cmd(ADC1, ENABLE);

  /* Enable ADC1 reset calibration register */   

  ADC_ResetCalibration(ADC1);

  /* Check the end of ADC1 reset calibration register */

  while(ADC_GetResetCalibrationStatus(ADC1));

  /* Start ADC1 calibration */

  ADC_StartCalibration(ADC1);

  /* Check the end of ADC1 calibration */

  while(ADC_GetCalibrationStatus(ADC1));

     

  /* Start ADC1 Software Conversion */ 

  ADC_SoftwareStartConvCmd(ADC1, ENABLE);

}

ebommer
Associate II
Posted on April 09, 2014 at 22:05

I just noticed sometime unusual.  Every time I rewrite to the ADC_Config routine the position of the A/D channel 0 can change in the DMA array(not always but quite often) even if the data I write doesn't change.  From a reset A/D 0 is always mapped to DMA array [0], but if I call the routine after its been running I don't know where A/D 0 is writing its data any more.  But the data is always in order it just shifts.  Not sure if this due to some counter in the DMA not being reset.

ebommer
Associate II
Posted on April 09, 2014 at 23:25

I think I figured it out.  I needed to disable the DMA and the A/D before re-configuring. Seems to work now.