cancel
Showing results for 
Search instead for 
Did you mean: 

Found 2 bugs with DMA for Input Capture and Sigma Delta ADC

DMårt
Senior III

Hi!

I just want to report that I have found two bugs. There is no errors with the HAL_DMA functions. I assume there is some errors with the predefined constants or enumerations.

Introduction

I'm using STM32CubeIDE 1.7.0 with STM32F373VBTx and firmware V1.11.3

I'm going to enable DMA for two timers. TIM17 and TIM16.

I'm going also to enable DMA for Sigma Delta ADC.

Goal

The goal is that with TIM17 and TIM16, they will work as Input Capture and save the counter value into arrays.

For Sigma Delta ADC, I want to store the ADC values into arrays.

Method - Input Capture

First I enable the input capture with this code.

volatile static uint16_t input_capture0[2] = {0};
volatile static uint16_t input_capture1[2] = {0};
 
void STM32_PLC_Start_Input_Capture(TIM_HandleTypeDef* htim17, TIM_HandleTypeDef* htim16) {
	/*
	 * Input capture for measuring frequency
	 * For TIM17 and TIM16
	 * Timer clock: 48 Mhz
	 * Prescaler: 4799
	 * Counter: 65535 (0xffff)
	 * Update frequency: 0.1526 Hz (1/0.1526 = 6.5535 seconds)
	 * Example: For every second, it will count 10000
	 * Lowest frequency measurement: 1/(0xFFFF*0.0001) = 0.1526 Hz
	 * Highest frequency measurement: 1/(1*0.0001) = 10000 Hz
	 */
	if(HAL_TIM_IC_Start_DMA(htim16, TIM_CHANNEL_1, (uint32_t*)input_capture1, 2) != HAL_OK)
		Error_Handler();
	if(HAL_TIM_IC_Start_DMA(htim17, TIM_CHANNEL_1, (uint32_t*)input_capture0, 2) != HAL_OK)
		Error_Handler();
}

They both DMA are for circular modes.

0693W00000D2UKvQAN.png0693W00000D2ULFQA3.pngThe purpose with the arrays above, is that I can compute the freqeuency by calling the function

static float compute_frequency(uint16_t input_capture[]) {
	/*
	 * Typical worst case scenarios:
	 * T1: 0xFFFF - T0: 0x0
	 * T1: 0x0    - T0: 0xFFFF
	 * T1: 0x7FFF - T0: 0x7FFF
	 * T1: 0x0	  -	T0: 0x0
	 */
	if(input_capture[1] > input_capture[0]) {
		return (float) 1/((input_capture[1] - input_capture[0])*0.0001f);
	} else if(input_capture[1] < input_capture[0]) {
		return (float) 1/((input_capture[1] + 0xFFFF - input_capture[0])*0.0001f);
	} else if(input_capture[1] == 0x7FFF && input_capture[0] == 0x7FFF){
		return (float) 1/(0xFFFF*0.0001f);
	} else {
		return 0;
	}
}
 
float STM32_PLC_Input_Capture_Get(uint8_t i) {
	if(i == 0)
		return compute_frequency((uint16_t*)input_capture0);
	else
		return compute_frequency((uint16_t*)input_capture1);
}

TIM17 and TIM16 have the same configurations.

0693W00000D2UMSQA3.png 

0693W00000D2UMcQAN.pngMethod - Sigma Delta ADC

To enable Sigma Delta ADC, I calling this function.

volatile static int16_t SDADC1_Single[9];
volatile static int16_t SDADC2_Single[3];
volatile static int16_t SDADC3_Differential[5];
static float SDADC_Single_Calibration_Gain[12] = {0};
static float SDADC_Single_Calibration_Bias[12] = {0};
static float SDADC_Differential_Calibration_Gain[5] = {0};
static float SDADC_Differential_Calibration_Bias[5] = {0};
TIM_HandleTypeDef *handler_tim12;
TIM_HandleTypeDef *handler_tim13;
SDADC_HandleTypeDef *handler_sdadc1;
SDADC_HandleTypeDef *handler_sdadc2;
SDADC_HandleTypeDef *handler_sdadc3;
 
