Coordinate Rotation Digital Computer (CORDIC)

[中文]

Overview

CORDIC (Coordinate Rotation Digital Computer) is an iterative method for computing trigonometric, hyperbolic, and arctangent functions. The algorithm converts these operations into simple additions and shifts through iterative rotations and scaling, enabling efficient hardware-based computation.

CORDIC is primarily implemented in hardware with the following characteristics:

  • High computation speed

  • High precision

  • Lower resource usage

The table below compares the performance of computing the cosine of a random value using a CORDIC driver and the software IQmath library, measured in CPU cycles.

Function

IQmath

CORDIC

cos

29640

8080

Driver Introduction

Before using the CORDIC driver, you should understand its calculation methods and parameter meanings.

Calculation Methods

The CORDIC function is selected via cordic_calculate_config_t::function. Supported functions are listed in the table below. Some functions take two arguments, others one; some produce two results, others one.

The input scaling factor can be set with cordic_calculate_config_t::scale_exp (effective scaling is \(2^n\)). In the table below, \(n\) denotes this parameter.

\(arg_{1}\) and \(arg_{2}\) are the inputs, corresponding to cordic_input_buffer_desc_t::p_data_arg1 and cordic_input_buffer_desc_t::p_data_arg2. \(res_{1}\) and \(res_{2}\) are the outputs, corresponding to cordic_output_buffer_desc_t::p_data_res1 and cordic_output_buffer_desc_t::p_data_res2. The mapping is summarized in the following table.

CORDIC Supported Functions and Formulas

Function

Input

Output

Scale exponent \(n\)

Input/Output range (scale = 1)

ESP_CORDIC_FUNC_COS Cosine

\(\frac{\theta}{\pi}, \quad \theta \text{ in radians}\)

\(res_1 = \cos(\theta)\), \(res_2 = \sin(\theta)\)

0

\(arg_1, res_1, res_2 \in \left[-1, 1\right)\)

ESP_CORDIC_FUNC_SIN Sine

\(\frac{\theta}{\pi}, \quad \theta \text{ in radians}\)

\(res_1 = \sin(\theta)\), \(res_2 = \cos(\theta)\)

0

\(arg_1, res_1, res_2 \in \left[-1, 1\right)\)

ESP_CORDIC_FUNC_PHASE Phase

\(arg_1 = x \cdot 2^{-n}\), \(arg_2 = y \cdot 2^{-n}\)

\(res_1 = \arctan(y/x) \cdot 2^{-n}/\pi\), \(res_2 = \sqrt{x^2+y^2} \cdot 2^{-n}\)

[0, 15]

\(arg_{1,2} \in \left[-1, 1\right)\), \(res_1 \in \left[-1, 1\right)\), \(res_2 \in \left[0, 1\right)\)

ESP_CORDIC_FUNC_MODULUS Modulus

\(arg_1 = x \cdot 2^{-n}\), \(arg_2 = y \cdot 2^{-n}\)

\(res_1 = \sqrt{x^2+y^2} \cdot 2^{-n}\), \(res_2 = \arctan(y/x) \cdot 2^{-n}/\pi\)

[0, 15]

\(arg_{1,2} \in \left[-1, 1\right)\), \(res_1 \in \left[0, 1\right)\), \(res_2 \in \left[-1, 1\right)\)

ESP_CORDIC_FUNC_ARCTAN Arctangent

\(arg_1 = x \cdot 2^{-n}\)

\(res_1 = \arctan(x) \cdot 2^{-n}/\pi\)

[0, 15]

\(arg_1, res_1 \in \left[-1, 1\right)\)

ESP_CORDIC_FUNC_COSH Hyperbolic cosine

\(arg_1 = x \cdot 2^{-n}\)

\(res_1 = \cosh(x) \cdot 2^{-n}\), \(res_2 = \sinh(x) \cdot 2^{-n}\)

1

