Skip to main content
Graduate II
June 2, 2023
Solved

CORDIC SINE gives wrong result when following a CORDIC PHASE calculation

  • June 2, 2023
  • 2 replies
  • 3533 views

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);
 

    This topic has been closed for replies.
    Best answer by PLE N.1
    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

    2 replies

    Super User
    June 3, 2023

    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.

    BPaikAuthor
    Graduate II
    August 27, 2023

    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

     

    Graduate II
    August 27, 2023
    PLE N.1Answer
    ST Employee
    September 6, 2023
    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
    BPaikAuthor
    Graduate II
    September 12, 2023

    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.