void STM32_PLC_Start_Analog_Input(TIM_HandleTypeDef* htim12, TIM_HandleTypeDef* htim13, SDADC_HandleTypeDef* hsdadc1, SDADC_HandleTypeDef* hsdadc2, SDADC_HandleTypeDef* hsdadc3) {
	/*
	 * For TIM12, TIM13
	 * Timer clock: 48 Mhz
	 * Prescaler: 0
	 * Counter: 48000 (0xbb80)
	 * Update frequency: 1000 Hz
	 */
	HAL_TIM_OC_Start(htim13, TIM_CHANNEL_1); /* TIM13 Channel 1 is trigger source for SDADC1 */
	HAL_TIM_OC_Start(htim12, TIM_CHANNEL_1); /* TIM12 Channel 1 is trigger source for SDADC2 */
	HAL_TIM_OC_Start(htim12, TIM_CHANNEL_2); /* TIM12 Channel 2 is trigger source for SDADC3 */
	if (HAL_SDADC_CalibrationStart(hsdadc1, SDADC_CALIBRATION_SEQ_1) != HAL_OK)
		Error_Handler();
	if (HAL_SDADC_CalibrationStart(hsdadc2, SDADC_CALIBRATION_SEQ_1) != HAL_OK)
		Error_Handler();
	if (HAL_SDADC_CalibrationStart(hsdadc3, SDADC_CALIBRATION_SEQ_1) != HAL_OK)
		Error_Handler();
	if (HAL_SDADC_PollForCalibEvent(hsdadc1, HAL_MAX_DELAY) != HAL_OK)
		Error_Handler();
	if (HAL_SDADC_PollForCalibEvent(hsdadc2, HAL_MAX_DELAY) != HAL_OK)
		Error_Handler();
	if (HAL_SDADC_PollForCalibEvent(hsdadc3, HAL_MAX_DELAY) != HAL_OK)
		Error_Handler();
	if(HAL_SDADC_InjectedStart_DMA(hsdadc1, (uint32_t*)SDADC1_Single, 9) != HAL_OK)
		Error_Handler();
	if(HAL_SDADC_InjectedStart_DMA(hsdadc2, (uint32_t*)SDADC2_Single, 3) != HAL_OK)
		Error_Handler();
	if(HAL_SDADC_InjectedStart_DMA(hsdadc3, (uint32_t*)SDADC3_Differential, 5) != HAL_OK)
		Error_Handler();
 
	/* Save */
	handler_tim13 = htim13;
	handler_tim12 = htim12;
	handler_sdadc1 = hsdadc1;
	handler_sdadc2 = hsdadc2;
	handler_sdadc3 = hsdadc3;
 
}

Here is DMA configurations for SDADC1, SDADC2 and SDADC3.0693W00000D2UMrQAN.pngI have also selected Injected Conversion and using a timer for calling the SDADC function.

0693W00000D2UMwQAN.pngAnd the timers TIM12 and TIM13 for SDADC.

0693W00000D2UNGQA3.pngI also can change gain on the Sigma Delta ADC while the STM32 processor is running.

/* Inline is only for optimization */
static inline int16_t* array_to_pointer(int16_t array[]){
	return array; /* This return the address */
}
 
