• How to change stm32 m4 adc channel?

    From Ed Lee@21:1/5 to Michael Kellett on Tue Apr 27 13:50:43 2021
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael Kellett@21:1/5 to Ed Lee on Wed Apr 28 09:17:08 2021
    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;

    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 ?



    MK

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ed Lee@21:1/5 to Michael Kellett on Wed Apr 28 07:17:06 2021
    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?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Damon@21:1/5 to Ed Lee on Wed Apr 28 19:40:59 2021
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ed Lee@21:1/5 to Richard Damon on Wed Apr 28 18:36:10 2021
    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) μ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;

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Damon@21:1/5 to Ed Lee on Wed Apr 28 22:48:27 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) μ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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)