\(arg_1 \in \left[-0.559, 0.559\right]\), \(res_1 \in \left[0.5, 0.846\right]\), \(res_2 \in \left[-0.683, 0.683\right]\)

ESP_CORDIC_FUNC_SINH Hyperbolic sine

\(arg_1 = x \cdot 2^{-n}\)

\(res_1 = \sinh(x) \cdot 2^{-n}\), \(res_2 = \cosh(x) \cdot 2^{-n}\)

1

\(arg_1 \in \left[-0.559, 0.559\right]\), \(res_1 \in \left[-0.683, 0.683\right]\), \(res_2 \in \left[0.5, 0.846\right]\)

ESP_CORDIC_FUNC_ARCHTANH Inverse hyperbolic tangent

\(arg_1 = x \cdot 2^{-n}\)

\(res_1 = \mathrm{arctanh}(x) \cdot 2^{-n}\)

1

\(arg_1 \in \left[-0.403, 0.403\right]\), \(res_1 \in \left[-0.559, 0.559\right]\)

ESP_CORDIC_FUNC_LOGE Natural logarithm

\(arg_1 = (x-1)/(x+1) \cdot 2^{-1}\)

\(res_1 = \ln(x) \cdot 2^{-2}\)

1

\(arg_1 \in \left[-0.403, 0.403\right]\), \(res_1 \in \left[-0.559, 0.559\right]\)

ESP_CORDIC_FUNC_SQUARE_ROOT Square root

\(arg_1 = x \cdot 2^{-n}\)

\(res_1 = \sqrt{x} \cdot 2^{-n}\)

[0, 4]

\(arg_1 \in \left[0.1069, 1\right)\), \(res_1 \in \left[0.177, 1\right)\)

Data Format

Input and output data format is selected via cordic_calculate_config_t::iq_format. Supported formats:

  • ESP_CORDIC_FORMAT_Q15 Q15 format

    In Q15 format, data has one sign bit plus 15 fractional bits. Range: [-1 (0x8000), 1 - 2^-15 (0x7FFF)].

Q15 format

Q15 format

\[value = \sum_{i=0}^{14} \frac{1}{2^{(15-i)}} \times B_i\]
  • ESP_CORDIC_FORMAT_Q31 Q31 format

    In Q31 format, data has one sign bit plus 31 fractional bits. Range: [-1 (0x80000000), 1 - 2^-31 (0x7FFFFFFF)].

Q31 format

Q31 format

\[value = \sum_{i=0}^{30} \frac{1}{2^{(31-i)}} \times B_i\]

Precision

The number of iterations (precision) is set via cordic_calculate_config_t::iteration_count. Supported values are given below.

Phase, Modulus, Arctan functions

Function

Iterations

Cycles

Max residual (q1.31)

Max residual (q1.15)

Phase, Modulus, Arctan

4

1

\(2^{-4}\)

\(2^{-4}\)

8

2

\(2^{-8}\)

\(2^{-8}\)

12

3

\(2^{-12}\)

\(2^{-12}\)

16

4

\(2^{-16}\)

\(2^{-15}\)

20

5

\(2^{-20}\)

\(2^{-15}\)

24

6

\(2^{-24}\)

\(2^{-15}\)

Sin, Cos, Sinh, Cosh, Arctanh, Ln functions

Function

Iterations

Cycles

Max residual (q1.31)

Max residual (q1.15)

Sin, Cos, Sinh, Cosh, Arctanh, Ln

4

1

\(2^{-3}\)

\(2^{-3}\)

8

2

\(2^{-7}\)

\(2^{-7}\)

12

3

\(2^{-11}\)

\(2^{-11}\)

16

4

\(2^{-14}\)

\(2^{-14}\)

20

5

\(2^{-18}\)

\(2^{-15}\)

24

6

\(2^{-22}\)

\(2^{-15}\)

Sqrt function

Function

Iterations

Cycles

Max residual (q1.31)

Max residual (q1.15)

