2015-04-26 10:36 AM
I am using Cube generated code, exported to EWARM, running on a Nucleo L053R8 board. My question is how to select the active ADC source outside of the ADC initialization code. For instance, with channel 12 and 13 selected in Cube, the ADC initialization is:
/* ADC init function */
void MX_ADC_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc.Instance = ADC1;
hadc.Init.OversamplingMode = DISABLE;
hadc.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV1;
hadc.Init.Resolution = ADC_RESOLUTION12b;
hadc.Init.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
hadc.Init.ScanDirection = ADC_SCAN_DIRECTION_UPWARD;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ContinuousConvMode = DISABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIG_EDGE_NONE;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.EOCSelection = EOC_SINGLE_CONV;
hadc.Init.Overrun = OVR_DATA_PRESERVED;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.LowPowerFrequencyMode = DISABLE;
hadc.Init.LowPowerAutoOff = DISABLE;
HAL_ADC_Init(&hadc);
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_12;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_13;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
}
I have my ADC temp variable defined as:
__IO uint32_t ADCVal = 0;
I'm trying to switch between channels 12 and 13 by doing the following:
while(1)
{
ADC_ChannelConfTypeDef ADCChan;
ADCChan.Channel = ADC_CHANNEL_12;
HAL_ADC_ConfigChannel(&hadc, &ADCChan);
HAL_Delay(1); //give it time to settle
HAL_ADC_Start(&hadc);
HAL_ADC_PollForConversion(&hadc, 10); //poll for conversion
if(HAL_ADC_GetState(&hadc) == HAL_ADC_STATE_EOC)
{
//Get the converted value of regular channel
ADCVal = HAL_ADC_GetValue(&hadc);
}
....output ADCVal (channel 12) to LCD and pause for a second....
ADCChan.Channel = ADC_CHANNEL_13;
HAL_ADC_ConfigChannel(&hadc, &ADCChan);
HAL_Delay(1); //give it time to settle
HAL_ADC_Start(&hadc);
HAL_ADC_PollForConversion(&hadc, 10); //poll for conversion
if(HAL_ADC_GetState(&hadc) == HAL_ADC_STATE_EOC)
{
//Get the converted value of regular channel
ADCVal = HAL_ADC_GetValue(&hadc);
}
...outputADCVal (channel 13) to LCD and pause for a second....
}
I have a potentiometer hooked to channel 13 (PC3) and channel 12 (PC2) is grounded. The LCD is outputting fine, but it is only showing the value of channel i.e. with 3.3V on channel 13 and 0V on channel 12, both are reading 4
Any ideas what I am doing wrong trying to switch between the two? Thanks for your time. #cube #adc #switching2015-04-26 12:55 PM
ADC_ChannelConfTypeDef
structures, they are junk at the moment.
2015-04-26 01:29 PM
It's a one element structure:
/**
* @brief ADC Configuration regular Channel structure definition
*/
typedef struct
{
uint32_t Channel; /*!< the ADC channel to configure
}ADC_ChannelConfTypeDef;
2015-04-26 02:13 PM
2015-04-26 03:31 PM
Getting back to my Assembly roots, I've even tried ''cheating'' by writing directly to the ADC_CHSELR:
ADC_CHSELR = 0x0800; but EWARM apparently doesn't recognize the register names. In this code-already-written-for-you environment, it seems like the actual manipulations of the registers is a lot of smoke and mirrors, and you are tied to sticking with the pre-written libraries. Hopefully I'm just missing something big picture here.2015-04-27 10:00 AM
ADC_CHSELR = 0x0800;
Try this: ADC1->CHSELR = 0x0800;
Cheers, Hal2015-04-27 11:25 AM
Hal,
Awesome. That works. I am still trying to get it to work using the Cube functions like I posted above without any luck. I did mess around with the sampling time which gave very strange results. For instance, if I changed the sampling time to ''ADC_SAMPLETIME_13CYCLES_5'', it would alternate between the two channels twice, then stay on channel 13. If I changed it to '' ADC_SAMPLETIME_239CYCLES_5'', it would just stay on channel 12. Again...smoke and mirrors, and it's really difficult to wade through all the pre-written code to figure out what it's doing or not doing. I'm trying to learn the STM32, and there are just soooo many options. I don't know if I should concentrate my efforts on learning how to get the pre-written libraries to work, or if I should go old school and write my code at the register level.2015-04-27 12:37 PM
I don't know if I should concentrate my efforts on learning how to get the pre-written libraries to work, or if I should go old school and write my code at the register level.
Well I've pretty much written off the L0 as a choice because of the lack of an SPL port. If my money was on the line I'd figure out how similar the implementation of the L0 peripheral were to another STM32 library and port that. Register level is clearly an option, but it gets nuanced and can easily consume man-days of effort to get it right, or change it later on.2015-04-27 02:42 PM
Clive,
Good input - thanks. I chose the L0, because I figured it would be best to start small and work my way up. Where would you start if you were trying to learn an STM32 (or any ARM for that matter) from scratch? I'm kind of overwhelmed. To name a few starting points, there is the Cube MX code generator and examples, examples within IAR from the information center, all sorts of examples through mbed, tons of examples on the web... There seems to be no standardization. Everything seems to be written with a different set of libraries. Any sage advice is appreciated. Joe