[G32R] 【极海G32R430 TinyBoard开发板测评】+TMU测试

[复制链接]
16|0
yinxiangxv 发表于 2026-4-25 13:03 | 显示全部楼层 |阅读模式
为了完成申请时提出的要求,也就是要测试一下TMU这个性能,于是一顿折腾后终于出结果了。

geehy_tmu.jpg
这个是调试界面,可以跳转到关键的寄存器配置和相关定义。

下面补充一下关键的代码:
geehy_debug.jpg
下面是tmu_benchmark.c的代码:
  1. #include <stdio.h>
  2. #include <math.h>
  3. #include "MathLib.h"
  4. #include "g32r4xx.h"
  5. #include "tmu_benchmark.h"

  6. // 计时辅助宏(假设已初始化 DWT)
  7. #define START_TIMER()   uint32_t start = DWT->CYCCNT
  8. #define GET_CYCLES()    (DWT->CYCCNT - start)

  9. void Run_TMU_Benchmark(int32_t x, int32_t y) {
  10.     uint32_t tmu_cycles[9]; // 记录1-8级的耗时
  11.     float tmu_errors[9];
  12.     uint32_t soft_cycles;
  13.     float soft_res;

  14.     // 开启 FPU 与 CDE(自定义数据路径扩展) 协处理器权限
  15.     // Geehy 的 ATAN2 底层使用了 ARM CDE 自定义指令,必须开启 CP0-CP7 以及 CP10-CP11
  16.     SCB->CPACR |= 0xFFFF;
  17.     __ISB(); // 指令同步屏障,确保后续的 CDE 指令不会抛出异常


  18.     // 1. 标准 C 库测试 (运行 1000 次取平均)
  19.     float fx = (float)x / 2147483648.0f;
  20.     float fy = (float)y / 2147483648.0f;
  21.    
  22.     START_TIMER();
  23.     for(int i=0; i<1000; i++) {
  24.         soft_res = atan2f(fy, fx);
  25.     }
  26.     soft_cycles = GET_CYCLES() / 1000;

  27.     int soft_res_int = (int)soft_res;
  28.     int soft_res_frac = (int)(fabsf(soft_res - soft_res_int) * 10000.0f);
  29.     printf("--- Benchmark Result (Soft: %d cycles, Result: %d.%04d rad) ---\r\n", soft_cycles, soft_res_int, soft_res_frac);


  30.     // 2. TMU 硬件测试 (遍历 1-8 精度等级)
  31.     for(int level = 1; level <= 8; level++) {
  32.         int32_t tmu_raw;
  33.         
  34.         START_TIMER();
  35.         for(int i=0; i<1000; i++) {
  36.             tmu_raw = ATAN2(x, y, level);
  37.         }
  38.         tmu_cycles[level] = GET_CYCLES() / 1000;

  39.         // 计算误差
  40.         float tmu_float = (float)tmu_raw / 2147483648.0f * 3.1415926535f;
  41.         float error = fabsf(tmu_float - soft_res);

  42.         // 分离整数和小数部分进行打印,避免 %f 触发 printf 内部死机
  43.         int tmu_int = (int)tmu_float;
  44.         int tmu_frac = (int)(fabsf(tmu_float - tmu_int) * 10000.0f);
  45.         
  46.         int err_int = (int)error;
  47.         int err_frac = (int)(fabsf(error - err_int) * 100000000.0f);

  48.         printf("  Level %d | Cycles: %d | Result: %d.%04d rad | Error: %d.%08d\r\n",
  49.                 level, tmu_cycles[level], tmu_int, tmu_frac, err_int, err_frac);
  50.     }

  51. }