Sqrt

4

1

\(2^{-7}\)

\(2^{-7}\)

8

2

\(2^{-14}\)

\(2^{-14}\)

12

3

\(2^{-22}\)

\(2^{-15}\)

Note

More iterations give higher precision but longer computation time. Once precision reaches the limit of the data format, further increasing iterations does not improve results and only increases latency.

Quick Start

This section shows how to create a CORDIC engine and run calculations. Typical usage flow:

Create CORDIC Engine

Create a CORDIC engine as follows:

cordic_engine_handle_t engine = NULL;
cordic_engine_config_t config = {
    .clock_source = CORDIC_CLK_SRC_DEFAULT,  // Select clock source
};
ESP_ERROR_CHECK(cordic_new_engine(&config, &engine));

Run CORDIC Calculation

Use the engine to perform a calculation:

cordic_calculate_config_t calc_config = {
    .function = ESP_CORDIC_FUNC_COS,           // Select function
    .iq_format = ESP_CORDIC_FORMAT_Q15,        // Input/output data format
    .iteration_count = 4,                     // Iteration count (precision)
    .scale_exp = 0,                            // Input scale exponent n (effective scale 2^n)
};

size_t buffer_depth = 60;

uint32_t data_x[buffer_depth] = {};  // Input 1, length 60
uint32_t data_y[buffer_depth] = {};  // Input 2, length 60

uint32_t res1[buffer_depth] = {};  // Output 1, length 60
uint32_t res2[buffer_depth] = {};  // Output 2, length 60

// Configure input
cordic_input_buffer_desc_t input_buffer = {
    .p_data_arg1 = data_x,   // Input 1
    .p_data_arg2 = data_y,   // Input 2
};

// Configure output
cordic_output_buffer_desc_t output_buffer = {
    .p_data_res1 = res1,   // Output 1
    .p_data_res2 = res2,   // Output 2
};

// Run calculation
ESP_ERROR_CHECK(cordic_calculate_polling(engine, &calc_config, &input_buffer, &output_buffer, buffer_depth));

Format Conversion

The driver provides conversion between fixed-point and floating-point via cordic_convert_fixed_to_float() and cordic_convert_float_to_fixed().

// Fixed-point to float
// res1[0], res2[0] are CORDIC fixed-point outputs
float res1_float = cordic_convert_fixed_to_float(res1[0], ESP_CORDIC_FORMAT_Q15);
float res2_float = cordic_convert_fixed_to_float(res2[0], ESP_CORDIC_FORMAT_Q15);

// Float to fixed-point
uint32_t res1_fixed = cordic_convert_float_to_fixed(res1_float, ESP_CORDIC_FORMAT_Q15);
uint32_t res2_fixed = cordic_convert_float_to_fixed(res2_float, ESP_CORDIC_FORMAT_Q15);

Resource Cleanup

When the CORDIC engine is no longer needed, call cordic_delete_engine() to release the underlying hardware.

ESP_ERROR_CHECK(cordic_delete_engine(engine));

Advanced

Thread Safety

The following CORDIC APIs are thread-safe and can be called from different RTOS tasks without extra locking:

Factory functions:

Note

cordic_calculate_polling() is not thread-safe. Do not call it from multiple tasks without mutex protection.

Cache Safety

cordic_calculate_polling() can be used safely in an ISR. For correct behavior when cache is disabled (e.g., in cache-safe ISRs), enable the Kconfig option CONFIG_CORDIC_ONESHOT_CTRL_FUNC_IN_IRAM to place the control functions in IRAM.

Kconfig Options

The following Kconfig option configures the CORDIC driver:

API Reference

CORDIC Driver API

Header File

  • components/esp_driver_cordic/include/driver/cordic.h

  • This header file can be included with:

    #include "driver/cordic.h"
    
  • This header file is a part of the API provided by the esp_driver_cordic component. To declare that your component depends on esp_driver_cordic, add the following to your CMakeLists.txt:

    REQUIRES esp_driver_cordic
    

    or

    PRIV_REQUIRES esp_driver_cordic
    

