cancel
Showing results for 
Search instead for 
Did you mean: 

CORDIC SINE gives wrong result when following a CORDIC PHASE calculation

BPaik
Senior

I am using the CORDIC engine on an STM32G474 to perform an atan2, sin, and cos operations sequentially. Running the code below and testing different inputs yields expected results for atan2, but does not yield expected results for sin and cos. However, the sin/cos operation does yield expected results when commenting out the first CORDIC operation. Essentially, it appears that reconfiguring the CORDIC engine and running a different operation in quick succession yields incorrect results for the second operation. I didn't notice any examples in AN5325 that discussed reconfiguring the CORDIC engine, so I'm not sure how to deal with this issue.

 LL_CORDIC_Config(hcordic.Instance,
		 	 	  LL_CORDIC_FUNCTION_PHASE,
		 	 	  LL_CORDIC_PRECISION_6CYCLES,
		 	 	  LL_CORDIC_SCALE_0,
		 	 	  LL_CORDIC_NBWRITE_2,
		 	 	  LL_CORDIC_NBREAD_1,
                                  LL_CORDIC_INSIZE_32BITS,
                                  LL_CORDIC_OUTSIZE_32BITS);
 LL_CORDIC_WriteData(hcordic.Instance, cordic_input_x);
 LL_CORDIC_WriteData(hcordic.Instance, cordic_input_y);
 cordic_angle_result = (int32_t)LL_CORDIC_ReadData(hcordic.Instance);
 
 LL_CORDIC_Config(hcordic.Instance,
		        LL_CORDIC_FUNCTION_SINE,
		        LL_CORDIC_PRECISION_6CYCLES,
		        LL_CORDIC_SCALE_0,
		        LL_CORDIC_NBWRITE_1,
		        LL_CORDIC_NBREAD_2,
		        LL_CORDIC_INSIZE_32BITS,
		        LL_CORDIC_OUTSIZE_32BITS);
 
 LL_CORDIC_WriteData(hcordic.Instance, cordic_angle_input);
 cordic_sin = (int32_t)LL_CORDIC_ReadData(hcordic.Instance);
 cordic_cos = (int32_t)LL_CORDIC_ReadData(hcordic.Instance);
 

1 ACCEPTED SOLUTION

Accepted Solutions
PLE N.1
ST Employee
Hi BPaik,
 
I reproduced your issue and analyzed it on G4.
Then the issue is similar if using also the Modulus function instead of Phase.
 
As related in the Reference Manual, the Sine & Cosine functions need 2 arguments (Angle & Modulus).
In your usecase, you configure the Sine function with LL_CORDIC_NBWRITE_1 to pass only the angle value. Then the value of the second argument is that of the Phase function.
 
There are 2 workarounds for your LL usecase:
    - Either, update your Sine configuration to pass the modulus argument
        LL_CORDIC_Config(hcordic.Instance,
                 LL_CORDIC_FUNCTION_SINE,
                 LL_CORDIC_PRECISION_6CYCLES,
                 LL_CORDIC_SCALE_0,
                 LL_CORDIC_NBWRITE_2,
                 LL_CORDIC_NBREAD_2,
                 LL_CORDIC_INSIZE_32BITS,
                 LL_CORDIC_OUTSIZE_32BITS);
 
        LL_CORDIC_WriteData(hcordic.Instance, cordic_angle_input);
        LL_CORDIC_WriteData(hcordic.Instance, 0x7FFFFFFF); /* Set the modulus argument to 1.0f in q31 format */
 
        cordic_sin = (int32_t)LL_CORDIC_ReadData(hcordic.Instance);
        cordic_cos = (int32_t)LL_CORDIC_ReadData(hcordic.Instance);
 
- Or, Deinit the IP after using Phase or Modulus function to reset it
       /* Phase Function code */
       ...
 
        /* Reset the IP to reset the second argument value to 1 */
       LL_CORDIC_DeInit(CORDIC);
 
        /* Reenable the IP */
        LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_CORDIC);
 
       /* Sine Function code */
       ...
 
 
For HAL Driver, the 2 workarounds are similar:
- Either, configure the field NbWrite of CORDIC_ConfigTypeDef with the value CORDIC_WRITE_2 and then transmit your angle and the modulus with the value 0x7FFFFFFF (q31 format)
- Or, deinitialize CORDIC after using Phase or Modulus function by calling HAL_CORDIC_DeInit following by HAL_CORDIC_Init to reenable it.
 
I hope you find these workarounds useful.
 
Best Regards

View solution in original post

5 REPLIES 5
Pavel A.
Evangelist III

While waiting for more helpful answers, please test your case using HAL functions instead of LL.

If this works, then find the difference between HAL and LL implementation.

I finally got around to implementing the HAL version of this test. I basically copied the inline functions from the ST CORDIC tutorial videos on youtube (see the link below). It looks like the HAL version suffers from the same issues as the low level implementation. The results of the sine function appear to corrupted when called immediately after the phase. The results are as expected when only one of the CORDIC functions is used.

https://www.youtube.com/watch?v=zR5oCBNpqfQ&t=335s

 

@STOne-32 

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
PLE N.1
ST Employee
Hi BPaik,
 
I reproduced your issue and analyzed it on G4.
Then the issue is similar if using also the Modulus function instead of Phase.
 
As related in the Reference Manual, the Sine & Cosine functions need 2 arguments (Angle & Modulus).
In your usecase, you configure the Sine function with LL_CORDIC_NBWRITE_1 to pass only the angle value. Then the value of the second argument is that of the Phase function.
 
There are 2 workarounds for your LL usecase:
    - Either, update your Sine configuration to pass the modulus argument
        LL_CORDIC_Config(hcordic.Instance,
                 LL_CORDIC_FUNCTION_SINE,
                 LL_CORDIC_PRECISION_6CYCLES,
                 LL_CORDIC_SCALE_0,
                 LL_CORDIC_NBWRITE_2,
                 LL_CORDIC_NBREAD_2,
                 LL_CORDIC_INSIZE_32BITS,
                 LL_CORDIC_OUTSIZE_32BITS);
 
        LL_CORDIC_WriteData(hcordic.Instance, cordic_angle_input);
        LL_CORDIC_WriteData(hcordic.Instance, 0x7FFFFFFF); /* Set the modulus argument to 1.0f in q31 format */
 
        cordic_sin = (int32_t)LL_CORDIC_ReadData(hcordic.Instance);
        cordic_cos = (int32_t)LL_CORDIC_ReadData(hcordic.Instance);
 
- Or, Deinit the IP after using Phase or Modulus function to reset it
       /* Phase Function code */
       ...
 
        /* Reset the IP to reset the second argument value to 1 */
       LL_CORDIC_DeInit(CORDIC);
 
        /* Reenable the IP */
        LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_CORDIC);
 
       /* Sine Function code */
       ...
 
 
For HAL Driver, the 2 workarounds are similar:
- Either, configure the field NbWrite of CORDIC_ConfigTypeDef with the value CORDIC_WRITE_2 and then transmit your angle and the modulus with the value 0x7FFFFFFF (q31 format)
- Or, deinitialize CORDIC after using Phase or Modulus function by calling HAL_CORDIC_DeInit following by HAL_CORDIC_Init to reenable it.
 
I hope you find these workarounds useful.
 
Best Regards

Thanks, I was able to implement the recommended workarounds successfully. I did see the reference manual refers to inputting two arguments. However, the examples in AN5325 for sine and cosine all show only the single angle input. It might prove useful for others to update it to be consistent with the reference manual.