Skip to main content
Graduate II
June 23, 2025
Solved

STM32G4 CORDIC HAL Library HAL_CORDIC_Calculate function

  • June 23, 2025
  • 2 replies
  • 608 views

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.

 

 

    This topic has been closed for replies.
    Best answer by PLE N.1

    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

    2 replies

    Technical Moderator
    June 23, 2025

    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
    }

     

    Graduate II
    June 24, 2025

    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.

    PLE N.1Answer
    ST Employee
    June 24, 2025

    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

    Graduate II
    June 25, 2025

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

    Putting them in fixed the problem. Sorry about that.

    ST Employee
    June 25, 2025

    Don't worry @Garnett.Robert 

    Glad to have helped you

    Best Regards

    Philippe