void STM32_PLC_Analog_Input_Set_Gain_Offset(uint8_t sdadc, uint8_t configuration_index, uint8_t gain, uint16_t offset) {
	/* Initial */
	SDADC_ConfParamTypeDef ConfParamStruct = {0};
	ConfParamStruct.CommonMode = SDADC_COMMON_MODE_VSSA;
	SDADC_HandleTypeDef *handler;
	uint8_t length_DMA;
	uint32_t *array_DMA;
 
	/* Stop DMA */
	switch(sdadc){
	case 1:
		/* Stop DMA for SDADC1 */
		if(HAL_SDADC_InjectedStop_DMA(handler_sdadc1) != HAL_OK)
			Error_Handler();
		handler = handler_sdadc1;
		length_DMA = 9;
		array_DMA = (uint32_t*)array_to_pointer((int16_t*)SDADC1_Single);
		ConfParamStruct.InputMode = SDADC_INPUT_MODE_SE_ZERO_REFERENCE;
		break;
	case 2:
		/* Stop DMA for SDADC2 */
		if(HAL_TIM_OC_Stop(handler_tim12, TIM_CHANNEL_1))
			Error_Handler();
		if(HAL_SDADC_InjectedStop_DMA(handler_sdadc2) != HAL_OK)
			Error_Handler();
		handler = handler_sdadc2;
		length_DMA = 3;
		array_DMA = (uint32_t*)array_to_pointer((int16_t*)SDADC2_Single);
		ConfParamStruct.InputMode = SDADC_INPUT_MODE_SE_ZERO_REFERENCE;
		break;
	case 3:
		/* Stop DMA for SDADC3 */
		if(HAL_SDADC_InjectedStop_DMA(handler_sdadc3) != HAL_OK)
			Error_Handler();
		handler = handler_sdadc3;
		length_DMA = 5;
		array_DMA = (uint32_t*)array_to_pointer((int16_t*)SDADC3_Differential);
		ConfParamStruct.InputMode = SDADC_INPUT_MODE_DIFF;
		break;
	default:
		/* Stop DMA for SDADC1 */
		if(HAL_SDADC_InjectedStop_DMA(handler_sdadc1) != HAL_OK)
			Error_Handler();
		handler = handler_sdadc1;
		length_DMA = 9;
		array_DMA = (uint32_t*)array_to_pointer((int16_t*)SDADC1_Single);
		ConfParamStruct.InputMode = SDADC_INPUT_MODE_SE_ZERO_REFERENCE;
		break;
	}
 
	/* Set gain and offset */
	switch(gain){
	case 0:
		ConfParamStruct.Gain = SDADC_GAIN_1_2;
		break;
	case 1:
		ConfParamStruct.Gain = SDADC_GAIN_1;
		break;
	case 2:
		ConfParamStruct.Gain = SDADC_GAIN_2;
		break;
	case 3:
		ConfParamStruct.Gain = SDADC_GAIN_4;
		break;
	case 4:
		ConfParamStruct.Gain = SDADC_GAIN_8;
		break;
	case 5:
		ConfParamStruct.Gain = SDADC_GAIN_16;
		break;
	case 6:
		ConfParamStruct.Gain = SDADC_GAIN_32;
		break;
	default:
		ConfParamStruct.Gain = SDADC_GAIN_1;
		offset = 0;
		break;
	}
	ConfParamStruct.Offset = offset;
 
	/* Set calibration */
	if (HAL_SDADC_PrepareChannelConfig(handler, configuration_index, &ConfParamStruct) != HAL_OK)
	    Error_Handler();
 
	/* Start ADC again */
	if (HAL_SDADC_CalibrationStart(handler, SDADC_CALIBRATION_SEQ_1) != HAL_OK)
		Error_Handler();
	if (HAL_SDADC_PollForCalibEvent(handler, HAL_MAX_DELAY) != HAL_OK)
		Error_Handler();
	if(HAL_SDADC_InjectedStart_DMA(handler, array_DMA, length_DMA) != HAL_OK)
		Error_Handler();
}

Result - Input Capture

These arrays gets different values when the STM32 processor runs.

volatile static uint16_t input_capture0[2] = {0};
volatile static uint16_t input_capture1[2] = {0};

I can read them, but ONLY input_capture0 (TIM17) get updates values. ONLY input_capture1 (TIM16) get values once, then nothing happens any more.

Result - Sigma Delta ADC

When I try to change the gain for the Sigma Delta ADC, I call this function. This is just an example for illusration:

if(HAL_SDADC_InjectedStop_DMA(mySDADCHandler) != HAL_OK)
	Error_Handler();

Then inside the function, this calls to abort the HAL_DMA.

HAL_StatusTypeDef HAL_SDADC_InjectedStop_DMA(SDADC_HandleTypeDef *hsdadc)
{
  HAL_StatusTypeDef status;
 
  /* Check parameters */
  assert_param(IS_SDADC_ALL_INSTANCE(hsdadc->Instance));
 
  /* Check SDADC state */
  if((hsdadc->State != HAL_SDADC_STATE_INJ) && \
     (hsdadc->State != HAL_SDADC_STATE_REG_INJ))
  {
    /* Return error status */
    status = HAL_ERROR;
  }
  else
  {
    /* Clear JDMAEN bit in SDADC_CR1 register */
    hsdadc->Instance->CR1 &= ~(SDADC_CR1_JDMAEN);
 
    /* Stop current DMA transfer */
    if(HAL_DMA_Abort(hsdadc->hdma) != HAL_OK)
    {
      /* Set SDADC in error state */
      hsdadc->State = HAL_SDADC_STATE_ERROR;
      status = HAL_ERROR;
    }

Continue below:

12 REPLIES 12

Great! And for the STM32CubeIDE?

Hello @Daniel Mårtensson​ ,

Yes the issue is also fixed in STM32CubeIDE v1.10.0 since it contains the MX v6.6.0 plugin.

Sara.

How is it going with the LwIP bug for the 407 series?