0x00 前言

因为笔者的某些使用要求,这里测试完了HC32F460的IO最快的直接反转的速度,因为语言执行与未接外设的情况下,可能反应的只是软件切换的情况下最大的反转速度,并不能代表真实的最快速度。

本文还有一个主要原因是为了测试笔者购得的梦源逻辑分析仪的效果。

技能熟练度
C语言熟悉
数字电路熟悉

0x10 测试环境

电脑一台,系统版本为Windows 10

调试器为CMSIS DAP系列,使用串口进行更新。

调试区域是当前的HC32F460JET6,输出引脚为PB5。

使用了逻辑分析仪为梦源个人版Plus,采样频率为400MHz。

0x20 测试程序

首先,对测试引脚的最快翻转有影响的主要有:软件因素、硬件因素、环境因素。

软件因素:主要是固件的执行效率和实际的寄存器延迟。这个可以使用尽量大的优化等级以及尽量简单的操作实现。由于现在的C编译器对于流程优化已经很好了,所以这里不再使用汇编进行调试。

硬件因素:主要是当前的硬件的端口电容、端口的极限反转速度。因为笔者在开发板上测试,当前引脚直接引出,据测试点距离不超过50mil,所以干扰原因极小,可以近似参考数据手册得到的端口电容10pF。

环境因素:主要为当前的逻辑分析仪的采样速率以及端口的采样电容的影响。经过查找可以看到,逻辑分析仪的输入电容为13pF.

image20211122195123934.png

这里可以查到在HC32系列手册内最快的输出频率约为100MHz(输入电容约为25pF)。所以在硬件层面上完全可以达到最快的输出。

image20211122195440891.png

测试代码

实际的测试代码如下:

void send_test()
{
  
    uint16_t *POx;
    while(1)
    {
    	POx = (uint16_t *)((uint32_t)(&M4_PORT->PORRA) ); 
        *POx = (*POx) | Pin05;

    	POx = (uint16_t *)((uint32_t)(&M4_PORT->POSRA) );
        *POx = (*POx) | Pin05;
  
    }


}

这就组成了最简单的一个翻转的函数。

需要注意的是,这里还需要打开编译器的-O3的优化。这样可以达到较为稳定的快速优化。

0x30 测试结果

最后使用测试函数测试的结果如下。

image20211122211046389.png

image20211122211135726.png

可以看到,当前翻转的速度还是可以达到负脉冲40MHz稳定输出,正脉冲约为10MHz。这里测试主要因为当前的幅值与当前优化的区别。

下面笔者打开O3优化并优化时间。

image20211122211446556.png

这里可以看到,当前的最大优化等级下,频率逐渐趋近于10MHz。

一般情况下,我们不可能使用这种代码驱动。

于是笔者用比较温和的驱动方式。

void send_test()
{
    static unsigned char stat = 0;
    uint16_t *POx;
    stat = 1 - stat;
    if(stat)
    	POx = (uint16_t *)((uint32_t)(&M4_PORT->PORRA) ); 
    else
    	POx = (uint16_t *)((uint32_t)(&M4_PORT->POSRA) );
    *POx = (*POx) | Pin05;
}

int main()
  {
    clk_init();   
    io_init();
    while(1)
        send_test();
}

这个就是结果

image20211122212111534.png

这里可以看出来,基本上已经可以稳定输出IO了。这个频率大概在4MHz左右。

如果使用输入参数的方式则大概为330nS左右的稳定翻转。频率大约在3MHz左右。

0x40 测试的总体代码

