cancel
Showing results for 
Search instead for 
Did you mean: 

Multi-channel SDADC on STM32F373 using HAL

aaron239955
Associate
Posted on November 14, 2016 at 14:02

I'm trying to get the SDADC on a STM32F373 working for muti-channel acquisitions using the HAL (and not standard peripheral library). I've not found a good multi-channel tutorial/example that uses the HAL, so I'm turning to asking here. Apologies if this has been answered before and I have missed the response.

I've tried to piece something together by using UM1786, the firmware examples provided with the STM32F3Cube firmware, and also inferring behaviour from the normal ADC, but am stuck.

I am using SDADC1, channels 4,5,6,7,8. At the moment I am going for what I hoped would be the simplest example and manually trigger and poll for conversion. It is my understanding that the only way to have multiple channels on the SDADC is to use an injected trigger, and I am using software trigger for this.

The code below isn't enough for it to be a working example unfortunately, hopefully it is enough for someone to comment though.

Configure the SDADC (this was generated by STM32CubeMx):

static

void

MX_SDADC1_Init(

void

)

{

SDADC_ConfParamTypeDef ConfParamStruct;

/**Configure the SDADC low power mode, fast conversion mode,

slow clock mode and SDADC1 reference voltage

*/

hsdadc1.Instance = SDADC1;

hsdadc1.Init.IdleLowPowerMode = SDADC_LOWPOWER_NONE;

hsdadc1.Init.FastConversionMode = SDADC_FAST_CONV_DISABLE;

hsdadc1.Init.SlowClockMode = SDADC_SLOW_CLOCK_DISABLE;

hsdadc1.Init.ReferenceVoltage = SDADC_VREF_VDDA;

hsdadc1.InjectedTrigger = SDADC_SOFTWARE_TRIGGER;

if

(HAL_SDADC_Init(&hsdadc1) != HAL_OK)

{

Error_Handler();

}

/**Configure the Injected Mode

*/

if

(HAL_SDADC_SelectInjectedDelay(&hsdadc1, SDADC_INJECTED_DELAY_NONE) != HAL_OK)

{

Error_Handler();

}

if

(HAL_SDADC_SelectInjectedTrigger(&hsdadc1, SDADC_SOFTWARE_TRIGGER) != HAL_OK)

{

Error_Handler();

}

/**Set parameters for SDADC configuration 0 Register

*/

ConfParamStruct.InputMode = SDADC_INPUT_MODE_SE_ZERO_REFERENCE;

ConfParamStruct.Gain = SDADC_GAIN_1;

ConfParamStruct.CommonMode = SDADC_COMMON_MODE_VSSA;

ConfParamStruct.Offset = 0;

if

(HAL_SDADC_PrepareChannelConfig(&hsdadc1, SDADC_CONF_INDEX_0, &ConfParamStruct) != HAL_OK)

{

Error_Handler();

}

/**Configure the Regular Channel

*/

if

(HAL_SDADC_AssociateChannelConfig(&hsdadc1, SDADC_CHANNEL_4, SDADC_CONF_INDEX_0) != HAL_OK)

{

Error_Handler();

}

/**Configure the Injected Channel

*/

if

(HAL_SDADC_InjectedConfigChannel(&hsdadc1, SDADC_CHANNEL_4, SDADC_CONTINUOUS_CONV_OFF) != HAL_OK)

{

Error_Handler();

}

/**Configure the Injected Channel

*/

if

(HAL_SDADC_AssociateChannelConfig(&hsdadc1, SDADC_CHANNEL_5, SDADC_CONF_INDEX_0) != HAL_OK)

{

Error_Handler();

}

if

(HAL_SDADC_InjectedConfigChannel(&hsdadc1, SDADC_CHANNEL_5, SDADC_CONTINUOUS_CONV_OFF) != HAL_OK)

{

Error_Handler();

}

/**Configure the Injected Channel

*/

if

(HAL_SDADC_AssociateChannelConfig(&hsdadc1, SDADC_CHANNEL_6, SDADC_CONF_INDEX_0) != HAL_OK)

{

Error_Handler();

}

if

(HAL_SDADC_InjectedConfigChannel(&hsdadc1, SDADC_CHANNEL_6, SDADC_CONTINUOUS_CONV_OFF) != HAL_OK)

{

Error_Handler();

}

/**Configure the Injected Channel

*/

if

(HAL_SDADC_AssociateChannelConfig(&hsdadc1, SDADC_CHANNEL_7, SDADC_CONF_INDEX_0) != HAL_OK)

{

Error_Handler();

}

if

(HAL_SDADC_InjectedConfigChannel(&hsdadc1, SDADC_CHANNEL_7, SDADC_CONTINUOUS_CONV_OFF) != HAL_OK)

{

Error_Handler();

}

/**Configure the Injected Channel

*/

if

(HAL_SDADC_AssociateChannelConfig(&hsdadc1, SDADC_CHANNEL_8, SDADC_CONF_INDEX_0) != HAL_OK)

{

Error_Handler();

}

if

(HAL_SDADC_InjectedConfigChannel(&hsdadc1, SDADC_CHANNEL_8, SDADC_CONTINUOUS_CONV_OFF) != HAL_OK)

{

Error_Handler();

}

}

