首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PIC32速度:优化c代码

PIC32速度:优化c代码
EN

Stack Overflow用户
提问于 2015-11-02 01:07:27
回答 1查看 233关注 0票数 0

我想要一些建议来优化我的代码,这是一个简单的,但它需要是快速的,我指的是小于250 ns的东西。

我的第一个代码很慢,大约1000 ns,但经过一些工作,它大约是550 ns,但我相信它可以更快,但我不知道如何:<

我使用的是系统时钟为80 MHz的PIC32

我的代码:

代码语言:javascript
复制
void main()
{
    unsigned long int arr_1[4095]; 
    unsigned long int arr_2[4095]; 

    //here I assign arr_1 and arr_2 values
    //...
    //...

    TRISC = 0;
    TRISD = 0;

    while(1){
         LATC = arr_1[PORTE];
         LATD = arr_2[PORTE];
    }

}

正如你所看到的,这是一项非常简单的工作,唯一的问题是速度。

我看了汇编清单,只是想看看有多少指令,但我不知道汇编语言如何优化它。

代码语言:javascript
复制
;main.c, 14 ::      LATC = arr_1[PORTE];
0x9D000064  0x27A30000  ADDIU   R3, SP, 0
0x9D000068  0x3C1EBF88  LUI R30, 49032
0x9D00006C  0x8FC26110  LW  R2, 24848(R30)
0x9D000070  0x00021080  SLL R2, R2, 2
0x9D000074  0x00621021  ADDU    R2, R3, R2
0x9D000078  0x8C420000  LW  R2, 0(R2)
0x9D00007C  0x3C1EBF88  LUI R30, 49032
0x9D000080  0xAFC260A0  SW  R2, 24736(R30)
;main.c, 15 ::      LATD = arr_2[PORTE];
0x9D000084  0x27A33FFC  ADDIU   R3, SP, 16380
0x9D000088  0x3C1EBF88  LUI R30, 49032
0x9D00008C  0x8FC26110  LW  R2, 24848(R30)
0x9D000090  0x00021080  SLL R2, R2, 2
0x9D000094  0x00621021  ADDU    R2, R3, R2
0x9D000098  0x8C420000  LW  R2, 0(R2)
0x9D00009C  0x3C1EBF88  LUI R30, 49032
;main.c, 16 ::      }
0x9D0000A0  0x0B400019  J   L_main0
0x9D0000A4  0xAFC260E0  SW  R2, 24800(R30)  

有什么建议可以优化我的代码吗?

编辑:

*端口、LATC和LATD是I/O映射寄存器*代码的目标是在端口更改时尽可能快地更改LATC和LATD寄存器(因此端口是输入,而LATC和LATD是输出),输出取决于端口的值

EN

回答 1

Stack Overflow用户

发布于 2015-11-02 03:06:48

一个潜在的限制因素是,由于PORTELATCLATD不是常规存储器而是I/O寄存器,所以I/O总线速度可能低于存储器总线速度,并且处理器在访问之间插入等待状态。对于PIC32来说,这可能是情况,也可能不是,但这是任何架构都需要考虑的一般问题。

如果I/O总线不是一个限制,那么首先,您是否应用了编译器优化?对于这样的微优化,这通常是你最好的选择。这段代码似乎进行了微不足道的优化,但汇编程序似乎没有反映这一点(尽管我不是MIPS汇编专家-但编译器优化器是)。

由于I/O寄存器是易失性的,因此优化器在优化循环体方面可能会显着失败。但由于它们是易失性的,代码也可能是不安全的,因为PORTE有可能(确实很可能)在LATCLATD的赋值之间改变值,这可能不是您的意图或期望。如果是这种情况,则应按如下方式更改代码:

代码语言:javascript
复制
int porte_value_latch = 0 ;
for(;;)
{
     // Get a non-volatile copy of PORTE.
     porte_value_latch = PORTE ;  

     // Write LATC/D with a consistent PORTE value that 
     // won't change between assignments, and does not need 
     // to be read from memory or I/O.
     LATC = arr_1[porte_value_latch] ;
     LATD = arr_2[porte_value_latch] ;
}

这既安全又潜在地更快,因为易失性PORTE仅被读取一次,并且porte_value_latch值可以被保留在临时寄存器中用于两次阵列访问,而不是每次都从存储器读取。优化器几乎肯定会将其优化为寄存器访问,即使常规编译不会这样做。

使用for(;;)而不是while(1)可能没有什么区别,但一些编译器会对不变表达式发出警告,因为它会悄悄地接受for(;;)习惯用法。您没有包含第13行的代码汇编程序,因此无法确定编译器生成了什么。

如果LATCLATD位于相邻的地址,则可以进行进一步的优化,在这种情况下,您可以使用unsigned long long int类型的单个数组,以便在单个赋值中写入这两个位置。当然,64位访问仍然是非原子的,但编译器在任何情况下都可以生成更有效的代码。它还巧妙地避免了对porte_value_latch变量的需要,因为这样将只有一个对PORTE的引用。但是,如果必须以特定的顺序编写LATCLATD,您将失去该级别的控制。该循环将如下所示:

代码语言:javascript
复制
for(;;)
{
    LATCD = arr_1_2[PORTE] ;
}

其中,LATCD的地址是相邻LATCLATD寄存器的低位地址,类型为unsigned long long int。如果LATC具有较低的地址,则:

代码语言:javascript
复制
unsigned long long int LATCD = (unsigned long long int)LATC ;

因此写入LATCD会同时写入LATC和LATD。然后,Toy必须将arr_1arr_2组合成具有适当词序的单个unsigned long long数组,以便它在单个值中同时包含C和D值。

另一个建议:配置硬件,使用从>=4MHz的时钟信号触发的直接存储器访问来读取端口到单个位置。然后,该循环将根本不需要读取端口,而是读取DMA存储器位置,这可能更快,也可能不更快。您还可以将DMA设置为从内存位置写入LATC/LATD,以便循环根本不执行I/O。该方法还将允许“相邻内存”方法工作,即使LATC和LATD实际上并不相邻。

最终,如果问题只是编译器的代码生成,那么在内联汇编程序中实现循环并手动优化它可能是有意义的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33464795

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档