2025-05-12 12:03 AM
Hi all.
I have this piece of code:
__HAL_RCC_CORDIC_CLK_ENABLE();
CORDIC->CSR |= CORDIC_CSR_NARGS;
CORDIC->CSR |= (CORDIC_CSR_PRECISION_3 | CORDIC_CSR_PRECISION_2 | CORDIC_CSR_PRECISION_1 | CORDIC_CSR_PRECISION_0);
CORDIC->CSR |= CORDIC_CSR_FUNC_1; // Phase function (atan2)
int32_t a = 1000;
int32_t b = 1000;
CORDIC->WDATA = a;
CORDIC->WDATA = b;
volatile double result_from_hw = (double)CORDIC->RDATA / 2147483648.0 * 180.0;
volatile double result_from_sw = ((atan2((double)a, (double)b)) / M_PI) * (180.0);
__NOP();
__NOP();
__NOP();
The result from SW is 45 (as expected).
However the result from HW is 43.2.
WHY??
Solved! Go to Solution.
2025-05-18 2:39 AM
Hi all.
I opened a ticket in st support and got the solution.
We SHOULD shift left the sine and cosine to get it's max value as SIGNED 32 bit.
Here is a full example
// Enable clock of CORDIC for atan2 calculation
__HAL_RCC_CORDIC_CLK_ENABLE();
CORDIC->CSR |= CORDIC_CSR_NARGS;
CORDIC->CSR |= (CORDIC_CSR_PRECISION_1 | CORDIC_CSR_PRECISION_0); //Looks like it is enough
CORDIC->CSR |= CORDIC_CSR_FUNC_1; // Phase function (atan2)
uint32_t sine = 1000;
uint32_t cosine = 1000;
uint32_t maximal_left_shift = get_maximal_left_shift(sine, cosine);
sine <<= maximal_left_shift;
cosine <<= maximal_left_shift;
CORDIC->WDATA = cosine;
CORDIC->WDATA = cosine;
double ea_from_cordic = (double)(CORDIC->RDATA) * 180.0 / (double)(0x80000000); //From 0 to 360
While the shift can be calculated with:
uint32_t get_maximal_left_shift(int32_t num1, int32_t num2)
{
if (num1 < 0)
{
num1 = -num1;
}
if (num2 < 0)
{
num2 = -num2;
}
if (num2 > num1)
{
num1 = num2;
}
uint32_t counter = 0;
while (1)
{
num1 <<= 1;
if (num1 < 0)
{
return counter;
} else
{
counter++;
}
}
}
2025-05-12 2:40 AM
Maybe its just the way you let it calculate: first divide, then multiply = bad for precision;
try
(double)(CORDIC->RDATA * 180.0 ) / 2147483648.0 ;
2025-05-12 3:20 AM
I tried but it does not work :(
Furthermore, I checked the register value:
volatile uint32_t register_value = CORDIC->RDATA;
volatile double result_from_hw = (double)(register_value * 180.0 ) / 2147483648.0;
volatile double result_from_sw = ((atan2((double)a, (double)b)) / M_PI) * (180.0);
And I got that register_value = 0x1ec0e600.
However I was expecting to get 0x200000 (As 45 is quarter of 180 so 0.25 * 2 ^ 31 = 2 ^29)
2025-05-18 2:39 AM
Hi all.
I opened a ticket in st support and got the solution.
We SHOULD shift left the sine and cosine to get it's max value as SIGNED 32 bit.
Here is a full example
// Enable clock of CORDIC for atan2 calculation
__HAL_RCC_CORDIC_CLK_ENABLE();
CORDIC->CSR |= CORDIC_CSR_NARGS;
CORDIC->CSR |= (CORDIC_CSR_PRECISION_1 | CORDIC_CSR_PRECISION_0); //Looks like it is enough
CORDIC->CSR |= CORDIC_CSR_FUNC_1; // Phase function (atan2)
uint32_t sine = 1000;
uint32_t cosine = 1000;
uint32_t maximal_left_shift = get_maximal_left_shift(sine, cosine);
sine <<= maximal_left_shift;
cosine <<= maximal_left_shift;
CORDIC->WDATA = cosine;
CORDIC->WDATA = cosine;
double ea_from_cordic = (double)(CORDIC->RDATA) * 180.0 / (double)(0x80000000); //From 0 to 360
While the shift can be calculated with:
uint32_t get_maximal_left_shift(int32_t num1, int32_t num2)
{
if (num1 < 0)
{
num1 = -num1;
}
if (num2 < 0)
{
num2 = -num2;
}
if (num2 > num1)
{
num1 = num2;
}
uint32_t counter = 0;
while (1)
{
num1 <<= 1;
if (num1 < 0)
{
return counter;
} else
{
counter++;
}
}
}