Then in main:

int

main(

void

) {

HAL_Init();

SystemClock_Config();

MX_SDADC1_Init();

MX_USART1_UART_Init();

//etc. other configuration steps required

uint32_t tADC = HAL_GetTick();

uint32_t channel;

uint16_t adcVal;

while

(1){

if

(HAL_GetTick() > tADC + 100){

tADC +=100;

HAL_SDADC_InjectedStart(&hsdadc1);

HAL_SDADC_PollForInjectedConversion(&hsdadc1, HAL_MAX_DELAY);

adcVal = HAL_SDADC_InjectedGetValue(&hsdadc1, (uint32_t *) &channel);

char

msg[100];

sprintf

(msg,

''%u\t%u''

, adcVal, channel);

HAL_UART_Transmit(&huart1, (uint8_t*)msg,

strlen

(msg), HAL_MAX_DELAY);

}

}

}

This is where I started to run into trouble. As far as I can tell, the injected conversion is starting and the polling is working correctly, but can only obtain results for channel 8. I originally thought the second argument for HAL_SDADC_InjectedGetValue would be to specify what channel to get the result for, but it actually seems to accept channel by reference, and upon return it has modified that to the value 8.

So then I thought I need to callHAL_SDADC_InjectedGetValue multiple times to get data from all the channel, and the order would be descending from channel 8 down. But calling it twice just returns 0 for both the adcVal and channel. Same with running HAL_SDADCPollForInjectedConversion and then HAL_SDADC_InjectedGetValue.

for my application I will probably want to use DMA and either have a continuous conversion, or a timer driving the conversion so it is at a specific sampling rate. However it's not clear to me how the DMA buffer is filled for multiple channel data.

Thanks in advance!

#sdadc

4 REPLIES 4
aaron239955
Associate
Posted on November 17, 2016 at 13:53

Following this up - managed to get what I need working.

It turns out that the version of STM32CubeMx I was using (1.16) produced incorrect configuration code for setting the injected channels. Updating to 1.17 now merges all of the HAL_SDADC_InjectedConfigChannel calls into just one:

if
(HAL_SDADC_InjectedConfigChannel(&hsdadc1, SDADC_CHANNEL_4|SDADC_CHANNEL_5
|SDADC_CHANNEL_6|SDADC_CHANNEL_7
|SDADC_CHANNEL_8, SDADC_CONTINUOUS_CONV_OFF) != HAL_OK)
{
Error_Handler();
}

After doing this I was then able to: 1. Get multi channel continuous conversions working with DMA transfer. 2. Get multi channel timer based conversions working with DMA transfer. I think ST could definitely help by providing documented examples for multi-channel SDADC conversions.
Posted on April 24, 2017 at 10:36

Hi,

I have encountered some problems with Multi-channel SDADC and I was wondering if you could help me with that.

I have enabled SDADC1_AIN4P, 

SDADC1_AIN7P and SDADC1_AIN8P (PB2, PE8, PE9 pins respectively) using STMCubeMX and set  the Conversion Configuration to zero. Each channel is in the 'Single-Ended Zero Reference' mode. 

My code in the 'main' is pretty the same as yours.

The problem is that the 'adcVal's of each channel are not transmitted one after the other. In other words, I expect that in the output, I first see the adcVal for channel 4, then channel 7 and finally channel 8. but this does not happen!!!

would appreciate if you could me on this matter.

Tnx

Sirma Siang
ST Employee
Posted on July 04, 2017 at 18:06

Hello Aot and Omid,

I would like to thanks you for your feedback.

There are two symptoms described in this thread.

First I advice you to open a new thread if the symptoms are not the one already described.

Second about the SDADC multichannel configuration with the 'or', I tested it with what will be CubeMX4.22 (in few days from now), combined with FM version 1.8.0 and 1.9.0. This is working as expected... the 'ored' parameters are well generated.

Third, about the adcVal symptom, could you please share your ioc file, then I can try it in my side.

Kind regards

Sirma

Daniil Zotkin
Associate
Posted on December 11, 2017 at 12:05

I had this problem too. If you are using one hsdadc with multiple injected channels, you can use this code to get all injected channels:

uint32_t ch;
uint32_t raw
for(int i = 0; i < NUMOFINJECTEDCHANNELS; i++) {
 raw = HAL_SDADC_InjectedGetValue(&hsdadc1, &ch);
 if(ch != 0) {
 // GetValue was successful. Place your code here
 }
 if(hsdadc1.State != HAL_SDADC_STATE_READY) {
 HAL_SDADC_PollForInjectedConversion(&hsdadc1, HAL_MAX_DELAY);
 }
}�?�?�?�?�?�?�?�?�?�?�?�?�?