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.
Function |
Input |
Output |
Scale exponent \(n\) |
Input/Output range (scale = 1) |
|---|---|---|---|---|
|
\(\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)\) |
|
\(\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)\) |
|
\(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)\) |
|
\(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)\) |
|
\(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)\) |
|
\(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]\) |
|
\(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]\) |
|
\(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]\) |
|
\(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]\) |
|
\(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_Q15Q15 formatIn Q15 format, data has one sign bit plus 15 fractional bits. Range: [-1 (0x8000), 1 - 2^-15 (0x7FFF)].
Q15 format
ESP_CORDIC_FORMAT_Q31Q31 formatIn Q31 format, data has one sign bit plus 31 fractional bits. Range: [-1 (0x80000000), 1 - 2^-31 (0x7FFFFFFF)].
Q31 format
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:
CONFIG_CORDIC_ONESHOT_CTRL_FUNC_IN_IRAM - Place calculation control functions in IRAM.
API Reference
CORDIC Driver API
Header File
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_cordiccomponent. To declare that your component depends onesp_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_IRAMto 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
-
cordic_clock_source_t 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_func_t function
CORDIC HAL API
Header File
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_cordiccomponent. To declare that your component depends onesp_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.
-
struct cordic_output_buffer_desc_t
Output buffer descriptor for CORDIC operations.
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)
-
enumerator ESP_CORDIC_FUNC_COS
-
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)
-
enumerator ESP_CORDIC_FORMAT_Q15
CORDIC Types
Header File
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_cordiccomponent. To declare that your component depends onesp_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.