我正在尝试为 ATtiny13 编写一个程序。我的问题是它有很大的尺寸限制。好吧,在制作我的第一个 Hello World 程序时,只需要 100 字节的程序空间就可以打开和关闭灯!我可以给 avr-gcc 提供什么选项来缩小这个大小吗?另外,crt0中有什么?我不太热衷于 AVR 组装,所以我不太了解它..
我不想为了这个项目而去组装..
我正在尝试为 ATtiny13 编写一个程序。我的问题是它有很大的尺寸限制。好吧,在制作我的第一个 Hello World 程序时,只需要 100 字节的程序空间就可以打开和关闭灯!我可以给 avr-gcc 提供什么选项来缩小这个大小吗?另外,crt0中有什么?我不太热衷于 AVR 组装,所以我不太了解它..
我不想为了这个项目而去组装..
您可以使用 avr-objdump -d .elf 查看正在生成的内容:
我们稍微分析一下:
[jpc@jpc ~] avr-objdump -d avr.elf | sed -e 's/^/ /' | pbcopy
avr.elf: file format elf32-avr
Disassembly of section .text:
00000000 <__vectors>:
0: 09 c0 rjmp .+18 ; 0x14 <__ctors_end>
2: 0e c0 rjmp .+28 ; 0x20 <__bad_interrupt>
4: 0d c0 rjmp .+26 ; 0x20 <__bad_interrupt>
6: 0c c0 rjmp .+24 ; 0x20 <__bad_interrupt>
8: 0b c0 rjmp .+22 ; 0x20 <__bad_interrupt>
a: 0a c0 rjmp .+20 ; 0x20 <__bad_interrupt>
c: 09 c0 rjmp .+18 ; 0x20 <__bad_interrupt>
e: 08 c0 rjmp .+16 ; 0x20 <__bad_interrupt>
10: 07 c0 rjmp .+14 ; 0x20 <__bad_interrupt>
12: 06 c0 rjmp .+12 ; 0x20 <__bad_interrupt>
20 字节中断向量表(如果您坚持并承诺永远不会启用相应的中断,至少可以省略一些条目)。
00000014 <__ctors_end>:
14: 11 24 eor r1, r1
16: 1f be out 0x3f, r1 ; 63
18: cf e9 ldi r28, 0x9F ; 159
1a: cd bf out 0x3d, r28 ; 61
1c: 02 d0 rcall .+4 ; 0x22 <main>
1e: 05 c0 rjmp .+10 ; 0x2a <_exit>
清除 SREG(我不确定这是否真的需要),将 0x9f(RAMEND)写入 SPL(堆栈指针)并跳转到 main。最后一个 rjmp 有点多余。(你可以保证永远不会从 main 返回)
00000020 <__bad_interrupt>:
20: ef cf rjmp .-34 ; 0x0 <__vectors>
这些中断的默认中断过程比没有用 C 覆盖的。(与 __vectors 的规则相同)
00000022 <main>:
22: bb 9a sbi 0x17, 3 ; 23
24: c3 9a sbi 0x18, 3 ; 24
26: c3 98 cbi 0x18, 3 ; 24
28: fd cf rjmp .-6 ; 0x24 <main+0x2>
你的主要过程。紧的。
0000002a <_exit>:
2a: f8 94 cli
0000002c <__stop_program>:
2c: ff cf rjmp .-2 ; 0x2c <__stop_program>
这两个不是很有用。C 标准可能需要 _exit 并且需要 __stop_program 才能正常工作。
你最终的应用是什么?ATtiny13 有 1kB 的闪存,你可以用 C 做很多事情。crt0 是 avr-libc C 运行时。它包含诸如堆栈处理之类的东西,因此您可以使用带有参数和返回值的函数。
嵌入式 C 设置的 100 字节还不错,而且它的大小是恒定的。将程序逻辑的行数加倍不一定会变成 200 字节。您在什么优化级别进行编译?你应该在“-Os”。你是如何编译这个的?avr-libc 站点提供的演示项目中的 Makefile 非常好且全面。
下面的简单 LED 开/关程序在 avr-gcc 4.3.3 上带有“-Os”的 ATtiny13 上占用 62 个字节。来自 CrossPack-AVR:
#include <avr/io.h> #include <avr/delay.h> 诠释主要(无效) { DDRB |= _BV( PB3 ); 而(1){ PORTB |= _BV( PB3 ); _delay_ms(200); PORTB &=~ _BV( PB3 ); _delay_ms(200); } }
删除 _delay_ms() 调用使其变为 46 个字节。
ATtiny13 上一个更大的例子是我的智能 LED 原型。此代码包含 3 通道软件 PWM、HSV 到 RGB 颜色转换、状态机和读取两个按钮。它写得不是特别好,只有 864 字节。在 avr-gcc 3.x 下它甚至更小。(出于某种原因,avr-gcc 4 使几乎所有程序都增长了几个字节)
crt0 是 uC 的启动例程。这些例程执行寄存器的设置以及数据的初始化。
100 字节是否包含中断向量表?我不确定 ATtiny13 但 ATtiny25/45/85 有 15 个中断向量。这将占用 30 个字节。
gcc 有一个选项来链接你的 crt0。您可以获取 AVR crt0.S 文件并对其进行修改。它不是很长,所以应该不难做到。
如果您空间不足,请尝试 IAR 的嵌入式工作台——他们的免费“kickstart”版本有 4K 字代码大小限制,对于 ATTiny 来说已经足够了,并且可能比 gcc 更好的优化