对应的main.c代码:
  1. /**
  2. *
  3. * [url=/u/file]@file[/url]        main.c
  4. *
  5. * [url=/u/brief]@brief[/url]       Main program body
  6. *
  7. * [url=/u/version]@version[/url]     V1.0.0
  8. *
  9. * [url=/u/date]@date[/url]        2025-10-30
  10. *
  11. * @attention
  12. *
  13. *  Copyright (C) 2025 Geehy Semiconductor
  14. *
  15. *  You may not use this file except in compliance with the
  16. *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
  17. *
  18. *  The program is only for reference, which is distributed in the hope
  19. *  that it will be useful and instructional for customers to develop
  20. *  their software. Unless required by applicable law or agreed to in
  21. *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
  22. *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
  23. *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
  24. *  and limitations under the License.
  25. */

  26. /* Includes ***************************************************************/
  27. #include "main.h"

  28. /* Private includes *******************************************************/
  29. #include <stdio.h>
  30. #include "tmu_benchmark.h"
  31. #include "system_g32r4xx_dwtmeasure.h"

  32. /* Private macro **********************************************************/
  33. #define DEBUG_USART COM2_PORT
  34. /* === 新增:DWT 周期计数器底层操作宏 === */
  35. #ifndef ENABLE_DWT_CYCCNT
  36. // 1. 开启内核 Debug 模块 (DEMCR的 TRCENA 位)
  37. // 2. 将计数器清零
  38. // 3. 开启周期计数器 (CYCCNTENA 位)
  39. #define ENABLE_DWT_CYCCNT() \
  40.     do { \
  41.         CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; \
  42.         DWT->CYCCNT = 0; \
  43.         DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; \
  44.     } while(0)
  45. #endif

  46. #ifndef RESET_DWT_CYCCNT
  47. #define RESET_DWT_CYCCNT() (DWT->CYCCNT = 0)
  48. #endif
  49. /* Private typedef ********************************************************/

  50. /* Private variables ******************************************************/
  51. /* ADC AWD Active Flag */
  52. uint8_t iAWD_Flag = 0;

  53. /* Private function prototypes ********************************************/
  54. void DDL_SysClkConfig(void);
  55. void ADC_Init(void);
  56. void ADC_Isr(void);

  57. /* Delay */
  58. void Delay(uint32_t count);

  59. /* External variables *****************************************************/

  60. /* External functions *****************************************************/

  61. /**
  62. * @brief     Main program
  63. *
  64. * @param     None
  65. *
  66. * @retval    None
  67. *
  68. */
  69. int main(void)
  70. {
  71.     /* USART init structure */
  72.     DDL_USART_InitTypeDef USART_InitStruct = {0U};

  73.     /* Configure system clock */
  74.     DDL_SysClkConfig();

  75.     /* Configure interrupt group 4: 4-bit preemptive priority, 0-bit subpriority */
  76.     DDL_NVIC_ConfigPriorityGroup(DDL_NVIC_PRIORITY_GROUP_4);

  77.     /* USART Init */
  78.     USART_InitStruct.BaudRate            = 115200U;
  79.     USART_InitStruct.DataWidth           = DDL_USART_DATAWIDTH_8B;
  80.     USART_InitStruct.StopBits            = DDL_USART_STOPBITS_1;
  81.     USART_InitStruct.Parity              = DDL_USART_PARITY_NONE ;
  82.     USART_InitStruct.TransferDirection   = DDL_USART_DIRECTION_TX_RX;
  83.     USART_InitStruct.HardwareFlowControl = DDL_USART_HWCONTROL_NONE;
  84.     USART_InitStruct.OverSampling        = DDL_USART_OVERSAMPLING_16;
  85.     BOARD_COMInit(COM2, &USART_InitStruct);

  86.     /* LED1 Init */
  87.     BOARD_LEDInit(LED1);

  88.     printf("\r\nADC3 Analog Window Watchdog Examples.\r\n");
  89.     /* ========================================================================= */
  90.     /* ==================== 融合 DWT 计时与 TMU 测试逻辑 ======================= */
  91.     /* ========================================================================= */
  92.    
  93.     /* 1. 必须在调用 TMU_Benchmark 前开启 DWT,否则内部计时器无效 */
  94.     ENABLE_DWT_CYCCNT();
  95.     RESET_DWT_CYCCNT();  // 确保从 0 开始

  96.     /* 2. 获取开始前的 CPU 周期数 */
  97.     uint32_t start_cycles = DWT->CYCCNT;

  98.     /* 3. 运行你的核心测试代码 (内部也会调用 DWT->CYCCNT) */
  99.     Run_TMU_Benchmark(1073741824, 1073741824); // 传入 Q31 格式数据

  100.     /* 4. 获取结束时的 CPU 周期数 */
  101.     uint32_t end_cycles = DWT->CYCCNT;
  102.    
  103.     /* 5. 计算并打印总耗时 */
  104.     uint32_t total_cycles = end_cycles - start_cycles;
  105.     printf(">> Total Benchmark Execution Time: %u CPU Cycles <<\r\n\n", total_cycles);

  106.     /* ========================================================================= */
  107.     Run_TMU_Benchmark(1073741824, 1073741824);

  108.     /* ADC Init */
  109.     ADC_Init();
  110.    


  111.     while (1)
  112.     {
  113.     }
  114. }

  115. /**
  116. * @brief   System clock configuration
  117. *
  118. * @param   None
  119. *
  120. * @retval  None
  121. */
  122. void DDL_SysClkConfig(void)
  123. {
  124.     /* Unlock clock control registers */
  125.     /* Wait until the registers are unlocked */
  126.     DDL_RCM_Unlock();
  127.     while ((RCM->KEY & RCM_KEY_KEYST) != RCM_KEY_KEYST)
  128.     {
  129.     }

  130.     /* Enable HSE and wait for ready */
  131.     /* Enable HSE input clock */
  132.     DDL_RCM_HSE_Enable();
  133.     /* Wait until HSE is ready */
  134.     while (DDL_RCM_HSE_IsReady() != 1)
  135.     {
  136.         /* wait for HSERDY */
  137.     }

  138.     /* Configure Flash wait states appropriate for 120 MHz */
  139.     /* Set Flash wait period to accommodate higher frequency */
  140.     DDL_FLASH_SetWaitPeriod(FLASH_DDL_WAIT_PERIOD_3);
  141.     /* Set Flash erase time base to 120 MHz (use 119 to represent 120 MHz) */
  142.     DDL_FLASH_SetEraseTimeBase(119);

  143.     /* Configure PLL */
  144.     /* Ensure PLL is disabled prior to configuration */
  145.     DDL_RCM_PLL_Disable();

  146.     /* Configure PLL settings: multiplier, prescaler, and clock source */
  147.     /* PLL multiplier set to 15 (x15), prescaler no division, clock source from HSE */
  148.     DDL_RCM_PLL_SetMultiplier(15);
  149.     DDL_RCM_PLL_SetPrescaler(DDL_RCM_PLL_DIV1);
  150.     DDL_RCM_PLL_SetClkSource(DDL_RCM_PLL_CLKSOURCE_HSE);

  151.     /* Enable PLL and wait for ready */
  152.     DDL_RCM_PLL_Enable();
  153.     while (DDL_RCM_PLL_IsReady() != 1)
  154.     {
  155.         /* wait for PLL Ready */
  156.     }

  157.     /* Switch system clock to PLL output */
  158.     DDL_RCM_SetSysClkSource(DDL_RCM_SYS_CLKSOURCE_PLL);

  159.     /* Enable clock switch and wait for completion */
  160.     DDL_RCM_EnableSysClkSwitch();
  161.     while (DDL_RCM_IsActiveFlag_SWDONE() != 1)
  162.     {
  163.     }

  164.     /* Set AHB, APB prescalers */
  165.     DDL_RCM_SetAHBPrescaler(DDL_RCM_AHB_DIV_1);
  166.     DDL_RCM_SetAPBPrescaler(DDL_RCM_APB_DIV_1);
  167.    
  168.     /* Disable clock switch controls */
  169.     DDL_RCM_DisableSysClkSwitch();
  170.    
  171.     /* Lock clock control registers */
  172.     DDL_RCM_Unlock();

  173.     /* Update SystemCoreClock if used by the project */
  174.     SystemCoreClockUpdate();
  175. }

  176. /*!
  177. * @brief     ADC Init
  178. *
  179. * @param     None
  180. *
  181. * @retval    None
  182. */
  183. void ADC_Init(void)
  184. {
  185.     /* GPIO init structure */
  186.     DDL_GPIO_InitTypeDef GPIO_InitStruct = {0U};
  187.     /* ADC init structure */
  188.     DDL_ADC12_REG_InitTypeDef ADC_REG_InitStruct = {0U};

  189.     /* Config Clock */
  190.     DDL_RCM_Unlock();

  191.     /* Set ADC3 clock source to SYSCLK */
  192.     DDL_RCM_ADC_SetAdcAnalogClkSource(DDL_RCM_ADCACLK_SYSCLK);

  193.     /* Set ADC3 Clock Division */
  194.     DDL_RCM_ADC_SetAdc12AnalogClkDivision(DDL_RCM_ADC12ACLK_DIV_8);
  195.     DDL_RCM_EnableAHBPeripheral(DDL_RCM_AHB_PERIPHERAL_GPIO);
  196.     DDL_RCM_EnableAHBPeripheral(DDL_RCM_AHB_PERIPHERAL_ADC3);
  197.     DDL_RCM_Lock();

  198.     /* ADC channel 0 configuration */
  199.     GPIO_InitStruct.Pin        = DDL_GPIO_PIN_3;
  200.     GPIO_InitStruct.Mode       = DDL_GPIO_MODE_ANALOG;
  201.     GPIO_InitStruct.Speed      = DDL_GPIO_SPEED_FREQ_HIGH;
  202.     GPIO_InitStruct.OutputType = DDL_GPIO_OUTPUT_PUSHPULL;
  203.     GPIO_InitStruct.Pull       = DDL_GPIO_PULL_NO;
  204.     GPIO_InitStruct.Alternate  = DDL_GPIO_AF_0;
  205.     DDL_GPIO_Init(GPIOC, &GPIO_InitStruct);
  206.     DDL_GPIO_EnableAnalogSwitchPin(GPIOC, DDL_GPIO_PIN_3);

  207.     DDL_ADC12_InitTypeDef ADC_InitStruct = {0U};
  208.     ADC_InitStruct.DataAlignment = DDL_ADC12_ALIGNMENT_RIGHT;
  209.     DDL_ADC12_Init(ADC3, &ADC_InitStruct);

  210.     /* Config ADC3 */
  211.     ADC_REG_InitStruct.TriggerSource    = DDL_ADC12_REG_TRIG_SOFTWARE;
  212.     ADC_REG_InitStruct.SequencerLength  = DDL_ADC12_REG_SEQ_SCAN_DISABLE;
  213.     ADC_REG_InitStruct.SequencerDiscont = DDL_ADC12_REG_SEQ_DISCONT_DISABLE;
  214.     ADC_REG_InitStruct.ContinuousMode   = DDL_ADC12_REG_CONV_CONTINUOUS;
  215.     ADC_REG_InitStruct.DMATransfer      = DDL_ADC12_REG_DMA_TRANSFER_DISABLE;
  216.     DDL_ADC12_REG_Init(ADC3, &ADC_REG_InitStruct);

  217.     /* Set the sampling time of ADC3 */
  218.     DDL_ADC12_SetChannelSamplingTime(ADC3, DDL_ADC12_CHANNEL_0, DDL_ADC12_SAMPLINGTIME_128CYCLES);

  219.     DDL_ADC12_REG_SetSequencerLength(ADC3, DDL_ADC12_REG_SEQ_SCAN_DISABLE);
  220.     DDL_ADC12_REG_SetSequencerRanks(ADC3, DDL_ADC12_REG_RANK_1, DDL_ADC12_CHANNEL_0);

  221.     /* Set the upper and lower threshold of AWD1 for ADC3. */
  222.     /* Upper threshold voltage: 2268 mV = 0xB00 * 3300 / 4095 */
  223.     /* Lower threshold voltage:  618 mV = 0x300 * 3300 / 4095 */
  224.     DDL_ADC12_ConfigAnalogWDThresholds(ADC3, DDL_ADC12_AWD1, 0xB00, 0x300);

  225.     /* Enable the mode for ADC3 AWD1 */
  226.     DDL_ADC12_SetAnalogWDMonitChannels(ADC3, DDL_ADC12_AWD1, DDL_ADC12_AWD_CHANNEL_0_REG);

  227.     /* Enable Interrupt */
  228.     DDL_ADC12_EnableIT_EOC(ADC3);
  229.     DDL_ADC12_EnableIT_AWD1(ADC3);

  230.     DDL_Interrupt_Register(ADC3_IRQn, ADC_Isr);
  231.     DDL_NVIC_EnableIRQRequest(ADC3_IRQn, 1, 1);

  232.     DDL_ADC12_Enable(ADC3);
  233.     while (DDL_RCM_ADC_IsAdc12AnalogClkRDY() == RESET);

  234.     /* ADC start conversion */
  235.     DDL_ADC12_REG_StartConversion(ADC3);
  236. }

  237. /*!
  238. * @brief     ADC interrupt service routine
  239. *
  240. * @param     None
  241. *
  242. * @retval    None
  243. */

  244. void ADC_Isr(void)
  245. {
  246.     uint16_t adcData = 0;
  247.     uint16_t voltage = 0;

  248.     if(DDL_ADC12_IsActiveFlag_AWD1(ADC3))
  249.     {
  250.         /* Turn on LED1 */
  251.         BOARD_LEDOn(LED1);
  252.         iAWD_Flag = 1;
  253.     }

  254.     if(DDL_ADC12_IsActiveFlag_EOC(ADC3))
  255.     {
  256.         adcData = DDL_ADC12_REG_ReadConversionData32(ADC3);
  257.         voltage = (adcData * 3300) / 4095;
  258.         if(iAWD_Flag == 1 )
  259.         {
  260.             printf("\r\nADC1 Analog Window Watchdog is active.\r\n");
  261.             iAWD_Flag = 0;
  262.         }
  263.         else
  264.         {
  265.             /* Turn off LED1 */
  266.             BOARD_LEDOff(LED1);
  267.         }
  268.         printf("\r\n voltage : %d mV\r\n", voltage);
  269.         Delay(0x1FF);
  270.     }
  271.     /* Clear ADC3 AWD pending interrupt bit */
  272.     DDL_ADC12_ClearFlag_AWD1(ADC3);
  273.     /* Clear ADC3 EOC pending interrupt bit */
  274.     DDL_ADC12_ClearFlag_EOC(ADC3);
  275. }

  276. /*!
  277. * @brief       Delay
  278. *
  279. * @param       count:  delay count
  280. *
  281. * @retval      None
  282. */
  283. void Delay(uint32_t count)
  284. {
  285.     volatile uint32_t delay = count;
  286.     while(delay--);
  287. }

  288. #if defined(__CC_ARM) || defined(__ARMCC_VERSION)
  289. /*!
  290. * @brief       Redirect C Library function printf to serial port.
  291. *              After Redirection, you can use printf function.
  292. *
  293. * @param       ch:  The characters that need to be send.
  294. *
  295. * @param       *f:  pointer to a FILE that can recording all information
  296. *              needed to control a stream
  297. *
  298. * @retval      The characters that need to be send.
  299. *
  300. * @note
  301. */
  302. int fputc(int ch, FILE* f)
  303. {
  304.     /* send a byte of data to the serial port */
  305.     DDL_USART_TransmitData8(DEBUG_USART, (uint8_t)ch);
  306.    
  307.     /* wait for the data to be send */
  308.     while (DDL_USART_IsActiveFlag_TC(DEBUG_USART) == RESET);

  309.     return (ch);
  310. }
  311. #elif defined(__ICCARM__)

  312. /*!
  313. * @brief       Redirect C Library function printf to serial port.
  314. *              After Redirection, you can use printf function.
  315. *
  316. * @param       ch:  The characters that need to be send.
  317. *
  318. * @retval      The characters that need to be send.
  319. *
  320. * @note
  321. */
  322. int __io_putchar(int ch)
  323. {
  324.     /* send a byte of data to the serial port */
  325.     DDL_USART_TransmitData8(DEBUG_USART, (uint8_t)ch);
  326.    
  327.     /* wait for the data to be send */
  328.     while (DDL_USART_IsActiveFlag_TC(DEBUG_USART) == RESET);

  329.     return (ch);
  330. }

  331. /*!
  332. * @brief       Redirect C Library function printf to serial port.
  333. *              After Redirection, you can use printf function.
  334. *
  335. * @param       file:  Meaningless in this function.
  336. *
  337. * @param       *ptr:  Buffer pointer for data to be sent.
  338. *
  339. * @param       len:  Length of data to be sent.
  340. *
  341. * @retval      The characters that need to be send.
  342. *
  343. * @note
  344. */
  345. int __write(int file, char* ptr, int len)
  346. {
  347.     int i;
  348.     for (i = 0; i < len; i++)
  349.     {
  350.         __io_putchar(*ptr++);
  351.     }

  352.     return len;
  353. }
  354. #elif defined (__clang__) && !defined (__ARMCC_VERSION)

  355. int uart_putc(char ch, FILE *file)
  356. {
  357.     /* send a byte of data to the serial port */
  358.     DDL_USART_TransmitData8(DEBUG_USART, (uint8_t)ch);
  359.    
  360.     /* wait for the data to be send */
  361.     while (DDL_USART_IsActiveFlag_TC(DEBUG_USART) == RESET);

  362.     return (ch);
  363. }

  364. static FILE __stdio = FDEV_SETUP_STREAM(uart_putc, NULL, NULL, _FDEV_SETUP_WRITE);
  365. FILE *const stdin = &__stdio;

  366. __strong_reference(stdin, stdout);
  367. __strong_reference(stdin, stderr);

  368. #else

  369. #warning Not supported compiler type
  370. #endif
下一篇,最后看看其他功能,或者什么项目。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

58

主题

394

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部
0