5.3 CORDIC 使用说明
本章说明 N32H49x 标准外设库中 CORDIC 驱动的文件组成与 11 个公开函数,以及 3 个示例。CORDIC 是芯片内置的坐标旋转数字计算加速器,可用硬件完成三角函数、双曲函数、幅值与反正切等运算;数据位宽、缩放因子与输出限幅的取值请配合用户手册的“坐标旋转数字计算机(CORDIC)”章节阅读。
5.3.1 相关文件
| 相对路径 | 作用 |
|---|---|
firmware/n32h49x_std_periph_driver/inc/n32h49x_cordic.h |
定义运算功能、数据位宽、缩放与限幅等配置项及寄存器掩码,声明 11 个公开函数 |
firmware/n32h49x_std_periph_driver/src/n32h49x_cordic.c |
实现上述 11 个函数:初始化与结构体默认值、中断与 DMA 请求控制、数据寄存器地址获取与读写、状态标志读取与清除 |
projects/n32h49x_EVAL/examples/CORDIC/ |
CORDIC 示例根目录,含 CORDIC_Fixed_Sin_DMA、CORDIC_Fixed_Sin_IT、CORDIC_Float_Sin_IT 3 个示例 |
projects/n32h49x_EVAL/examples/CORDIC/CORDIC_Fixed_Sin_DMA/ |
该示例的工程目录组成:MDK-ARM/、EWARM/、inc/、src/、readme.txt |
projects/n32h49x_EVAL/bsp/ |
该示例引用的公共板级文件:串口日志函数 |
5.3.2 API 参考
以下 11 个公开函数按 n32h49x_cordic.h 的声明顺序分为 4 组;每个条目给出功能摘要与 n32h49x_cordic.c 中该函数正上方的注释原文。
初始化与复位
CORDIC_DeInit、CORDIC_Init、CORDIC_StructInit
中断与 DMA 请求
CORDIC_InterruptCmd、CORDIC_DMAReadRequestCmd、CORDIC_DMAWriteRequestCmd
数据读写
CORDIC_GetRegisterAddr、CORDIC_WriteData、CORDIC_ReadData
状态与标志
CORDIC_GetFlagStatus、CORDIC_ClearStatusFlag
void CORDIC_DeInit(void)复位 CORDIC 外设。
name CORDIC_DeInit.
fun DeInitializes the CORDIC peripheral.
param none
return none
void CORDIC_Init(CORDIC_InitType* CORDIC_InitParam)以 CORDIC_InitType 类型的 CORDIC_InitParam 初始化 CORDIC 模块。
name CORDIC_Init.
fun Initialize the CORDIC module with CORDIC_InitParam of type CORDIC_InitType.
param CORDIC_InitParam :
- Pointer to the CORDIC_InitType structure which will be initialized.
return none
void CORDIC_StructInit(CORDIC_InitType* CORDIC_InitParam)初始化用于 CORDIC 初始化的 CORDIC_InitType 结构体参数,通常在配置 CORDIC_InitType 参数之前调用。
name CORDIC_StructInit.
fun Initializes the structure parameter of type CORDIC_InitType used to
initialize CORDIC. This function is usually called before initializing
a parameter of type CORDIC_InitType.
param CORDIC_InitParam :
- Pointer to the CORDIC_InitType structure which will be initialized.
return none
void CORDIC_InterruptCmd(uint32_t Interrupt, FunctionalStatus Cmd)使能或关闭指定的 CORDIC 中断。
name CORDIC_InterruptCmd.
fun Enables or disables the specified CORDIC interrupts.
param Interrupt (The input parameters must be the following values):
- CORDIC_INT
- CORDIC_INT_INOVERFLOW
param Cmd (The input parameters must be the following values):
- ENABLE
- DISABLE
return none
void CORDIC_DMAReadRequestCmd(FunctionalStatus Cmd)使能或关闭 CORDIC 的 DMA 读请求。
name CORDIC_DMAReadRequestCmd.
fun Enables or disables the CORDIC DMA read request.
param Cmd (The input parameters must be the following values):
- ENABLE
- DISABLE
return none
void CORDIC_DMAWriteRequestCmd(FunctionalStatus Cmd)使能或关闭 CORDIC 的 DMA 写请求。
name CORDIC_DMAWriteRequestCmd.
fun Enables or disables the CORDIC DMA write request.
param Cmd (The input parameters must be the following values):
- ENABLE
- DISABLE
return none
uint32_t CORDIC_GetRegisterAddr(uint32_t Direction)获取用于 DMA 传输的 CORDIC 数据寄存器地址。
name CORDIC_GetRegisterAddr.
fun Get the CORDIC data register address used for DMA transfer.
param Direction (The input parameters must be the following values):
- CORDIC_AS_DMA_SRCADDR
- CORDIC_AS_DMA_DSTADDR
return Address of data register.
void CORDIC_WriteData(uint32_t *pInData)写入用于 CORDIC 运算的 32 位输入数据。
name CORDIC_WriteData.
fun Write 32-bit input data for the CORDIC processing.
param pInData :
- Points to the address of input data
return none
void CORDIC_ReadData(uint32_t *pOutData)返回 CORDIC 运算的 32 位输出数据。
name CORDIC_ReadData.
fun Return 32-bit output data of CORDIC processing.
param pOutData :
- Points to the address where the output data is stored
return 32-bit output data of CORDIC processing.
FlagStatus CORDIC_GetFlagStatus(uint32_t Flag)检查指定的 CORDIC 标志是否置位。
name CORDIC_GetFlagStatus.
fun Checks whether the specified CORDIC flag is set or not.
param Flag (The input parameters must be the following values):
- CORDIC_FLAG_RRF
- CORDIC_FLAG_INOVF
- CORDIC_FLAG_DMAWENF
- CORDIC_FLAG_DMARENF
- CORDIC_FLAG_INTENF
return SET or RESET
void CORDIC_ClearStatusFlag(uint32_t Flag)清除 CORDIC 的挂起标志。
name CORDIC_ClearStatusFlag.
fun Clears the pending flag for the CORDIC.
param Flag (The input parameters must be the following values):
- CORDIC_FLAG_INOVF
- CORDIC_FLAG_DMAWENF
- CORDIC_FLAG_DMARENF
- CORDIC_FLAG_INTENF
return none
note The RRF flag cannot be cleared by a call to this function;
the RRF flag is cleared by hardware when reading the data
register is complete.
5.3.3 Demo 示例说明
本节说明 CORDIC 的 3 个示例:CORDIC_Fixed_Sin_DMA 用 DMA 搬运定点正弦的输入与输出,CORDIC_Fixed_Sin_IT 用中断读取定点结果,CORDIC_Float_Sin_IT 用中断读取浮点结果。
5.3.3.1 CORDIC_Fixed_Sin_DMA 定点正弦 DMA 搬运
工程目录: projects/n32h49x_EVAL/examples/CORDIC/CORDIC_Fixed_Sin_DMA/
配置 CORDIC 与 DMA1 时钟→复位 CORDIC 并配置正弦运算参数→取得 CORDIC 读写寄存器地址→配置 DMA 读写通道并开启 DMA 请求→等待结果就绪标志后比对参考正弦值
| 项目 | 源码解读 |
|---|---|
| 功能 | 以定点 Q1.31 格式计算 64 点正弦; CORDIC 配置为正弦函数、6 周期精度,并使能坐标与相位限幅; DMA 读通道把 CORDIC_RDAT 结果搬到 aCalResult,DMA 写通道把 aInData 搬到 CORDIC_WDAT;全部搬完后逐点与 aRefResult 比对。 |
| 源码组成 | src/main.c:main、RCC_Configuration、NVIC_Configuration、DMA_ReadConfiguration、DMA_WriteConfiguration、CheckResidualError;inc/n32h49x_it.h、src/n32h49x_it.c:中断向量与异常处理;readme.txt:功能、环境与使用说明;MDK-ARM/、EWARM/:Keil 与 IAR 工程。 |
| 关键配置 | 时钟:使能 CORDIC 与 DMA1 时钟,并调用 RCC_ConfigPeriphClk(RCC_PERIPH_HCLK_DIV2);CORDIC: CORDIC_FUNCTION_SINE、CORDIC_PRECISION_6CYCLES、CORDIC_CODIN_LIMIT_ENABLE、CORDIC_PHASE_LIMIT_ENABLE;DMA 读通道:DMA1_CH1,映射 DMA_REMAP_CORDIC_RD;DMA 写通道:DMA1_CH2,映射 DMA_REMAP_CORDIC_WR,两者均为 WORD 宽度、存储器地址自增、长度 64。 |
| 程序与数据路径 | main 依次调用 RCC_Configuration、NVIC_Configuration、CORDIC_DeInit;CORDIC_GetRegisterAddr 取回 CORDIC_RDAT、CORDIC_WDAT 地址,CORDIC_Init 配置正弦运算;开 DMA 读请求后用 DMA_ReadConfiguration 把结果搬到 aCalResult,开 DMA 写请求后用 DMA_WriteConfiguration 把 aInData 搬到 CORDIC;等待 CORDIC_FLAG_RRF 置位后逐点用 CheckResidualError 比对 aRefResult。 |
| 主要 API | CORDIC_DeInit、CORDIC_GetRegisterAddr、CORDIC_Init、CORDIC_DMAReadRequestCmd、CORDIC_DMAWriteRequestCmd、CORDIC_GetFlagStatus |
| 验证方法 | 编译下载运行后,串口打印 “CORDIC demo success!!!” 表示 64 点结果都在容差内; 若某点偏差超过 MAX_RESIDUAL_ERROR_18,打印 “Error[i]” 并停在 while(1)。 |
| 使用提示 | 使能 CORDIC 时必须把 HCLK 配置为 DIV2; 输入数据为 Q1.31 定点格式,数组从 0 递增到 2π; 该示例的 inc/ 目录只含中断头文件,没有独立的 main.h。 |
核心代码解读与移植
示例用两条 DMA 通道把 64 点 Q1.31 输入搬入 CORDIC、把结果搬出,最后逐点与参考正弦值比对。
数据路径: RCC_Configuration 使能 CORDIC 与 DMA1 时钟并设 HCLK 为 DIV2 → CORDIC_DeInit 复位 → CORDIC_GetRegisterAddr 取 CORDIC_RDAT、CORDIC_WDAT 地址 → CORDIC_Init 配置正弦运算 → DMA 读、写通道把 aInData 搬入 CORDIC、把结果搬入 aCalResult → 等待 CORDIC_FLAG_RRF 后逐点比对 aRefResult
1. 配置 CORDIC 与 DMA1 时钟。 RCC_Configuration 使能 CORDIC 与 DMA1 时钟,并把 HCLK 配置为 DIV2——使能 CORDIC 时这一分频是必需的。
void RCC_Configuration()
{
/* Enable DMA1 and CORDIC clock */
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_CORDIC | RCC_AHB_PERIPHEN_DMA1, ENABLE);
/* When enabling CORDIC, HCLK DIV2 must be configured */
RCC_ConfigPeriphClk(RCC_PERIPH_HCLK_DIV2);
}
移植到其它型号时只需保留 CORDIC 与所用 DMA 的时钟;RCC_PERIPH_HCLK_DIV2 不能省略。
2. 取得数据寄存器地址并配置正弦运算。 main 先用 CORDIC_GetRegisterAddr 取回读、写数据寄存器地址供 DMA 使用,再用结构体把 CORDIC 配置为正弦、6 周期精度并打开坐标与相位限幅。
/* Get CORDIC read register (CORDIC_RDAT) address */
rRegAddr = CORDIC_GetRegisterAddr(CORDIC_AS_DMA_SRCADDR);
/* Get CORDIC write register (CORDIC_WDAT) address */
wRegAddr = CORDIC_GetRegisterAddr(CORDIC_AS_DMA_DSTADDR);
CORDIC_StructInit(&CORDIC_InitStructure);
/* Select sine function */
CORDIC_InitStructure.Function = CORDIC_FUNCTION_SINE;
/* Set max precision for Q1.31 sine */
CORDIC_InitStructure.Precision = CORDIC_PRECISION_6CYCLES;
/* Enable Coordinate Limit */
CORDIC_InitStructure.CodinLimit = CORDIC_CODIN_LIMIT_ENABLE;
/* Enable Phase Limit */
CORDIC_InitStructure.PhaseLimit = CORDIC_PHASE_LIMIT_ENABLE;
/* Configure CORDIC */
CORDIC_Init(&CORDIC_InitStructure);
换用其它运算功能或精度时改 Function 与 Precision 即可,读写寄存器地址由 Direction 参数区分。
3. 配置 DMA 读写通道并开启 DMA 请求。 DMA_ReadConfiguration 把外设地址设为 CORDIC_RDAT、存储器地址设为 aCalResult,并把该通道映射到 CORDIC 读请求;写侧由 DMA_WriteConfiguration 把 aInData 搬入 CORDIC_WDAT。
/* Reset DMA1 channel 1 */
DMA_DeInit(DMA1_CH1);
/* Initialize the DMA parameter structure */
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.PeriphAddr = SrcAddr;
DMA_InitStructure.MemAddr = (uint32_t)DstAddr;
DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC;
DMA_InitStructure.BufSize = DataLen;
DMA_InitStructure.MemoryInc = DMA_MEM_INC_ENABLE;
DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_WIDTH_WORD;
DMA_InitStructure.MemDataSize = DMA_MEM_DATA_WIDTH_WORD;
/* Initialize DMA1 channel 1 */
DMA_Init(DMA1_CH1, &DMA_InitStructure);
/* CORDIC read channel mapping */
DMA_RequestRemap(DMA_REMAP_CORDIC_RD, DMA1_CH1, ENABLE);
/* Enable DMA1 channel 1 transfer completion interrupt */
DMA_ConfigInt(DMA1_CH1, DMA_INT_TXC, ENABLE);
/* Enable DMA1 channel 1 */
DMA_EnableChannel(DMA1_CH1, ENABLE);
/* Configure DMA read channel */
DMA_ReadConfiguration(rRegAddr, aCalResult, ARRAY_SIZE);
/* Enable CORDIC DMA read request */
CORDIC_DMAReadRequestCmd(ENABLE);
/* Configure DMA write channel */
DMA_WriteConfiguration(aInData, wRegAddr, ARRAY_SIZE);
/* Enable CORDIC DMA write request */
CORDIC_DMAWriteRequestCmd(ENABLE);
移植时两条通道的请求映射要与实际搬运方向一致;DMA 模式下不要再由 CPU 直接读写 CORDIC 数据寄存器。
4. 等待结果并比对参考值。 计算启动后 main 轮询 CORDIC_FLAG_RRF,就绪后逐点用 CheckResidualError 与参考正弦比较。
while (CORDIC_GetFlagStatus(CORDIC_FLAG_RRF) == RESET)
{
/* Do nothing */
}
/* Compare CORDIC results to the reference values */
for (i = 0; i < ARRAY_SIZE; i++)
{
/* Check the data results sequentially */
if (CheckResidualError(aCalResult[i], aRefResult[i], MAX_RESIDUAL_ERROR_18) == 0U)
{
log_info("Error[%d]\n", i);
while (1);
}
}
容差常量随精度选择调整:6 周期精度下正弦的残留误差约 2^-18。
对应源码: src/main.c
5.3.3.2 CORDIC_Fixed_Sin_IT 定点正弦中断读取
工程目录: projects/n32h49x_EVAL/examples/CORDIC/CORDIC_Fixed_Sin_IT/
配置 CORDIC 时钟→复位并配置正弦运算参数→使能 CORDIC 中断→逐点写入 Q1.31 输入数据→中断读回结果后比对参考正弦值
| 项目 | 源码解读 |
|---|---|
| 功能 | 以定点 Q1.31 格式计算 64 点正弦; 输入由主循环逐点写入 CORDIC_WDAT,每次结果就绪触发 Cordic_IRQn 中断;Cordic_IRQ_IRQHandler 在中断里读回结果存入 aCalResult,主循环再逐点与 aRefResult 比对。 |
| 源码组成 | src/main.c:main、RCC_Configuration、NVIC_Configuration、CheckResidualError、Cordic_IRQ_IRQHandler;inc/n32h49x_it.h、src/n32h49x_it.c:中断向量与异常处理;readme.txt:功能、环境与使用说明;MDK-ARM/、EWARM/:Keil 与 IAR 工程。 |
| 关键配置 | 时钟:使能 CORDIC 时钟并调用 RCC_ConfigPeriphClk(RCC_PERIPH_HCLK_DIV2);CORDIC: CORDIC_FUNCTION_SINE、CORDIC_PRECISION_6CYCLES、CORDIC_CODIN_LIMIT_ENABLE、CORDIC_PHASE_LIMIT_ENABLE,并调用 CORDIC_InterruptCmd(CORDIC_INT, ENABLE);NVIC:优先级组 0,使能 Cordic_IRQn。 |
| 程序与数据路径 | main 依次调用 RCC_Configuration、NVIC_Configuration、CORDIC_DeInit、CORDIC_Init;开中断后用 for 循环逐点调用 CORDIC_WriteData 写入 aInData;每次运算完成, Cordic_IRQ_IRQHandler 检查 CORDIC_FLAG_RRF 并用 CORDIC_ReadData 读回 aCalResult;主循环用 CheckResidualError 逐点比对 aRefResult。 |
| 主要 API | CORDIC_DeInit、CORDIC_Init、CORDIC_InterruptCmd、CORDIC_WriteData、CORDIC_ReadData、CORDIC_GetFlagStatus |
| 验证方法 | 编译下载运行后,串口打印 “CORDIC demo success!!!” 表示 64 点结果都在容差内; 若某点偏差超过 MAX_RESIDUAL_ERROR_18,打印 “Error[i]” 并停在 while(1)。 |
| 使用提示 | 使能 CORDIC 时必须把 HCLK 配置为 DIV2; 读取结果寄存器会插入总线等待直到计算完成,中断里直接调用 CORDIC_ReadData 即可;读取数据寄存器后 CORDIC_FLAG_RRF 由硬件清除。 |
核心代码解读与移植
示例把 64 点 Q1.31 输入逐点写入 CORDIC,每次结果就绪由 Cordic_IRQn 中断读回,最后逐点与参考正弦值比对。
数据路径: RCC_Configuration 使能 CORDIC 时钟并设 HCLK 为 DIV2 → CORDIC_DeInit 复位 → CORDIC_Init 配置正弦运算 → CORDIC_InterruptCmd 开中断 → 主循环 CORDIC_WriteData 写入 aInData → Cordic_IRQ_IRQHandler 读 CORDIC_RDAT 到 aCalResult → 主循环比对 aRefResult
1. 配置 CORDIC 时钟。 RCC_Configuration 使能 CORDIC 时钟并把 HCLK 配置为 DIV2。
void RCC_Configuration()
{
/* Enable CORDIC clock */
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_CORDIC, ENABLE);
/* When enabling CORDIC, HCLK DIV2 must be configured */
RCC_ConfigPeriphClk(RCC_PERIPH_HCLK_DIV2);
}
使能 CORDIC 时 RCC_PERIPH_HCLK_DIV2 是必需的,移植时不能省略。
2. 配置正弦运算并使能中断。 main 把 CORDIC 配置为正弦、6 周期精度、坐标与相位限幅,并打开 CORDIC 中断。
CORDIC_StructInit(&CORDIC_InitStructure);
/* Select sine function */
CORDIC_InitStructure.Function = CORDIC_FUNCTION_SINE;
/* Set max precision for Q1.31 sine */
CORDIC_InitStructure.Precision = CORDIC_PRECISION_6CYCLES;
/* Enable Coordinate Limit */
CORDIC_InitStructure.CodinLimit = CORDIC_CODIN_LIMIT_ENABLE;
/* Enable Phase Limit */
CORDIC_InitStructure.PhaseLimit = CORDIC_PHASE_LIMIT_ENABLE;
/* Configure CORDIC */
CORDIC_Init(&CORDIC_InitStructure);
/* Enable CORDIC interrupt */
CORDIC_InterruptCmd(CORDIC_INT, ENABLE);
中断方式适合边算边取结果,CPU 不必轮询完成标志。
3. 逐点写入输入数据。 开中断后 main 用循环把 aInData 的每个点写入数据寄存器,硬件随即开始计算。
for (wArrayIndex = 0; wArrayIndex < ARRAY_SIZE; wArrayIndex++)
{
/* Write data to be calculated */
CORDIC_WriteData((uint32_t *)&aInData[wArrayIndex]);
}
输入按 Q1.31 定点沿 0 到 2π 均匀排列,写入顺序即结果读出的顺序。
4. 在中断中读回结果。 Cordic_IRQ_IRQHandler 检查 CORDIC_FLAG_RRF,就绪时读取数据寄存器并把结果存入 aCalResult,读操作同时由硬件清除该标志。
void Cordic_IRQ_IRQHandler(void)
{
if (CORDIC_GetFlagStatus(CORDIC_FLAG_RRF) != RESET)
{
/* Read calculation results */
/* The RRF flag will be cleared after reading the data register */
CORDIC_ReadData((uint32_t *)&aCalResult[rArrayIndex++]);
}
}
移植到多通道或 DMA 混用时,注意不要在 DMA 读通道使能后再由 CPU 读 CORDIC_RDAT。
对应源码: src/main.c
5.3.3.3 CORDIC_Float_Sin_IT 浮点正弦中断读取
工程目录: projects/n32h49x_EVAL/examples/CORDIC/CORDIC_Float_Sin_IT/
配置 CORDIC 时钟→复位并配置浮点正弦运算参数→使能 CORDIC 中断→生成随机输入并逐点写入→中断读回浮点结果后比对参考值
| 项目 | 源码解读 |
|---|---|
| 功能 | 以浮点格式计算 64 点正弦;rand 生成 -1.0~1.0 的输入,sinf 计算软件参考值;CORDIC 配置为浮点输入输出,结果经中断读回后与参考值比对。 |
| 源码组成 | src/main.c:main、RCC_Configuration、NVIC_Configuration、CheckResidualError、Cordic_IRQ_IRQHandler;inc/n32h49x_it.h、src/n32h49x_it.c:中断向量与异常处理;readme.txt:功能、环境与使用说明;MDK-ARM/、EWARM/:Keil 与 IAR 工程。 |
| 关键配置 | 时钟:使能 CORDIC 时钟并调用 RCC_ConfigPeriphClk(RCC_PERIPH_HCLK_DIV2);CORDIC: CORDIC_FUNCTION_SINE、CORDIC_PRECISION_6CYCLES、CORDIC_INPUT_FLOAT、CORDIC_OUTPUT_FLOAT,并打开坐标与相位限幅;NVIC:优先级组 0,使能 Cordic_IRQn。 |
| 程序与数据路径 | main 依次初始化时钟、NVIC 与 CORDIC;for 循环用 rand 生成 aInData 并用 sinf 算出 aRefResult;再用 CORDIC_WriteData 逐点写入,Cordic_IRQ_IRQHandler 读回 aCalResult;主循环用 CheckResidualError 比对。 |
| 主要 API | CORDIC_DeInit、CORDIC_Init、CORDIC_InterruptCmd、CORDIC_WriteData、CORDIC_ReadData、CORDIC_GetFlagStatus |
| 验证方法 | 串口打印 “CORDIC demo success!!!” 表示浮点结果都在容差内; 某点偏差超过 MAX_RESIDUAL_ERROR_18 时打印 “Error[i]” 并停在 while(1)。 |
| 使用提示 | 浮点输入范围需落在 -1.0~1.0;sinf 的参考值按输入乘以 π 的正弦计算,量纲与 CORDIC 一致;使能 CORDIC 时同样必须把 HCLK 配置为 DIV2。 |
核心代码解读与移植
示例用随机浮点输入驱动 CORDIC 计算正弦,结果经中断读回,并与 sinf 算出的参考值比对。
数据路径: RCC_Configuration 使能 CORDIC 时钟并设 HCLK 为 DIV2 → CORDIC_DeInit 复位 → CORDIC_Init 配置浮点正弦 → CORDIC_InterruptCmd 开中断 → 循环生成 aInData 与 aRefResult 并 CORDIC_WriteData 写入 → Cordic_IRQ_IRQHandler 读 CORDIC_RDAT 到 aCalResult → 主循环比对
1. 配置 CORDIC 时钟。 与定点示例相同,RCC_Configuration 使能 CORDIC 时钟并把 HCLK 配置为 DIV2。
void RCC_Configuration(void)
{
/* Enable CORDIC clock */
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_CORDIC, ENABLE);
/* When enabling CORDIC, HCLK DIV2 must be configured */
RCC_ConfigPeriphClk(RCC_PERIPH_HCLK_DIV2);
}
分频设置与定点示例一致,移植时照搬即可。
2. 配置浮点正弦运算并使能中断。 结构与定点示例相同,额外选择浮点输入与浮点输出。
CORDIC_StructInit(&CORDIC_InitStructure);
/* Select sine function */
CORDIC_InitStructure.Function = CORDIC_FUNCTION_SINE;
/* Set max precision for Q1.31 sine */
CORDIC_InitStructure.Precision = CORDIC_PRECISION_6CYCLES;
/* Select floating-point input */
CORDIC_InitStructure.InSelect = CORDIC_INPUT_FLOAT;
/* Select floating-point output */
CORDIC_InitStructure.OutSelect = CORDIC_OUTPUT_FLOAT;
/* Enable Coordinate Limit */
CORDIC_InitStructure.CodinLimit = CORDIC_CODIN_LIMIT_ENABLE;
/* Enable Phase Limit */
CORDIC_InitStructure.PhaseLimit = CORDIC_PHASE_LIMIT_ENABLE;
/* Configure CORDIC */
CORDIC_Init(&CORDIC_InitStructure);
/* Enable CORDIC interrupt */
CORDIC_InterruptCmd(CORDIC_INT, ENABLE);
浮点模式下输入输出都按单精度浮点解析,不再做 Q1.31 定点换算。
3. 生成随机输入与参考值。 主循环用 rand 生成 -1.0~1.0 的输入,再用 sinf 算出软件参考值。
for (i = 0; i < ARRAY_SIZE; i++)
{
/* Random generation of input data */
aInData[i] = -1.0f + ((float)(rand() % 1999)) * 0.001f;
/* Software calculation results */
aRefResult[i] = sinf(aInData[i] * PI);
}
生成范围与硬件相位输入范围一致,超出范围的点会被限幅而不参与正确性判定。
4. 写入输入并在中断中读回结果。 与定点示例相同,写侧逐点调用 CORDIC_WriteData,读侧在 Cordic_IRQ_IRQHandler 中读取数据寄存器。
void Cordic_IRQ_IRQHandler(void)
{
if (CORDIC_GetFlagStatus(CORDIC_FLAG_RRF) != RESET)
{
/* Read calculation results */
/* The RRF flag will be cleared after reading the data register */
CORDIC_ReadData((uint32_t *)&aCalResult[rArrayIndex++]);
}
}
浮点结果读回后直接与 aRefResult 比较,容差同样由 MAX_RESIDUAL_ERROR_18 控制。
对应源码: src/main.c
5.3.4 注意与排障
| 场景 | 检查与建议 | 来源 |
|---|---|---|
| 结果读取与等待 | 计算一旦启动,读取结果寄存器都会插入总线等待直到计算完成,程序不必轮询完成标志。 | 用户手册 |
| 输出限幅 | CODINLIMIT 把坐标输出限幅到 ±1,PHASELIMIT 把相位输出限幅到 ±π;限幅会改变超出范围的结果。 |
用户手册 |
| 角度取值 | 相位输入 θ 的有效范围为 [-1, 1),即实际角度除以 π 后的值。 | 用户手册 |
| 输入范围与缩放 | 当 x、y 的绝对值超出允许范围时,必须按同一因子同时缩放 x 与 y 后再输入。 | 用户手册 |
| 16 位结果打包 | INSIZE = 1 时 NUMWRITE 必须为 0;OUTSIZE = 1 时 NUMREAD 必须为 0,只读一次结果寄存器即可。 |
用户手册 |
| DMA 与 CPU 访问互斥 | 使能 DMA 读通道后不要再由 CPU 访问 CORDIC_RDAT;使能 DMA 写通道后不要再由 CPU 访问 CORDIC_WDAT。 |
用户手册 |
| 缩放因子与 DMA | DMA 传输过程中不能修改 SCALE 缩放因子。 |
用户手册 |
| 只用 DMA 重复运算 | CORDIC 没有针对编程 CTRLSTS 的 DMA 请求,DMA 模式只适合重复执行同一功能与同一配置的运算。 |
用户手册 |
| 写配置寄存器 | 写入 CTRLSTS 会丢弃已存储但尚未计算的数据。 |
用户手册 |
| 缩放精度 | 缩放因子会引入截断误差,缩放位数越大精度损失越明显。 | 用户手册 |