Functions

esp_err_t cordic_new_engine(const cordic_engine_config_t *cordic_cfg, cordic_engine_handle_t *ret_engine)

Create a new CORDIC engine instance.

This function creates and initializes a CORDIC engine with the specified configuration. The engine handle returned can be used for subsequent CORDIC calculations.

Parameters:
  • cordic_cfg -- [in] Pointer to CORDIC engine configuration structure. Must not be NULL.

  • ret_engine -- [out] Pointer to store the created CORDIC engine handle. Must not be NULL.

Returns:

  • ESP_OK: CORDIC engine created successfully.

  • ESP_ERR_INVALID_ARG: Invalid argument (NULL pointer or invalid scale exponent).

  • ESP_ERR_NO_MEM: Failed to allocate memory for the engine.

esp_err_t cordic_calculate_polling(cordic_engine_handle_t engine, const cordic_calculate_config_t *calc_cfg, cordic_input_buffer_desc_t *input_buffer_desc, cordic_output_buffer_desc_t *output_buffer_desc, size_t buffer_depth)

Start one-shot CORDIC calculation.

This function performs CORDIC calculations on a batch of data points. It processes each data point sequentially: sets arguments, starts calculation, waits for completion, and retrieves results.

Note

The function can be safely used in ISR, but for the ISR run in cache-safe, please enable CORDIC_ONESHOT_CTRL_FUNC_IN_IRAM to place the control functions into IRAM.

Note

This function is not guaranteed to be thread-safe.

Parameters:
  • engine -- [in] CORDIC engine handle created by cordic_new_engine(). Must not be NULL.

  • calc_cfg -- [in] Pointer to CORDIC calculation configuration structure. Must not be NULL.

  • input_buffer_desc -- [in] Pointer to input buffer descriptor containing input data. Must not be NULL.

  • output_buffer_desc -- [out] Pointer to output buffer descriptor for storing results. Must not be NULL.

  • buffer_depth -- [in] Number of data points to process.

Returns:

  • ESP_OK: All calculations completed successfully.

  • ESP_ERR_INVALID_ARG: Invalid argument (NULL pointer, zero buffer_depth, or invalid timeout).

  • ESP_ERR_TIMEOUT: Calculation timeout.

esp_err_t cordic_delete_engine(cordic_engine_handle_t engine)

Delete a CORDIC engine instance.

This function deletes a CORDIC engine and frees all associated resources including the mutex. After calling this function, the engine handle becomes invalid and should not be used.

Parameters:

engine -- [in] CORDIC engine handle to delete. Must not be NULL.

Returns:

  • ESP_OK: Engine deleted successfully.

  • ESP_ERR_INVALID_ARG: Invalid argument (NULL pointer).

float cordic_convert_fixed_to_float(uint32_t fixed_value, cordic_iq_format_t iq_format)

Convert CORDIC hex value to float.

This function converts a hexadecimal value from CORDIC hardware output to a floating-point number. The conversion depends on the IQ format specified by the iq_format parameter.

Parameters:
  • fixed_value -- [in] Hexadecimal value from CORDIC hardware output.

  • iq_format -- [in] IQ data format.

Returns:

Converted floating-point value. Returns 0.0f if iq_format is invalid.

uint32_t cordic_convert_float_to_fixed(float float_value, cordic_iq_format_t iq_format)

Convert float to CORDIC hex value.

This function converts a floating-point number to a hexadecimal value suitable for CORDIC hardware input. The conversion depends on the IQ format specified by the iq_format parameter.

Parameters:
  • float_value -- [in] Floating-point value to convert. Should be in the range [-1.0, 1.0].

  • iq_format -- [in] IQ data format.

Returns:

Converted hexadecimal value. Returns 0 if iq_format is invalid.

Structures