void send_test()
{
    static unsigned char stat = 0;
    uint16_t *POx;
    stat = 1 - stat;
    if(stat)
    	POx = (uint16_t *)((uint32_t)(&M4_PORT->PORRA) ); 
    else
    	POx = (uint16_t *)((uint32_t)(&M4_PORT->POSRA) );
    *POx = (*POx) | Pin05;

}
//外部时钟源8MHz
void clk_init()
{
    stc_clk_xtal_cfg_t xtal_init_struct;
    stc_clk_sysclk_cfg_t sysclk_init_struct;
    stc_clk_mpll_cfg_t mpll_init_struct;
    stc_clk_upll_cfg_t upll_init_struct;
    stc_clk_fcm_cfg_t fcm_init_struct;
    stc_sram_config_t sram_init_struct;
    stc_clk_freq_t freq_init_struct;

  
    MEM_ZERO_STRUCT(xtal_init_struct);
    MEM_ZERO_STRUCT(sysclk_init_struct);
    MEM_ZERO_STRUCT(mpll_init_struct);
    MEM_ZERO_STRUCT(upll_init_struct);
    MEM_ZERO_STRUCT(fcm_init_struct);
    MEM_ZERO_STRUCT(sram_init_struct);
    MEM_ZERO_STRUCT(freq_init_struct);

    CLK_GetClockFreq(&freq_init_struct);
  
    xtal_init_struct.enFastStartup = Enable;
    xtal_init_struct.enMode = ClkXtalModeOsc;
    xtal_init_struct.enDrv = ClkXtalTinyDrv;
  
    CLK_XtalConfig(&xtal_init_struct);
    CLK_XtalCmd(Enable);
    while (Set != CLK_GetFlagStatus(ClkFlagXTALRdy))
    {
    }
    CLK_SetSysClkSource(ClkSysSrcXTAL); //切换当前通道为外部时钟的通道
    /* MPLL config (XTAL / pllmDiv * plln / PllpDiv = 200M). */
    mpll_init_struct.pllmDiv = 8;
    mpll_init_struct.plln = 400;
    mpll_init_struct.PllpDiv = 2;
    mpll_init_struct.PllqDiv = 1;
    mpll_init_struct.PllrDiv = 1;
    EFM_Unlock();
    EFM_SetLatency(EFM_LATENCY_5);
    EFM_Lock();

    CLK_MpllConfig(&mpll_init_struct);
    CLK_MpllCmd(Enable);
    while (Set != CLK_GetFlagStatus(ClkFlagMPLLRdy))
    {
    }

    /* UPLL config (XTAL / pllmDiv * plln / PllpDiv = 480M). */
    upll_init_struct.pllmDiv = 8;
    upll_init_struct.plln = 500;//480
    upll_init_struct.PllrDiv = 12;  //run USB must use UPLLR 48M
    upll_init_struct.PllqDiv = 1;
    upll_init_struct.PllpDiv = 1;

  
    CLK_UpllConfig(&upll_init_struct);
    CLK_UpllCmd(Enable);
    while (Set != CLK_GetFlagStatus(ClkFlagUPLLRdy))
    {
    }


    sysclk_init_struct.enHclkDiv = ClkSysclkDiv1;   // 168MHz
    sysclk_init_struct.enExclkDiv = ClkSysclkDiv2;  // 84MHz
    sysclk_init_struct.enPclk0Div = ClkSysclkDiv1;  // 168MHz
    sysclk_init_struct.enPclk1Div = ClkSysclkDiv2;  // 84MHz
    sysclk_init_struct.enPclk2Div = ClkSysclkDiv4;  // 42MHz
    sysclk_init_struct.enPclk3Div = ClkSysclkDiv4;  // 42MHz
    sysclk_init_struct.enPclk4Div = ClkSysclkDiv2;  // 84MHz

    CLK_SysClkConfig(&sysclk_init_struct);


    sram_init_struct.u8SramIdx = Sram12Idx | Sram3Idx | SramHsIdx | SramRetIdx;
    sram_init_struct.enSramRC = SramCycle2;
    sram_init_struct.enSramWC = SramCycle2;
    sram_init_struct.enSramEccMode = EccMode3;
    sram_init_struct.enSramEccOp = SramNmi;
    sram_init_struct.enSramPyOp = SramNmi;
  
    SRAM_Init(&sram_init_struct);


    CLK_SetPllSource(ClkPllSrcXTAL);    //pll的切换用了晶振的
    /* flash read wait cycle setting */

    CLK_TpiuClkConfig(ClkTpiuclkDiv4);  //CM4的调制为50M
    CLK_SetUsbClkSource(ClkUsbSrcUpllr);//USB时钟丿48M


    CLK_SetSysClkSource(ClkSysSrcMPLL); //切换当前通道为外部时钟的通道
    CLK_GetClockFreq(&freq_init_struct);

}




void io_init()
{
    stc_port_init_t port_init_struct;
    TaskHandle_t led_task_handle;
    unsigned int start_limit;
    port_init_struct.enPinMode = Pin_Mode_Out;
    port_init_struct.enPullUp = Enable;
    port_init_struct.enLatch = Disable;
    port_init_struct.enExInt = Disable;
    port_init_struct.enInvert = Disable;
    port_init_struct.enPullUp = Enable;
    port_init_struct.enPinDrv = Pin_Drv_H;
    port_init_struct.enPinOType = Pin_OType_Cmos;
    port_init_struct.enPinSubFunc = Enable;


    PORT_Init(PortA, Pin05, &port_init_struct);
}

int main()
  {
    clk_init();         //测试时钟树
    io_init();
    while(1)
        send_test();
}

标题:关于HC32F460 IO的最快翻转速度测试
作者:GreenDream
地址:HTTPS://greendreamer.work/articles/2021/11/22/1637589409841.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!