C 转储闪存的微小代码
我正试图编写尽可能小的代码来提取英飞凌XMC4500微控制器的固件 代码必须适合30字节缓冲区,该缓冲区允许我使用Thumb 16位指令集拥有15条机器指令 从C开始,我尝试通过一个GPIO引脚转储闪存,这是一个很好的技巧 基本上我正在做的是:C 转储闪存的微小代码,c,assembly,embedded,arm,firmware,C,Assembly,Embedded,Arm,Firmware,我正试图编写尽可能小的代码来提取英飞凌XMC4500微控制器的固件 代码必须适合30字节缓冲区,该缓冲区允许我使用Thumb 16位指令集拥有15条机器指令 从C开始,我尝试通过一个GPIO引脚转储闪存,这是一个很好的技巧 基本上我正在做的是: 设置要输出的GPIO引脚方向 用时钟(SPI串行时钟)闪烁LED1(引脚1.1) 闪烁LED2(引脚1.0)和数据位(SPI MOSI) 用逻辑分析仪嗅探引脚 编辑: 更新C代码块 添加汇编代码块 #包括“XMC4500.h” void main(){
#包括“XMC4500.h”
void main(){
//在内存地址0x00000000处开始转储
无符号int*p=(uint32_t*)(0x0u);
//配置端口1输出(推拉)
端口1->IOCR0=0x8080u;
对于(;;){
int i=32;
int data=*(p++);
做{
//时钟低
端口1->OUT=0x0;
//数据位时钟高电平
端口1->OUT=0x2u |数据;
数据>>=1;
}而(-i>0);
}
}
然而,代码大小仍然太大,无法满足我的要求
我能做些什么来进一步缩减我的代码吗?任何可以优化或省去的东西?十六条指令并不是全部;我不希望C编译器能够产生足够高效的代码,从而使内存转储发生位爆炸。如果您对输出位模式不太挑剔,我认为32字节就足够了,可以使用以下内容:
ldr r1,=Port1 ; Address of IO Port
mov r3,#1
str r3,[r1+IOCR0]
lsl r0,r3,#27
bytes:
mov r5,#9
strb r5,[r1+OUT]
add r0,#1
ldrb r4,[r0]
bits:
strb r4,[r1+OUT]
lsr r4,#1
sub r5,#1
bne bits
b bytes
每个字节将作为一个高脉冲输出,然后是八位时间,可能是高或低(取决于数据读取),然后是位时间,该位时间始终为零,以确保下一个高脉冲的上升沿可见。基本上类似于异步串行通信,但级别相反。如果端口1的高位在此过程中没有变化,并且您可以确保在时钟变高后读取数据位,您可以尝试以下方法:
#define P1_DEFAULT = ?//constant high bits of port 1, zeros in low two bits
int* dp=0; //maybe use a register which is known to be zeroed.
PORT1->IOCR0 = 0x8080; //should be 3 ins
for(;;){
int i=32; //
int data=*(dp++); //LDMIA instruction may do load and increment in 1 step.
do{
PORT1->OUT = P1_DEFAULT #clock low
PORT1->OUT = P1_DEFAULT + 2+ (data&1); #clock high with data
data>>=1;
} while (--i>0);
}
这将删除三端口读取、一端口写入和一个条件。在一个函数中完成这一切,以避免任何调用开销。我将从为此生成的程序集开始,看看您可以做些什么来改进它。对于如此严格的要求,您必须在程序集中完成。编译器不会针对空间进行优化(它会针对空间进行速度优化),也不会使用怪癖,因为它们通常会因更新而中断。获取程序,编译并读取/解码程序集输出。能否加载缓冲区,然后重新加载缓冲区?也就是说,您可以使用不同的代码序列将寄存器初始化为已知值,然后运行实际执行数据传输的代码吗?否则不太可能,因为大部分代码都将加载常量。@artlessnoise很遗憾,重新加载缓冲区不是一个选项。您是否测试了更改?
r12
始终为0,因此您可以使用它来清除时钟,或者它随着ldr.w
前进,在这种情况下,您可以将其用作p
。不是两者都有。而最新的变化现在也将“随机”数据写入端口1的高位引脚。你确定那不会引起问题吗?@AShelly我的改动很好。1.:r12确实与ldr一起前进。然而,ldr.w将r12增加4,这将始终给我一个偶数。位1将始终为零。在这种情况下,我可以使用r12作为p和清除时钟。2.:为了切换两个引脚,我只需要前两位;所以我想没有必要担心高脚,对吧?谢谢你的提示!代码缩减到44字节!现在,我将进入生成的程序集,并尝试进行更多改进(请参阅上面更新的代码块)。很高兴它有所帮助。假设端口中的所有其他位都是1,用PORT1->OUT=0xFFFE |数据替换第二次写入代码>可能会删除其中一个添加。再次感谢!现在我有36字节的代码!还有三条指示要走!请参阅上面更新的代码块。我无法运行您的示例代码。没有输出。你测试过了吗?您的逻辑分析仪配置是什么?我没有测试过,因为我不熟悉您使用的精确控制器;我的假设是,在写入IOCR0的值中设置的任何位都将启用输出,而写入将设置这些IO引脚的高或低状态。
#define P1_DEFAULT = ?//constant high bits of port 1, zeros in low two bits
int* dp=0; //maybe use a register which is known to be zeroed.
PORT1->IOCR0 = 0x8080; //should be 3 ins
for(;;){
int i=32; //
int data=*(dp++); //LDMIA instruction may do load and increment in 1 step.
do{
PORT1->OUT = P1_DEFAULT #clock low
PORT1->OUT = P1_DEFAULT + 2+ (data&1); #clock high with data
data>>=1;
} while (--i>0);
}