EmbeddedRelated.com
Forums
Memfault Beyond the Launch

How to change stm32 m4 adc channel?

Started by Ed Lee April 26, 2021
On 4/28/21 9:36 PM, Ed Lee wrote:
> On Wednesday, April 28, 2021 at 4:41:06 PM UTC-7, Richard Damon wrote: >> On 4/28/21 10:17 AM, Ed Lee wrote: >>> On Wednesday, April 28, 2021 at 1:17:13 AM UTC-7, Michael Kellett wrote: >>>> On 27/04/2021 21:50, Ed Lee wrote: >>>>> On Tuesday, April 27, 2021 at 9:33:12 AM UTC-7, Michael Kellett wrote: >>>>>> On 27/04/2021 16:39, Ed Lee wrote: >>>>>>> On Tuesday, April 27, 2021 at 5:35:04 AM UTC-7, Michael Kellett wrote: >>>>>>>> On 26/04/2021 18:25, Ed Lee wrote: >>>>>>>>> Does anyone know how to do it in register level? >>>>>>>>> >>>>>>>>> I see many code examples using: >>>>>>>>> >>>>>>>>> ADC_ChannelConfTypeDef sConfig = {ADC_CHANNEL_0, 1, ADC_SAMPLETIME_28CYCLES}; >>>>>>>>> HAL_ADC_ConfigChannel(&hadc1, &sConfig); >>>>>>>>> or >>>>>>>>> ADC_RegularChannelConfig(ADC1, ADC_channel_0, 1, ADC_SampleTime_480Cycles); >>>>>>>>> >>>>>>>>> but i don't have access to these routines from arm-gcc. >>>>>>>>> >>>>>>>>> By the way, i am using this to read the adc data: >>>>>>>>> >>>>>>>>> #include "stm32f407xx.h" >>>>>>>>> ADC1->CR2 |= ADC_CR2_SWSTART; // Start A2D >>>>>>>>> while (!(ADC1->SR & ADC_SR_EOC)); // ready wait >>>>>>>>> data = ADC1->DR; >>>>>>>>> >>>>>>>> If you download and install ST's Cube etc you will end up with (amongst >>>>>>>> a LOT of other stuff) the library code that you could use if you want >>>>>>>> functions like: >>>>>>>> >>>>>>>> HAL_ADC_ConfigChannel() >>>>>>>> >>>>>>>> I don't use these - they try to be universal but end up being hard to >>>>>>>> understand and slow. >>>>>>>> >>>>>>>> To drive the ADC directly you will need to study the reference manual >>>>>>>> and register descriptions and it may well help to look at some ST >>>>>>>> examples (from the Cube again). >>>>>>>> >>>>>>>> To address your specific problem: >>>>>>>> >>>>>>>> Assuming a single conversion of one channel and starting after a >>>>>>>> hardware reset: >>>>>>>> >>>>>>>> write the channel to be converted into the SQ1 field of ADC_SQR3 >>>>>>>> >>>>>>>> make sure the L field of ADC_SQR1 = 0 so the ADC does just one conversion >>>>>>>> >>>>>>>> set the SMP field for the channel in question to the sampling time you >>>>>>>> want (ADC_SMPR1 or ADC_SMPR2) >>>>>>>> >>>>>>>> enable the ADC by setting bit 0 in ADC_CR1 >>>>>>>> >>>>>>>> start the conversion by setting bit 30 in ADC_CR2 >>>>>>>> >>>>>>>> (All the above based on Ref manual for STM446xx - check details for your >>>>>>>> own processor.) >>>>>>>> >>>>>>>> You will need to enable the ADC clock but you must have got there already. >>>>>>>> >>>>>>>> MK >>>>>>> >>>>>>> OK, i think this is getting close, but also need to select the Alt-Funct Reg for the port pin. I was hoping to find a complete example of such. >>>>>>> >>>>>> You don't use the GPIO port Alt Function Register for making a pin an >>>>>> analogue input. >>>>>> You do it by setting the mode bits for that pin in the GPIO Mode register. >>>>>> There are two bits for each pin, coded like this: >>>>>> >>>>>> Bits 2y:2y+1 MODERy[1:0]: Port x configuration bits (y = 0..15) >>>>>> These bits are written by software to configure the I/O direction mode. >>>>>> 00: Input (reset state) >>>>>> 01: General purpose output mode >>>>>> 10: Alternate function mode >>>>>> 11: Analog mode >>>>>> >>>>>> I don't have any shareable examples that don't use DMA with scan and >>>>>> usually continuous mode for the ADC which I think might be distracting. >>>>>> >>>>>> MK >>>>> >>>>> So, reading from PA0 or PA1 like this? >>>>> >>>>> RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; // Enable ADC clock >>>>> ADC1->CR2 |= ADC_CR2_ADON; // Enable ADC >>>>> ADC1->SQR1 = 0; // bit 23-20 single coversion >>>>> ADC->SMPR2 = 2; // 28 cycles >>>>> >>>>> #if PA0 >>>>> GPIOA->MODER |= 3; // bit 1-0 Analog mode >>>>> ADC1->SQR3 = 0; // bit 3-0,0 channel 0 >>>>> #endif >>>>> >>>>> #if PA1 >>>>> GPIOA->MODER |= 0xc; // bit 3-2 Analog mode >>>>> ADC1->SQR3 = 1; // bit 3-0,0 channel 1 >>>>> #endif >>>>> >>>>> ADC1->CR2 |= ADC_CR2_SWSTART; // Start ADC >>>>> while (!(ADC1->SR & ADC_SR_EOC)); // ready wait >>>>> DATA = ADC1->DR; // read data >>>>> >>>> Not quite, entries in SMPR1/2 are for each ADC channel, not each entry >>>> in the sequencer. >>>> So for PA1 you need to set SMP1 bit field to 2, >>>> ADC->SMPR2 = (uint32_t)2 << 3; >>> >>> OK, thanks. >>> >>>> Here's a little challenge for you - good practice is to test this code >>>> - and that would mean you should test that the sampling time is actually >>>> what you meant it to be (not that you wrote x bits to y register). >>>> How would you do that ? >>> >>> I guess i can measure the average conversion time from a sampling loop. For 100MHz clock, even 480 cycles are more than enough. >>> >>> One question remain. How does it ties PA0 with channel 0? If it's hard coded, does it mean only port A can be analog? >>> >> Each analog channel is hard tied internally to a given pin. (They are >> all port A from my memory, but scattered about a bit). Read the device >> reference manual for a listing of the capability of each pin. > > OK, i will have dig a bit deeper in the reference manual. > > This info is critical for someone like me new to the STM chip. > > For the (microchip/Atmel) &mu;A SAM world, we have to set them explicitly. > > PORT->Group[1].DIRCLR.reg = PORT_PB09; > // Enable the peripheral multiplexer for PB09 > PORT->Group[1].PINCFG[9].reg |= PORT_PINCFG_PMUXEN; > // Set PB09 to function B which is analog input. > PORT->Group[1].PMUX[4].reg = PORT_PMUX_PMUXO_B; >
The STM pins also have config registers to configure which special function (if any) they are set for. There generally is a table listing every pin and what functions it can connect to.

Memfault Beyond the Launch