AB32VG1超频,编译器优化设置

编程入门 行业动态 更新时间:2024-10-13 02:20:20

AB32VG1<a href=https://www.elefans.com/category/jswz/34/1702086.html style=超频,编译器优化设置"/>

AB32VG1超频,编译器优化设置

1.起因

之前修改了Helix解码库的底层强行使用C语言实现了底层,使得Helix解码库可以在任何处理器上运行。详情请见:Helix MP3解码库脱离汇编指令束缚,运行在任何处理器上的解决方案_Fairchild_1947的博客-CSDN博客

但是根据理论计算可知,解码44.1KHZ,320Kpbs的音频文件需要性能154.05DMIPS(具体计算请见上文),而AB32VG1的额定工作频率为120MHZ,实际使用时卡顿明显,因此欲通过编译器优化和超频使得该功能可以在AB32VG1单片机上正常使用。

2.编译器优化

编译器优化是非常稳妥的提高程序运行速度的方式,其设置如下图:

第1步:右键工程,并选择属性

第2步:选择C/C++构建

第3步:设置

第4步:点击Optimization

第5步:默认是不优化,从下拉单里面选择想要优化的等级即可,此处选择了最高3级优化

 3.编译器优化效果

不知道为什么RISC-V的编译器优化选择后编译后二进制文件大小不变,而且AB32VG1的下载软件带有一个检查两次下载镜像区别的功能,仅仅更新不同的地方,而调整了优化等级后,下载软件直接提示没有更新。

可能是我不了解RISC-V编译器,设置有误,请各位大佬指正。

 4.超频

原本以为这个想法很疯狂,没想到查看RT-Thread工程附赠的README.md时竟然看到了这样的一幕——

没想到官方已经抢先整活儿了,官方宣称可以超频到192MHZ,正好这也挑起了我的兴趣,我想试试AB32VG1的极限正常工作频率。 毕竟此前我把STM32F429一个额定180MHZ主频的单片机超频到了480MHZ与H7频率相同^*_^*

超频正式开始,RT-Thread会把时钟设置代码都放到board.c中,所以锁定这个文件找到对应的代码就可以改频率了。

4.1额定工作频率内的调整

额定工作频率内,即120MHZ以内调整可以用此方法,对了有什么意义呢?因为不知为何,新生成的工程都会默认48MHZ的工作频率,所以遇到AB32VG1性能不够的时候,有可能是因为工作的主频只有48MHZ,此函数代码如下:

void rt_hw_systick_init(void)
{CLKCON2 &= 0x00ffffff;CLKCON2 |= (25 << 24);                                  //配置x26m_div_clk = 1M (timer, ir, fmam ...用到)CLKCON0 &= ~(7 << 23);CLKCON0 |= BIT(24);                                     //tmr_inc select x26m_div_clk = 1Mset_sysclk(SYSCLK_48M);    //该这一句就可在额定频率范围内调整频率/* Setting software interrupt */set_cpu_irq_comm(cpu_irq_comm);rt_hw_interrupt_install(IRQ_SW_VECTOR, rt_soft_isr, RT_NULL, "sw_irq");timer0_init();hal_set_tick_hook(timer0_cfg);hal_set_ticks(get_sysclk_nhz() / RT_TICK_PER_SECOND);PICCON |= 0x10002;
}

改变set_sysclk的形参即可在额定频率范围内调整,注意,此函数的参数请从枚举中选择

4.2额定工作频率以上超频

超出额定工作频率后,将没有现成简洁的方法来进行超频,必须阅读倍频器设置代码,并进行手动修改。由于AB32VG1的芯片资料太少,内部时钟树的结构并没有详细文档介绍,那么就跟着例程的代码瞎摸索吧。锁相环设置的函数在文件system_ab32vg1.c中,函数如下:

