d你好Arduino
原文
ldc支持gdc风格汇编
avrd
d的avr
有两个
选项可链接ldc
发出的编译目标文件
:用avr-gcc
的链接器,或用llvm
的内部链接器.-gcc=avr-gcc
参数告诉在哪查找avr-gcc
工具,或可用使用llvm
的内置链接器的--link-internally
.两者都会起作用.
使用-gcc
相关的好处是可arduino studio
,因为它有objcopy,avrdude
等程序及其他有用的东西.让它正常工作,并更好地集成
与其他库和工具等一起使用,如gcc
提供的C运行时.
$ PATH=/opt/arduino/arduino-1.8.10/hardware/tools/avr/bin:$PATH ldc2 -betterC -Oz -mtriple=avr -mcpu=atmega328p -gcc=avr-gcc delay.d
$ file delay
delay: ELF 32-bit LSB executable, Atmel AVR 8-bit, version 1 (SYSV), statically linked, with debug_info, not stripped
$ ls -l delay
-rwxr-xr-x 1 me users 2440 Sep 18 08:28 delay
使用PATH
中的arduino
工具,-gcc=avr-gcc
参数就可工作.
使用--link-internally
,你不需要这些,但是:
$ ldc2 -betterC -Oz -mtriple=avr -mcpu=atmega328p --link-internally delay.d
lld: warning: cannot find entry symbol _start; defaulting to 0x110B4
$ file delay
delay: ELF 32-bit LSB executable, Atmel AVR 8-bit, version 1 (SYSV), statically linked, not stripped
$ ls -l delay
-rwxr-xr-x 1 me users 708 Sep 18 08:31 delay
注意它链接
了,但它给出了关于丢失_start
的警告.还要注意不同
的文件大小.这是因为gcc
提供的C运行时,提供了调用你的extern(C)main
来执行一些基本设置
的开始
符号.没有它,你需要自己
做更多的事情.我敢肯定,你也可在链接命令中列举lib/object
文件来让ldc
链接,但是使用-avr-gcc
,可正常工作,因为它已知道在哪
可找到所有这些东西
.
avr链接,有点过时.
可用标准的ldc2
安装,只需从ldc
网站获取二进制
.你不必自己编译它;正常下载中,avr
支持已有一段时间了.
得到ldc
后,先安装arduino
工具.我直接安装ArduinoStudio
.我把文件放在/opt/arduino/arduino-1.8.10/
中.你可能要调整
该路径.在那里,你会看到arduino
命令,硬件目录等.
me@arsd:/opt/arduino/arduino-1.8.10$ ls
arduino arduino-linux-setup.sh hardware java libraries revisions.txt tools-builder
arduino-builder examples install.sh lib reference tools uninstall.sh
写个测试:
import ldc.llvmasm;
// delay_basic.h中的移植
void _delay_loop_1(ubyte __count) {
//该模板参数是必需的,以避免
//`!Call.getType()->isVoidTy()&&"Badinlineasm!"'`断定失败.
__asm!ubyte (
"1: dec $0\n\tbrne 1b",
"=r,0", (__count)
);
}
void _delay_loop_2(ushort __count) {
__asm!ushort (`
1: sbiw $0,1
brne 1b
`,
`=w,0`,
__count);
}
// arduino 中 delay.h 的端口
enum F_CPU = 1000000UL;
// 这是`_delay_ms`,但我做错了,把`double`改成`int`,我还是不喜欢
void _delay(int __ms) {
ushort __ticks;
ulong __tmp = (F_CPU * __ms) / 4000;
if(__tmp < 1)
__ticks = 1;
else if(__tmp > 65535) {
__ticks = cast(ushort) (__ms * 10.0);
while(__ticks) {
_delay_loop_2(cast(ushort) (((F_CPU) / 4e3) / 10));
__ticks--;
}
return;
} else
__ticks = cast(ushort) __tmp;
_delay_loop_2(__ticks);
}
// 这是来自`WebFreak`在`Dwiki`上的示例代码
enum AVR_ARCH = 5; // MCU 的 AVR 架构
static if (AVR_ARCH >= 100) {
enum SFR_OFFSET = 0x00;
} else {
enum SFR_OFFSET = 0x20;
}
enum ubyte* MMIO_BYTE(ubyte memAddr) = cast(ubyte*) memAddr;
enum ubyte* SFR_IO8(ubyte ioAddr) = MMIO_BYTE!(ioAddr + SFR_OFFSET);
enum ubyte* PINB = SFR_IO8!(0x03);
enum ubyte* DDRB = SFR_IO8!(0x04);
enum ubyte* PORTB = SFR_IO8!(0x05);
extern(C) void main() {
import core.volatile;
volatileStore(DDRB, 0xFF);
//端口所有B设置为输出
// 我添加了延迟
while (true) {
volatileStore(PORTB, 0xFF);
//端口所有B设置为高
foreach(i; 0 .. 10)
_delay(1000);
volatileStore(PORTB, 0x00);
//端口所有B设置为低
foreach(i; 0 .. 20)
_delay(1000);
}
}
先,make
文件:
# Makefile
$ cat Makefile
all:
ldc2 delay.d -betterC -Oz -mtriple=avr -mcpu=atmega328p -Xcc=-mmcu=atmega328p -gcc=avr-gcc
avr-objcopy -O ihex -R .eeprom delay delay.hex
avrdude -F -V -c arduino -p ATMEGA328P -P /dev/ttyACM0 -b 115200 -U flash:w:delay.hex -C /opt/arduino/arduino-1.8.10/hardware/tools/avr/etc/avrdude.conf
请不要在最后一行
的路径,再次安装arduino
.
要运行它,请设置PATH
为你的arduino
安装,并运行make
,如下所示:
PATH=/opt/arduino/arduino-1.8.10/hardware/tools/avr/bin:$PATH make
这编译D代码
,然后把它复制
到arduino
硬件并开始
运行它.灯(及连接到引脚
上的其他东西)闪烁.
如果查看上面链接的wiki
页面,其中大部分
内容很熟悉.我随意复制/粘贴
.
需要注意的一些重要事项
:
1,不能用extern(C)
从arduinoC
的头文件中调用delay_ms
,因为它是按内联函数定义
的.库或目标文件中没有内联函数
;你必须移植
源.
源
WebFreak
在此移植了源码,我解释下.
gcc
和ldc
中的内联asm
略有不同.这是文件中的_delay_loop_1
:
void _delay_loop_1(uint8_t __count)
{
__asm__ volatile (
"1: dec %0" "\n\t"
"brne 1b"
: "=r" (__count)
: "0" (__count)
);
}
而,如下是D
文件中:
import ldc.llvmasm;
// delay_basic.h中的移植
void _delay_loop_1(ubyte __count) {
//该模板参数是必需的,以避免
//`!Call.getType()->isVoidTy()&&"Badinlineasm!"'`断定失败.
__asm!ubyte (
"1: dec $0\n\tbrne 1b",
"=r,0", (__count)
);
}
asm
不一样.在gcc
中,它使用__asm__
.在ldc
中,它使用ldc.llvmasm.__asm
.它们相似
但不同:
1,gcc
使用%0
作为占位符.ldc
使用了$0
.
2,gcc
使用冒号+神奇约束串
.ldc
使用函数的第二个
参数.所有约束都必须在ldc
用逗号分隔的串中.
3,gcc
似乎会自动
计算出大小.ldc
不会.不能指定
会触发编译器断定
失败.我并不知道类型
,但是让它
与输入
匹配似乎正确
.
构建和部署
过程都来自arduino
工具,所以除了设置路径
外,都与C一样.
我使用了-gcc
,--link-internally
要麻烦些.
我在这里使用了ldc
,因为它在下载
时开箱即用,无需自己构建
.
内联汇编
对这些控制器
的计时
有些重要,因此能够做到这一点很酷.