- #include <stdio.h>
- #include <math.h>
- #include "MathLib.h"
- #include "g32r4xx.h"
- #include "tmu_benchmark.h"
- // 计时辅助宏(假设已初始化 DWT)
- #define START_TIMER() uint32_t start = DWT->CYCCNT
- #define GET_CYCLES() (DWT->CYCCNT - start)
- void Run_TMU_Benchmark(int32_t x, int32_t y) {
- uint32_t tmu_cycles[9]; // 记录1-8级的耗时
- float tmu_errors[9];
- uint32_t soft_cycles;
- float soft_res;
- // 开启 FPU 与 CDE(自定义数据路径扩展) 协处理器权限
- // Geehy 的 ATAN2 底层使用了 ARM CDE 自定义指令,必须开启 CP0-CP7 以及 CP10-CP11
- SCB->CPACR |= 0xFFFF;
- __ISB(); // 指令同步屏障,确保后续的 CDE 指令不会抛出异常
- // 1. 标准 C 库测试 (运行 1000 次取平均)
- float fx = (float)x / 2147483648.0f;
- float fy = (float)y / 2147483648.0f;
-
- START_TIMER();
- for(int i=0; i<1000; i++) {
- soft_res = atan2f(fy, fx);
- }
- soft_cycles = GET_CYCLES() / 1000;
- int soft_res_int = (int)soft_res;
- int soft_res_frac = (int)(fabsf(soft_res - soft_res_int) * 10000.0f);
- printf("--- Benchmark Result (Soft: %d cycles, Result: %d.%04d rad) ---\r\n", soft_cycles, soft_res_int, soft_res_frac);
- // 2. TMU 硬件测试 (遍历 1-8 精度等级)
- for(int level = 1; level <= 8; level++) {
- int32_t tmu_raw;
-
- START_TIMER();
- for(int i=0; i<1000; i++) {
- tmu_raw = ATAN2(x, y, level);
- }
- tmu_cycles[level] = GET_CYCLES() / 1000;
- // 计算误差
- float tmu_float = (float)tmu_raw / 2147483648.0f * 3.1415926535f;
- float error = fabsf(tmu_float - soft_res);
- // 分离整数和小数部分进行打印,避免 %f 触发 printf 内部死机
- int tmu_int = (int)tmu_float;
- int tmu_frac = (int)(fabsf(tmu_float - tmu_int) * 10000.0f);
-
- int err_int = (int)error;
- int err_frac = (int)(fabsf(error - err_int) * 100000000.0f);
- printf(" Level %d | Cycles: %d | Result: %d.%04d rad | Error: %d.%08d\r\n",
- level, tmu_cycles[level], tmu_int, tmu_frac, err_int, err_frac);
- }
- }
对应的main.c代码:
- /**
- *
- * [url=/u/file]@file[/url] main.c
- *
- * [url=/u/brief]@brief[/url] Main program body
- *
- * [url=/u/version]@version[/url] V1.0.0
- *
- * [url=/u/date]@date[/url] 2025-10-30
- *
- * @attention
- *
- * Copyright (C) 2025 Geehy Semiconductor
- *
- * You may not use this file except in compliance with the
- * GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
- *
- * The program is only for reference, which is distributed in the hope
- * that it will be useful and instructional for customers to develop
- * their software. Unless required by applicable law or agreed to in
- * writing, the program is distributed on an "AS IS" BASIS, WITHOUT
- * ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
- * See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
- * and limitations under the License.
- */
- /* Includes ***************************************************************/
- #include "main.h"
- /* Private includes *******************************************************/
- #include <stdio.h>
- #include "tmu_benchmark.h"
- #include "system_g32r4xx_dwtmeasure.h"
- /* Private macro **********************************************************/
- #define DEBUG_USART COM2_PORT
- /* === 新增:DWT 周期计数器底层操作宏 === */
- #ifndef ENABLE_DWT_CYCCNT
- // 1. 开启内核 Debug 模块 (DEMCR的 TRCENA 位)
- // 2. 将计数器清零
- // 3. 开启周期计数器 (CYCCNTENA 位)
- #define ENABLE_DWT_CYCCNT() \
- do { \
- CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; \
- DWT->CYCCNT = 0; \
- DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; \
- } while(0)
- #endif
- #ifndef RESET_DWT_CYCCNT
- #define RESET_DWT_CYCCNT() (DWT->CYCCNT = 0)
- #endif
- /* Private typedef ********************************************************/
- /* Private variables ******************************************************/
- /* ADC AWD Active Flag */
- uint8_t iAWD_Flag = 0;
- /* Private function prototypes ********************************************/
- void DDL_SysClkConfig(void);
- void ADC_Init(void);
- void ADC_Isr(void);
- /* Delay */
- void Delay(uint32_t count);
- /* External variables *****************************************************/
- /* External functions *****************************************************/
- /**
- * @brief Main program
- *
- * @param None
- *
- * @retval None
- *
- */
- int main(void)
- {
- /* USART init structure */
- DDL_USART_InitTypeDef USART_InitStruct = {0U};
- /* Configure system clock */
- DDL_SysClkConfig();
- /* Configure interrupt group 4: 4-bit preemptive priority, 0-bit subpriority */
- DDL_NVIC_ConfigPriorityGroup(DDL_NVIC_PRIORITY_GROUP_4);
- /* USART Init */
- USART_InitStruct.BaudRate = 115200U;
- USART_InitStruct.DataWidth = DDL_USART_DATAWIDTH_8B;
- USART_InitStruct.StopBits = DDL_USART_STOPBITS_1;
- USART_InitStruct.Parity = DDL_USART_PARITY_NONE ;
- USART_InitStruct.TransferDirection = DDL_USART_DIRECTION_TX_RX;
- USART_InitStruct.HardwareFlowControl = DDL_USART_HWCONTROL_NONE;
- USART_InitStruct.OverSampling = DDL_USART_OVERSAMPLING_16;
- BOARD_COMInit(COM2, &USART_InitStruct);
- /* LED1 Init */
- BOARD_LEDInit(LED1);
- printf("\r\nADC3 Analog Window Watchdog Examples.\r\n");
- /* ========================================================================= */
- /* ==================== 融合 DWT 计时与 TMU 测试逻辑 ======================= */
- /* ========================================================================= */
-
- /* 1. 必须在调用 TMU_Benchmark 前开启 DWT,否则内部计时器无效 */
- ENABLE_DWT_CYCCNT();
- RESET_DWT_CYCCNT(); // 确保从 0 开始
- /* 2. 获取开始前的 CPU 周期数 */
- uint32_t start_cycles = DWT->CYCCNT;
- /* 3. 运行你的核心测试代码 (内部也会调用 DWT->CYCCNT) */
- Run_TMU_Benchmark(1073741824, 1073741824); // 传入 Q31 格式数据
- /* 4. 获取结束时的 CPU 周期数 */
- uint32_t end_cycles = DWT->CYCCNT;
-
- /* 5. 计算并打印总耗时 */
- uint32_t total_cycles = end_cycles - start_cycles;
- printf(">> Total Benchmark Execution Time: %u CPU Cycles <<\r\n\n", total_cycles);
- /* ========================================================================= */
- Run_TMU_Benchmark(1073741824, 1073741824);
- /* ADC Init */
- ADC_Init();
-
- while (1)
- {
- }
- }
- /**
- * @brief System clock configuration
- *
- * @param None
- *
- * @retval None
- */
- void DDL_SysClkConfig(void)
- {
- /* Unlock clock control registers */
- /* Wait until the registers are unlocked */
- DDL_RCM_Unlock();
- while ((RCM->KEY & RCM_KEY_KEYST) != RCM_KEY_KEYST)
- {
- }
- /* Enable HSE and wait for ready */
- /* Enable HSE input clock */
- DDL_RCM_HSE_Enable();
- /* Wait until HSE is ready */
- while (DDL_RCM_HSE_IsReady() != 1)
- {
- /* wait for HSERDY */
- }
- /* Configure Flash wait states appropriate for 120 MHz */
- /* Set Flash wait period to accommodate higher frequency */
- DDL_FLASH_SetWaitPeriod(FLASH_DDL_WAIT_PERIOD_3);
- /* Set Flash erase time base to 120 MHz (use 119 to represent 120 MHz) */
- DDL_FLASH_SetEraseTimeBase(119);
- /* Configure PLL */
- /* Ensure PLL is disabled prior to configuration */
- DDL_RCM_PLL_Disable();
- /* Configure PLL settings: multiplier, prescaler, and clock source */
- /* PLL multiplier set to 15 (x15), prescaler no division, clock source from HSE */
- DDL_RCM_PLL_SetMultiplier(15);
- DDL_RCM_PLL_SetPrescaler(DDL_RCM_PLL_DIV1);
- DDL_RCM_PLL_SetClkSource(DDL_RCM_PLL_CLKSOURCE_HSE);
- /* Enable PLL and wait for ready */
- DDL_RCM_PLL_Enable();
- while (DDL_RCM_PLL_IsReady() != 1)
- {
- /* wait for PLL Ready */
- }
- /* Switch system clock to PLL output */
- DDL_RCM_SetSysClkSource(DDL_RCM_SYS_CLKSOURCE_PLL);
- /* Enable clock switch and wait for completion */
- DDL_RCM_EnableSysClkSwitch();
- while (DDL_RCM_IsActiveFlag_SWDONE() != 1)
- {
- }
- /* Set AHB, APB prescalers */
- DDL_RCM_SetAHBPrescaler(DDL_RCM_AHB_DIV_1);
- DDL_RCM_SetAPBPrescaler(DDL_RCM_APB_DIV_1);
-
- /* Disable clock switch controls */
- DDL_RCM_DisableSysClkSwitch();
-
- /* Lock clock control registers */
- DDL_RCM_Unlock();
- /* Update SystemCoreClock if used by the project */
- SystemCoreClockUpdate();
- }
- /*!
- * @brief ADC Init
- *
- * @param None
- *
- * @retval None
- */
- void ADC_Init(void)
- {
- /* GPIO init structure */
- DDL_GPIO_InitTypeDef GPIO_InitStruct = {0U};
- /* ADC init structure */
- DDL_ADC12_REG_InitTypeDef ADC_REG_InitStruct = {0U};
- /* Config Clock */
- DDL_RCM_Unlock();
- /* Set ADC3 clock source to SYSCLK */
- DDL_RCM_ADC_SetAdcAnalogClkSource(DDL_RCM_ADCACLK_SYSCLK);
- /* Set ADC3 Clock Division */
- DDL_RCM_ADC_SetAdc12AnalogClkDivision(DDL_RCM_ADC12ACLK_DIV_8);
- DDL_RCM_EnableAHBPeripheral(DDL_RCM_AHB_PERIPHERAL_GPIO);
- DDL_RCM_EnableAHBPeripheral(DDL_RCM_AHB_PERIPHERAL_ADC3);
- DDL_RCM_Lock();
- /* ADC channel 0 configuration */
- GPIO_InitStruct.Pin = DDL_GPIO_PIN_3;
- GPIO_InitStruct.Mode = DDL_GPIO_MODE_ANALOG;
- GPIO_InitStruct.Speed = DDL_GPIO_SPEED_FREQ_HIGH;
- GPIO_InitStruct.OutputType = DDL_GPIO_OUTPUT_PUSHPULL;
- GPIO_InitStruct.Pull = DDL_GPIO_PULL_NO;
- GPIO_InitStruct.Alternate = DDL_GPIO_AF_0;
- DDL_GPIO_Init(GPIOC, &GPIO_InitStruct);
- DDL_GPIO_EnableAnalogSwitchPin(GPIOC, DDL_GPIO_PIN_3);
- DDL_ADC12_InitTypeDef ADC_InitStruct = {0U};
- ADC_InitStruct.DataAlignment = DDL_ADC12_ALIGNMENT_RIGHT;
- DDL_ADC12_Init(ADC3, &ADC_InitStruct);
- /* Config ADC3 */
- ADC_REG_InitStruct.TriggerSource = DDL_ADC12_REG_TRIG_SOFTWARE;
- ADC_REG_InitStruct.SequencerLength = DDL_ADC12_REG_SEQ_SCAN_DISABLE;
- ADC_REG_InitStruct.SequencerDiscont = DDL_ADC12_REG_SEQ_DISCONT_DISABLE;
- ADC_REG_InitStruct.ContinuousMode = DDL_ADC12_REG_CONV_CONTINUOUS;
- ADC_REG_InitStruct.DMATransfer = DDL_ADC12_REG_DMA_TRANSFER_DISABLE;
- DDL_ADC12_REG_Init(ADC3, &ADC_REG_InitStruct);
- /* Set the sampling time of ADC3 */
- DDL_ADC12_SetChannelSamplingTime(ADC3, DDL_ADC12_CHANNEL_0, DDL_ADC12_SAMPLINGTIME_128CYCLES);
- DDL_ADC12_REG_SetSequencerLength(ADC3, DDL_ADC12_REG_SEQ_SCAN_DISABLE);
- DDL_ADC12_REG_SetSequencerRanks(ADC3, DDL_ADC12_REG_RANK_1, DDL_ADC12_CHANNEL_0);
- /* Set the upper and lower threshold of AWD1 for ADC3. */
- /* Upper threshold voltage: 2268 mV = 0xB00 * 3300 / 4095 */
- /* Lower threshold voltage: 618 mV = 0x300 * 3300 / 4095 */
- DDL_ADC12_ConfigAnalogWDThresholds(ADC3, DDL_ADC12_AWD1, 0xB00, 0x300);
- /* Enable the mode for ADC3 AWD1 */
- DDL_ADC12_SetAnalogWDMonitChannels(ADC3, DDL_ADC12_AWD1, DDL_ADC12_AWD_CHANNEL_0_REG);
- /* Enable Interrupt */
- DDL_ADC12_EnableIT_EOC(ADC3);
- DDL_ADC12_EnableIT_AWD1(ADC3);
- DDL_Interrupt_Register(ADC3_IRQn, ADC_Isr);
- DDL_NVIC_EnableIRQRequest(ADC3_IRQn, 1, 1);
- DDL_ADC12_Enable(ADC3);
- while (DDL_RCM_ADC_IsAdc12AnalogClkRDY() == RESET);
- /* ADC start conversion */
- DDL_ADC12_REG_StartConversion(ADC3);
- }
- /*!
- * @brief ADC interrupt service routine
- *
- * @param None
- *
- * @retval None
- */
- void ADC_Isr(void)
- {
- uint16_t adcData = 0;
- uint16_t voltage = 0;
- if(DDL_ADC12_IsActiveFlag_AWD1(ADC3))
- {
- /* Turn on LED1 */
- BOARD_LEDOn(LED1);
- iAWD_Flag = 1;
- }
- if(DDL_ADC12_IsActiveFlag_EOC(ADC3))
- {
- adcData = DDL_ADC12_REG_ReadConversionData32(ADC3);
- voltage = (adcData * 3300) / 4095;
- if(iAWD_Flag == 1 )
- {
- printf("\r\nADC1 Analog Window Watchdog is active.\r\n");
- iAWD_Flag = 0;
- }
- else
- {
- /* Turn off LED1 */
- BOARD_LEDOff(LED1);
- }
- printf("\r\n voltage : %d mV\r\n", voltage);
- Delay(0x1FF);
- }
- /* Clear ADC3 AWD pending interrupt bit */
- DDL_ADC12_ClearFlag_AWD1(ADC3);
- /* Clear ADC3 EOC pending interrupt bit */
- DDL_ADC12_ClearFlag_EOC(ADC3);
- }
- /*!
- * @brief Delay
- *
- * @param count: delay count
- *
- * @retval None
- */
- void Delay(uint32_t count)
- {
- volatile uint32_t delay = count;
- while(delay--);
- }
- #if defined(__CC_ARM) || defined(__ARMCC_VERSION)
- /*!
- * @brief Redirect C Library function printf to serial port.
- * After Redirection, you can use printf function.
- *
- * @param ch: The characters that need to be send.
- *
- * @param *f: pointer to a FILE that can recording all information
- * needed to control a stream
- *
- * @retval The characters that need to be send.
- *
- * @note
- */
- int fputc(int ch, FILE* f)
- {
- /* send a byte of data to the serial port */
- DDL_USART_TransmitData8(DEBUG_USART, (uint8_t)ch);
-
- /* wait for the data to be send */
- while (DDL_USART_IsActiveFlag_TC(DEBUG_USART) == RESET);
- return (ch);
- }
- #elif defined(__ICCARM__)
- /*!
- * @brief Redirect C Library function printf to serial port.
- * After Redirection, you can use printf function.
- *
- * @param ch: The characters that need to be send.
- *
- * @retval The characters that need to be send.
- *
- * @note
- */
- int __io_putchar(int ch)
- {
- /* send a byte of data to the serial port */
- DDL_USART_TransmitData8(DEBUG_USART, (uint8_t)ch);
-
- /* wait for the data to be send */
- while (DDL_USART_IsActiveFlag_TC(DEBUG_USART) == RESET);
- return (ch);
- }
- /*!
- * @brief Redirect C Library function printf to serial port.
- * After Redirection, you can use printf function.
- *
- * @param file: Meaningless in this function.
- *
- * @param *ptr: Buffer pointer for data to be sent.
- *
- * @param len: Length of data to be sent.
- *
- * @retval The characters that need to be send.
- *
- * @note
- */
- int __write(int file, char* ptr, int len)
- {
- int i;
- for (i = 0; i < len; i++)
- {
- __io_putchar(*ptr++);
- }
- return len;
- }
- #elif defined (__clang__) && !defined (__ARMCC_VERSION)
- int uart_putc(char ch, FILE *file)
- {
- /* send a byte of data to the serial port */
- DDL_USART_TransmitData8(DEBUG_USART, (uint8_t)ch);
-
- /* wait for the data to be send */
- while (DDL_USART_IsActiveFlag_TC(DEBUG_USART) == RESET);
- return (ch);
- }
- static FILE __stdio = FDEV_SETUP_STREAM(uart_putc, NULL, NULL, _FDEV_SETUP_WRITE);
- FILE *const stdin = &__stdio;
- __strong_reference(stdin, stdout);
- __strong_reference(stdin, stderr);
- #else
- #warning Not supported compiler type
- #endif
下一篇,最后看看其他功能,或者什么项目。