void set_sysclk(uint32_t sys_clk)
{uint32_t uart_baud, spll_div = 0, spi_baud = 0, spi1baud;uint8_t cnt_1us, clk_sel;clk_sel = get_clksel_val(sys_clk);if(sys.clk_sel == clk_sel) {return;}
//    if (sys_clk > SYSCLK_48M) {
//        PWRCON0 = (PWRCON0 & ~0xf) | (sys_trim.vddcore + 1);            //VDDCORE加一档
//    }
//    vddcore_other_offset();//    printf("%s: %d, %d\n", __func__, sys_clk, clk_sel);switch (sys_clk) {case SYSCLK_12M:spll_div = 19;                   //pll0 240Mcnt_1us = 1;spi_baud = 0;spi1baud = 0;break;case SYSCLK_24M:spll_div = 9;                   //pll0 240Mcnt_1us = 2;spi_baud = 0;spi1baud = 1;break;case SYSCLK_30M:spll_div = 7;                   //pll0 240Mcnt_1us = 3;spi_baud = 1;                   //Baud Rate =Fsys clock / (SPI_BAUD+1)spi1baud = 1;break;case SYSCLK_48M:spll_div = 4;                   //pll0 240Mcnt_1us = 4;spi_baud = 1;                   //Baud Rate =Fsys clock / (SPI_BAUD+1)spi1baud = 3;break;case SYSCLK_60M:spll_div = 3;                   //pll0 240Mcnt_1us = 5;spi_baud = 2;                   //Baud Rate =Fsys clock / (SPI_BAUD+1)spi1baud = 3;break;case SYSCLK_80M:spll_div = 2;                   //pll0 240Mcnt_1us = 7;spi_baud = 3;                   //Baud Rate =Fsys clock / (SPI_BAUD+1)spi1baud = 4;break;case SYSCLK_120M:spll_div = 0;                   //pll0 240Mcnt_1us = 10;spi_baud = 4;                   //Baud Rate =Fsys clock / (SPI_BAUD+1)     //spiclk 120/5 = 24Mspi1baud = 9;break;case SYSCLK_26M:spll_div = 0;cnt_1us = 3;spi_baud = 1;spi1baud = 1;break;case SYSCLK_13M:spll_div = 1;cnt_1us = 1;spi_baud = 0;spi1baud = 0;break;case SYSCLK_2M:spll_div = 1;cnt_1us = 1;spi_baud = 0;spi1baud = 0;break;default:return;}//先判断PLL0是否打开if(clk_sel <= PLL0DIV_120M) {if (!(PLL0CON & BIT(12))) {PLL0CON &= ~(BIT(3) | BIT(4) | BIT(5));PLL0CON |= BIT(3);                     //Select PLL/VCO frequency band (PLL大于206M vcos = 0x01, 否则为0)PLL0CON |= BIT(12);                    //enable pll0 ldodelay_us(100);                         //delay 100usPLL0DIV = 240 * 65536 / 26;            //pll0: 240M, XOSC: 26MPLL0CON |= BIT(20);                    //update pll0div to pll0_clkPLL0CON |= BIT(6);                     //enable analog pll0PLL0CON |= BIT(18);                    //pll0 sdm enabledelay_us(1000);                        //wait pll0 stable}}syst_1us = cnt_1us;sys.sys_clk = sys_clk;sys.clk_sel = clk_sel;uart_baud =  (((get_sysclk_nhz() + (sys.uart0baud / 2)) / sys.uart0baud) - 1);set_sysclk_do(sys_clk, clk_sel,spll_div, spi_baud, spi1baud);set_peripherals_clkdiv();update_sd0baud();       //更新下SD0BAUDupdate_uart0baud_in_sysclk(uart_baud);
}

可以看到,这个函数用switch将不同频率选择分开设置参数,最后设置锁相环。而在参数设置时,有两个SPI开头的,这两个没有作用是SPI相关的,只有spll_div和cnt_1us两个参数是需要调整的,其中cnt_1us是设置系统时基的,如果超频了,但是这个值没有修改,那么将导致系统的延时功能、计时功能等的时间长度变化,在对绝对时间无要求的场合这个参数也可以不改。spll_div是倍频器倍频后的分频器。

这些参数会在最后调用set_sysclk_do函数真正发挥作用,set_sysclk_do函数内如如下:

static void set_sysclk_do(uint32_t sys_clk, uint32_t clk_sel, uint32_t spll_div, uint32_t spi_baud, uint32_t spi1baud)
{uint32_t cpu_ie;cpu_ie = PICCON & BIT(0);PICCONCLR = BIT(0);                             //关中断,切换系统时钟set_peripherals_clkdiv_safety();CLKCON0 &= ~(BIT(2) | BIT(3));                  //sysclk sel rc2mCLKCON2 &= ~(0x1f << 8);                        //reset spll divif(clk_sel <= PLL0DIV_120M) {//sys_clk来源PLL0的分频配置CLKCON0 &= ~(BIT(4) | BIT(5) | BIT(6));     //sys_pll select pll0outif (PLL0DIV != (240 * 65536 / 26)) {PLL0DIV = 230 * 65536 / 26;             //pll: 240M, XOSC: 26MPLL0CON &= ~(BIT(3) | BIT(4) | BIT(5));PLL0CON |= BIT(3);                      //Select PLL/VCO frequency band (PLL大于206M vcos = 0x01, 否则为0)PLL0CON |= BIT(20);                     //update pll0div to pll0_clkCLKCON3 &= ~(7 << 16);CLKCON3 |= (4 << 16);                   //USB CLK 48M}} else if (clk_sel <= OSCDIV_26M) {//sys_clk来源于XOSC26M时钟分频, 无USB时关闭PLL0
//        if (!is_usb_support()) {
//            PLL0CON &= ~BIT(18);
//            PLL0CON &= ~(BIT(12) | BIT(6));         //close pll0
//        }CLKCON0 &= ~(BIT(4) | BIT(5) | BIT(6));CLKCON0 |= BIT(6);                          //spll select xosc26m_clk}CLKCON2 |= (spll_div << 8);CLKCON0 |= BIT(3);                          //sysclk sel spllSPI0BAUD = spi_baud;if (CLKGAT1 & BIT(12)) {SPI1BAUD = spi1baud;}
//    if (spiflash_speed_up_en()) {
//        set_flash_safety(sys_clk);
//    }PICCON |= cpu_ie;
}

