Skip to main content
Associate II
February 21, 2024
Solved

Cordic STM32G47 f32_to q31 conversion and vice versa implementation

  • February 21, 2024
  • 5 replies
  • 2006 views

Hi,

i was working in stm32g4 series to implement  CORDIC , but i have noticed cordic is taking 6.5 e-05 sec while normal cos/sin function is taking  2.6e-06sec. let me know where I am making mistake.

below is code  i have implemented.

inline int f32_to_q31( double input )

{

const float Q_31_MAX_F = 1.0f ;// 0x0.FFFFFFp0F;//

const float Q_31_MIN_F = -1.0f;

return (int)roundf(scalbnf(fmaxf(fminf(input,Q_31_MAX_F),Q_31_MIN_F),31));

 

}

 

#define pi 3.14159265359

// convert notation integar to 32 bits float

#define q31_to_f32(x) ldexp((int32_t)x, -31) //q31 represent no in range -1,1

 

float cordic_q31_cosf(float x)

{

CORDIC_ConfigTypeDef sConfig;

int32_t input_q31 = f32_to_q31(fmod(x,2.0f*pi)/(2.0f*pi))<<1;

int32_t output_q31;

sConfig.Function = CORDIC_FUNCTION_COSINE;

sConfig.Precision = CORDIC_PRECISION_6CYCLES;

sConfig.Scale = CORDIC_SCALE_0;

sConfig.NbWrite = CORDIC_NBWRITE_1;

sConfig.NbRead = CORDIC_NBREAD_1;

sConfig.InSize = CORDIC_INSIZE_32BITS;

sConfig.OutSize = CORDIC_OUTSIZE_32BITS;

 

HAL_CORDIC_Configure(&hcordic, &sConfig);

HAL_CORDIC_CalculateZO(&hcordic, &input_q31, &output_q31,1 ,0);

return q31_to_f32(output_q31);

}

 

 

 user code begin

int i;

for(i=0;i<361;i++)

{

radian = (double)(i)*2.0*pi/360.0; //degree to radain (2pi/360)

 

 

 

start_tick= SysTick->VAL;

cordic_cos[i] = cordic_q31_cosf(radian);

stop_tick = SysTick->VAL;

elasped = (float)(start_tick - stop_tick)/170000000.0;

 

 

refrence https://www.youtube.com/watch?v=SeDyNtKRDMU

 }

 

 // normal cos function

int i;

for(i=0;i<361;i++)

{

radian = (double)(i)*2.0*pi/360.0; //degree to radain (2pi/360)

 

 

 

start_tick= SysTick->VAL;

cordic_cos[i] = cosf(radian);

stop_tick = SysTick->VAL;

elasped = (float)(start_tick - stop_tick)/170000000.0;

 }

 

 

 

}

    This topic has been closed for replies.
    Best answer by Tesla DeLorean

    Isn't SysTick a 24-bit down counter? Often at 1/8th the CPU clock?

    Would be better to use DWT CYCCNT

    Also please edit to fix Code Formatting 

    5 replies

    Andrew Neil
    Super User
    February 21, 2024

    Please use this button to properly post source code:

    AndrewNeil_0-1708516957596.png

     

     

    A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
    Pavel A.
    February 21, 2024

    If you want only 32-bit floats, why to use double type? This will cause extra library calls with a single-precision FPU.

     

    SushmitaAuthor
    Associate II
    February 22, 2024

    i tried with, without double type, but still same execution  timing is there  1.5e-05sec

    Tesla DeLorean
    Tesla DeLoreanBest answer
    Guru
    February 21, 2024

    Isn't SysTick a 24-bit down counter? Often at 1/8th the CPU clock?

    Would be better to use DWT CYCCNT

    Also please edit to fix Code Formatting 

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Associate II
    February 22, 2024

    Two remarks, not sure if they solve your problem:

    1. As mentioned above, never mix in double's :)
    2. I use a more "direct" converion from float to q1_31, see below. The stdlib functions you call may induce substantial overhead since they all operate on true floats. 

    Btw, if anyone recognizes a problem in this code, comments are welcome! I tried to get all the borderline cases right, but...

    #define CORDIC_2exp31divPI 683565275.57643158978229477811035f
    #define CORDIC_2exp31 0x1p31f
    #define CORDIC_2exp32 0x1p32f
    #define CORDIC_2exp31m1 0x7FFFFFFFp0f
    
    // theta is the float input 
    	q1_31_t Arg;
    	volatile q1_31_t Res;
    	float thetaScaled;
    // setup CORDIC as required here
    	thetaScaled = theta * CORDIC_2exp31divPI;
    	while (thetaScaled < -CORDIC_2exp31)
    		thetaScaled += CORDIC_2exp32;
    	while (thetaScaled > CORDIC_2exp31m1)
    		thetaScaled -= CORDIC_2exp32;
    	if (thetaScaled < -CORDIC_2exp31)
    		Arg = 0x80000000;
    	else
    		Arg = (q1_31_t)(thetaScaled);
    	asm volatile("": : :"memory");
    	CORDIC->WDATA = Arg;
    	asm volatile("": : :"memory");
    	CORDIC->WDATA = 0x7FFFFFFF; // the closest we can get to +1
    	asm volatile("": : :"memory");
    	Res = CORDIC->RDATA; // inserts bus wait cycles as needed