AnsweredAssumed Answered

Multi-channel SDADC on STM32F373 using HAL

Question asked by aot on Nov 14, 2016
Latest reply on Dec 11, 2017 by Daniil Zotkin
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 call HAL_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!

Outcomes