其中真真发挥作用的是给PLL0CON、PLL0DIV以及CLKCON0、CLKCON1等寄存器写入的语句。由于AB32VG1配套的文档没有对时钟系统的介绍,故这里用STM23的倍频器图代替理解。

倍频器可以选择从外部晶振和内部RC振荡器输入,输入后先预分频即“/M”再倍频即“*N”最后再分频即“/P”输入到后续的内核及外设。输入后,内核和不同的外设又拥有自己的分频器,再次分配,比如APB总线上的分频器,AHB总线上的分频器等。

接下来类比set_sysclk_do函数中的寄存器进行理解,PLL0CON就是Main PLL的“*N”,PLL0DIV就是Main PLL的“/M”,而CLKCON0、CLKCON1等好比APB、AHB总线上的分频器,其中通过观察发现CLKCON2是处理器的分频器,因为CLKCON2的设置参数来源于spll_div而此参数正是处理器的分频系数。

观察代码可发现,PLL0CON虽然是倍频设置,但是修改难度比较大不直观,而“PLL0DIV = 230 * 65536 / 26;             //pll: 240M, XOSC: 26M”这句不仅意思一目了然而且给了注释,那么就从这句下手改。

这句默认情况打开后参数是 240 * 65536 / 26,意思是,倍频器输出240MHZ前提是使用26MHZ的晶振,此时设置处理器分频为1(即2分频)即可得到120MHZ的额定主频。

超频时,笔者选择了将处理器分频改为0(不分频)然后不断修改PLL0DIV参数来进行超频。因为这种做法可以保证处理器之外的外设工作在额定频率以内,减少超频失败的因素。

实测发现,AB32VG1可以超频到比说明手册192MHZ更高的230MHZ稳定运行,当然再往上就不行了。

至此成功超频到230MHZ。

3.后续工作

超频后,由于AB32VG1默认是配有RT-Thread操作系统的,并不是裸机,所以需要重新设置系统定时器,以避免系统时间片过短。AB32VG1的系统定时器是timer0,设置的代码在board.c的void rt_hw_systick_init(void)函数,前文提到过,在这个函数中hal_set_ticks(get_sysclk_nhz()/RT_TICK_PER_SECOND);用来设置系统定时器的计数寄存器,这个将决定它的中断频率继而决定系统时间片长度。一路追溯下去发现获取参数的函数如下:

uint32_t get_sysclk_nhz(void)
{return sysclk_index[sys.sys_clk] * 1000000;
}

该函数直接从数组sysclk_index中的对应位置取值并乘以1M返回。而对应位置的参数sys.sys_clk正是在board.c的void rt_hw_systick_init(void)函数中调用set_sysclk(SYSCLK_120M);时写入的枚举变量SYSCLK_120M,因此我们可以在以此枚举变量为偏移量对应的sysclk_index数组那里修改为当前的实际工作频率。该数组定义如下:

const uint8_t sysclk_index[] = {2,12,13,24,26,30,48,60,80,120,
};

这里把数组最后的那个120改成230即可。

4.测试结果

超频230MHZ已经是很高的主频了。STM32F7系列也不过是216MHZ的主频。本以为可以秒天地的时候,不料再次尝试MP3功能时依旧有些许卡顿。而同样的算法,在STM32F429上180MHZ就可以非常流畅的运行。当然RISC-V编译器的优化也是拖后腿的一个很大原因,期待RISC-V编译器优化,相信优化后是可以性能是改天换地的!

更多推荐

AB32VG1超频,编译器优化设置

本文发布于:2024-03-06 08:33:56,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1714859.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:超频   编译器   优化设置

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!