struct cordic_engine_config_t

CORDIC engine configuration structure.

Public Members

cordic_clock_source_t clock_source

CORDIC clock source

struct cordic_calculate_config_t

CORDIC calculation configuration structure.

Public Members

cordic_func_t function

CORDIC calculation function type (e.g., cosine, sine, arctan)

cordic_iq_format_t iq_format

IQ data format

uint16_t iteration_count

Internal CORDIC iteration count

uint16_t scale_exp

Input scaling exponent n, effective scaling is 2^n (range depends on function type)

CORDIC HAL API

Header File

  • components/esp_hal_cordic/include/hal/cordic_types.h

  • This header file can be included with:

    #include "hal/cordic_types.h"
    
  • This header file is a part of the API provided by the esp_hal_cordic component. To declare that your component depends on esp_hal_cordic, add the following to your CMakeLists.txt:

    REQUIRES esp_hal_cordic
    

    or

    PRIV_REQUIRES esp_hal_cordic
    

Structures

struct cordic_input_buffer_desc_t

Input buffer descriptor for CORDIC operations.

Public Members

uint32_t *p_data_arg1

Pointer to input data argument 1 buffer

uint32_t *p_data_arg2

Pointer to input data argument 2 buffer (can be NULL for single argument functions)

struct cordic_output_buffer_desc_t

Output buffer descriptor for CORDIC operations.

Public Members

uint32_t *p_data_res1

Pointer to output result 1 buffer

uint32_t *p_data_res2

Pointer to output result 2 buffer (can be NULL for single result)

Type Definitions

typedef soc_periph_cordic_clk_src_t cordic_clock_source_t

CORDIC group clock source.

Enumerations

enum cordic_func_t

CORDIC calculation function type.

Values:

enumerator ESP_CORDIC_FUNC_COS

Cosine function (can have both cos, sin results)

enumerator ESP_CORDIC_FUNC_SIN

Sine function (can have both sin, cos results)

enumerator ESP_CORDIC_FUNC_PHASE

Phase function (requires two arguments) (can have both phase, modulus results)

enumerator ESP_CORDIC_FUNC_MODULUS

Modulus function (requires two arguments) (can have both phase, modulus results)

enumerator ESP_CORDIC_FUNC_ARCTAN

Arctangent function.

enumerator ESP_CORDIC_FUNC_COSH

Hyperbolic cosine function (can have both cosh, sinh results)

enumerator ESP_CORDIC_FUNC_SINH

Hyperbolic sine function (can have both sinh, cosh results)

enumerator ESP_CORDIC_FUNC_ARCHTANH

Hyperbolic arctangent function.

enumerator ESP_CORDIC_FUNC_LOGE

Natural logarithm function.

enumerator ESP_CORDIC_FUNC_SQUARE_ROOT

Square root function.

enumerator ESP_CORDIC_FUNC_MAX

Maximum function type (for boundary checking)

enum cordic_iq_format_t

CORDIC data format size.

Values:

enumerator ESP_CORDIC_FORMAT_Q15

Q15 format: 16-bit fixed-point (range: -1.0 to 1.0)

enumerator ESP_CORDIC_FORMAT_Q31

Q31 format: 32-bit fixed-point (range: -1.0 to 1.0)

enumerator ESP_CORDIC_IQ_SIZE_MAX

Maximum size type (for boundary checking)

CORDIC Types

Header File

  • components/esp_driver_cordic/include/driver/cordic_types.h

  • This header file can be included with:

    #include "driver/cordic_types.h"
    
  • This header file is a part of the API provided by the esp_driver_cordic component. To declare that your component depends on esp_driver_cordic, add the following to your CMakeLists.txt:

    REQUIRES esp_driver_cordic
    

    or

    PRIV_REQUIRES esp_driver_cordic
    

Type Definitions

typedef struct cordic_engine_t *cordic_engine_handle_t

CORDIC engine handle type.


Was this page helpful?