cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G4 CORDIC HAL Library HAL_CORDIC_Calculate function

Garnett.Robert
Senior III

Hi,

 

There would appear to be an error in the HAL_CORDIC_Calculate that results in errors when gcc optimsation O3 is turned on.

 

I had the following code:

void CORDIC_SineCalcSingleValue(float radiansNorm, float sin)
{
	float angle_q31f;
	int32_t angle_q31[1];

	/* Convert radians normalised over pi to Q31 format */
	angle_q31f = radiansNorm * Q_31;
	angle_q31[0] = (int32_t)angle_q31f; // Convert to Q31 integer format
	int32_t result_q31[1];							// Output array Cos then Sin

	/* Calc sine and cos with CORDIC */
	if(HAL_CORDIC_Calculate(&hcordic, angle_q31, result_q31, 1, 500) != HAL_OK)  /* HAL_MAX_DELAY */
	{
		// Handle error
		return;
	}

//	/* Compiler barrier to prevent reordering */
//	__asm volatile ("" ::: "memory");
	sin = (float)result_q31[0] / Q_31; // Convert back to float
}

 

My theory is the following although nit is probably wrong.

This code fails because the HAL_CORDIC_Calculate  argument result_q31 is not specified as volatile by the HAL function so the function is "skipped" and it does not return so the if function always executes the

// Handle Error

return;

when the O3 optimisation is on even though.the function returns HAL_OK  By putting a memory barrier in before the sine = ...  the HAL_CORDIC_Calculate is forced to fully evaluate in the order written so that is a fix.  But the real issue is the HAL_CORDIC_Calculate should use a volatile for the result arg as the compiler seems to miss the fact the variable is modified by code when it reads the output register: It seems to think it is changed by the peripheral directly.

HAL_StatusTypeDef HAL_CORDIC_Calculate(
CORDIC_HandleTypeDef *hcordic,
int32_t *pInBuff, 
volatile int32_t *pOutBuff,
uint32_t NbCalc, uint32_t Timeout)

 

/**
  * @brief  Read output data of CORDIC processing, and increment output buffer pointer.
  * @PAram  hcordic pointer to a CORDIC_HandleTypeDef structure that contains
  *         the configuration information for CORDIC module.
  * @PAram  ppOutBuff Pointer to pointer to output buffer.
  * @retval none
  */
static void CORDIC_ReadOutDataIncrementPtr(const CORDIC_HandleTypeDef *hcordic, int32_t **ppOutBuff)
{
  /* First read of output data from the Read Data register */
  **ppOutBuff = (int32_t)READ_REG(hcordic->Instance->RDATA);

  /* Increment output data pointer */
  (*ppOutBuff)++;

  /* Check if second read of output data is expected */
  if (HAL_IS_BIT_SET(hcordic->Instance->CSR, CORDIC_CSR_NRES))
  {
    /* Second read of output data from the Read Data register */
    **ppOutBuff = (int32_t)READ_REG(hcordic->Instance->RDATA);

    /* Increment output data pointer */
    (*ppOutBuff)++;
  }
}

When the function is called the result variable supplied must of course be volatile.

 

oid CORDIC_SineCalcSingleValue(float radiansNorm, float sin)
{
	float angle_q31f;
	int32_t angle_q31[1];

	/* Convert radians normalised over pi to Q31 format */
	angle_q31f = radiansNorm * Q_31;
	angle_q31[0] = (int32_t)angle_q31f; // Convert to Q31 integer format
	volatile int32_t result_q31[1];							// Output array Cos then Sin

	/* Calc sine and cos with CORDIC */
	if(HAL_CORDIC_Calculate(&hcordic, angle_q31, result_q31, 1, 500) != HAL_OK)  /* HAL_MAX_DELAY */
	{
		// Handle error
		return;
	}

	sin = (float)result_q31[0] / Q_31; // Convert back to float
}

 

When the volatile qualifier is used the function works correctly with gcc O3 optimisation.

The entire file for this working code is attached below.

Nay thoughts would be appreciated.

 

 

1 ACCEPTED SOLUTION

Accepted Solutions

Hello @Garnett.Robert 

First, your prototype function is wrong, it should be:

void CORDIC_CosineCalcSingleValue(float radiansNorm, float *cos, float *sin )
void CORDIC_SineCalcSingleValue(float radiansNorm, float *sin)

 

Next, to be able to reproduce your issue and help you to solve your problem, please could you share us:

 - some information about your Dev environment (gcc version , CubeIDE version, CubeFW version, STM32 Device characteristics...)

 - a standalone project 

 

Thank you for your understanding

 

Best Regards

Philippe

View solution in original post

5 REPLIES 5
Saket_Om
ST Employee

Hello @Garnett.Robert 

The output parameters in your functions should be a pointer:

void CORDIC_CosineCalcSingleValue(float radiansNorm, float cos, float sin )
{
	float angle_q31f;
	int32_t angle_q31[1];

	/* Convert radians normalised over pi to Q31 format */
	angle_q31f = radiansNorm * Q_31;
	angle_q31[0] = (int32_t)angle_q31f; // Convert to Q31 integer format
	int32_t result_q31[2];							// Output array Cos then Sin

	/* Calc sine and cos witt CORDIC */
	if(HAL_CORDIC_Calculate(&hcordic, angle_q31, result_q31, 1, 500) != HAL_OK)  /* HAL_MAX_DELAY */
	{
		// Handle error
		return;
	}

	/* Compiler barrier to prevent reordering */
	__asm volatile ("" ::: "memory");
	cos = (float)result_q31[0] / Q_31; // Convert back to float
	sin = (float)result_q31[1] / Q_31; // Convert back to float
}

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om

Could you write the correct syntax exactly as I should have it. 

 

The function works fine with O0 and produces the correct answer, but not with O3. I tried different syntax's, but this is the only one that worked. I also input it into co-pilot and it didn't complain about my syntax. I don't understand that if my syntax is incorrect why am I not getting a hard fault or an invalid result.  When I enter 30 degrees of angle I get a sine of 0.5. This is correct. The odds of a correct answer for q31 are very low.

 

I tried this with  O3 :

void CORDIC_SineCalcSingleValue(float radiansNorm, float sin)
{
	float angle_q31f;
	int32_t angle_q31[1];

	/* Convert radians normalised over pi to Q31 format */
	angle_q31f = radiansNorm * Q_31;
	angle_q31[0] = (int32_t)angle_q31f; // Convert to Q31 integer format
	int32_t result_q31[1];							// Output array Cos then Sin

	/* Calc sine and cos with CORDIC */
	if(HAL_CORDIC_Calculate(&hcordic, angle_q31, &result_q31, 1, 500) != HAL_OK)  /* HAL_MAX_DELAY */
	{
		// Handle error
		return;
	}

 

But it did not work, it executed the return on line 15. I also get the warning on compile: 

passing argument 3 of 'HAL_CORDIC_Calculate' from incompatible pointer type [-Wincompatible-pointer-types] cordicDriver.c /PixiePussAlarmV2_FW/Drivers/CordicDriver/Src line 123 C/C++ Problem

I also examined the example code for the Nucleo G4 and it uses the same sysntax I am using albeit this example uses DMA

		/* Reference sines are calculated using the standard library */
		refSinf[i] = sinf(radiansf[i] * (float)M_PI);
		compFloat[i][0] = degreesf[i];
		compFloat[i][1] = refSinf[i];
		aRefSin[i] = (int32_t)(calculatedSinef[i] * (1 << 31));
	}


  /*## Configure the CORDIC peripheral ####################################*/
  sCordicConfig.Function         = CORDIC_FUNCTION_SINE;     /* sine function */
  sCordicConfig.Precision        = CORDIC_PRECISION_15CYCLES; /* max precision for q1.31 sine */
  sCordicConfig.Scale            = CORDIC_SCALE_0;           /* no scale */
  sCordicConfig.NbWrite          = CORDIC_NBWRITE_1;         /* One input data: angle. Second input data (modulus) is 1 after cordic reset */
  sCordicConfig.NbRead           = CORDIC_NBREAD_1;          /* One output data: sine */
  sCordicConfig.InSize           = CORDIC_INSIZE_32BITS;     /* q1.31 format for input data */
  sCordicConfig.OutSize          = CORDIC_OUTSIZE_32BITS;    /* q1.31 format for output data */

  if (HAL_CORDIC_Configure(&hcordic, &sCordicConfig) != HAL_OK)
  {
    /* Configuration Error */
    Error_Handler();
  }

  /*## Start calculation of sines in DMA mode #############################*/
  if (HAL_CORDIC_Calculate_DMA(&hcordic, aAngles, aCalculatedSin,
                               ARRAY_SIZE, CORDIC_DMA_DIR_IN_OUT) != HAL_OK)
  {
    /* Processing Error */
    Error_Handler();
  }

This code works fine.

Hello @Garnett.Robert 

First, your prototype function is wrong, it should be:

void CORDIC_CosineCalcSingleValue(float radiansNorm, float *cos, float *sin )
void CORDIC_SineCalcSingleValue(float radiansNorm, float *sin)

 

Next, to be able to reproduce your issue and help you to solve your problem, please could you share us:

 - some information about your Dev environment (gcc version , CubeIDE version, CubeFW version, STM32 Device characteristics...)

 - a standalone project 

 

Thank you for your understanding

 

Best Regards

Philippe

Garnett.Robert
Senior III

I'm a knuckle head, I forgot the "*" in my functions

Putting them in fixed the problem. Sorry about that.

Don't worry @Garnett.Robert 

Glad to have helped you

Best Regards

Philippe