2025-06-23 1:34 AM
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.
Solved! Go to Solution.
2025-06-24 1:29 AM
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
2025-06-23 5:28 AM
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
}
2025-06-23 6:46 PM
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.
2025-06-24 1:29 AM
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
2025-06-24 7:10 PM
I'm a knuckle head, I forgot the "*" in my functions
Putting them in fixed the problem. Sorry about that.
2025-06-25 10:03 AM