D语言(Dlang)在单片机(cortex-m)上应用方法

本文介绍使用D语言编写单片机程序,目标芯片为STM32f401cc。阐述了D语言在单片机编程的优势,如类似C/C++设计、无需复杂交叉编译环境等。还说明了环境准备,给出具体实现方法,包括源代码、linker脚本、编译指令和连接仿真模拟等,最后提及可用vscode调试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用D语言(dlang.org)编写单片机程序.

实现目标

尝试使用Dlang语言编写单片机程序.目标芯片为 STM32f401cc. cortex-m4
HOST主机为windows 系统,

优势列举

D语言是一种无"语言宗教"的编程语言,类似于C/C++的设计,函数书写无顺序限制,无不可调试的鸿定义,没有复杂的头文件.

使用LDC编译器时无需构建复杂的交叉编译环境

在单片机上编程主要是应用D语言的一个子集 “Better C”,这个子集包括大部分D语言的实现,如下的功能未实现,:

序号功能注释
1内存GC单片机编程来说,这部分还是需要程序员考虑取舍
2结构信息TypeInfoModuleInfo,这部分主要应用是GC,还有就是一些共享库应用
3Class
4内置线程
5动态数组
6Exceptions
7内置同步函数
8静态构造和析构函数

当然也可以应用完整的D语言,但付出的成本较高(FLASH/RAM),一般来说单片机开发的程序运行态都是可以推定的,从效率来说不推荐使用GC管理或动态加载

linux的嵌入式开发不在这份文章里讨论了.

环境准备

首先我们确定一下我们需要哪些东西:

序号功能当前可用
1IDE推荐Vscode,外加 dlang所用的 webfreak.dlang-bundle插件 和 marus25.cortex-debug 调试插件
2编译器LDC,通过LLVM实现,在无需RT库的情况下可以直接下载二进制版本,
2.1连接器lld,推荐直接使用LDC内置
2.2杂项工具LLVM,包括不少工具用不惯的上套arm-none-eabi的也行啊~
3构建工具这个暂时没有,写个批处理搞定吧 😀
4调试器GDB吧,理论上支持gdb协议都可以,暂时没发现更好的方案
5仿真模拟qemu-arm,这模拟器可以仿真stm32多个系列,硬件浮点部分有问题,仿真时会出错

具体实现方法

源代码

module start;
 /*
 	filename : start.d
 */
version(LDC)
{
  import ldc.llvmasm;
}

alias void function() ISR;
extern(C) immutable ISR ResetHandler = &OnReset;

void SendCommand(int command, void* message)
{
    __asm
    (
      "mov r0, $0;
      mov r1, $1;
      bkpt #0xAB",
      "r,r,~{r0},~{r1}",
      command, message
    );
}
 
void OnReset()
{
  while(true)
  {
    // Create semihosting message
    uint[3] message =
      [
	2, 			      //stderr
	cast(uint)"hello\r\n".ptr,    //ptr to string
	7                             //size of string
      ];

    //Send semihosting command
    SendCommand(0x05, &message);
  }
}

说一下代码中的一些限制,这些限制主要是来源于TLS的实现,ldc自带的库中未实现这部分的函数造成.
D语言函数声明与C之间的关系
D语言函数声明与C++之间的关系

D定义SECTIONS region
__gshared int t.bss
__gshared int t=0x33.data
shared int t.data
shared int t=0x33.data
shared int t.bss
static int t.bss
static int t=0x33.data
int t.tbss
int t=0x33.tdata

这里遇到的麻烦主要是来至于TLS部分,这部分缺少实现函数以及LLVM的LLD部分的BUG(使用TLS后输出的binary 文件非常巨大),建议不要使用ABI的TLS,转而使用 emulated-tls

不过在"裸奔"的单片机上TLS什么的完全不需要,上嵌入式系统的话建议实现 emulated-tls方式

linker脚本

/*
	filename:ldscript.ld
*/
MEMORY
{
	FLASH (RX) : ORIGIN = 0x08000000, LENGTH = 256K
	SRAM (WXAR) : ORIGIN = 0x20000000, LENGTH = 64K
}

_stackStart = ORIGIN(CCRAM) + LENGTH(CCRAM);

SECTIONS
{  
  /* We don't need exceptions, and discarding these sections
     prevents linker errors with LDC */
  /DISCARD/ :
  {
    *(.ARM.extab*)
    *(.ARM.exidx*)
  }

  .text :       
  {
    LONG(_stackStart);              /* Initial stack pointer */
    KEEP(start.o(*.ResetHandler))   /* Interrupt vector table (Entry point) */
    
    /* the code */
    *(.text)      
    *(.text*)  
    
    /* for "hello\r\n" string constant */
    . = ALIGN(4);
    *(.rodata)
    *(.rodata*)
    
  }>FLASH
  
  
  /* Need .data, .bss, .ctors and probably more as program becomes
     More complex */
}

这个连接脚本并未实现内存部分操作的 SECTIONS,仅仅作为这次的演示!!!
之后我会出一个注释说明的linker 脚本

编译指令

第一次心动时刻来了,
ldc2 --conf= --mtriple=thumb-none-eabi --mcpu=cortex-m4 --exception-model=sjlj --defaultlib= --platformlib= --betterC --nogc --static --link-internally -L=-Tldscript.ld -L=-nostdlib -L=--oformat -L=binary start.d --of start.bin

指令功能
--conf=禁止默认配置文件
--mtriple=thumb-none-eabi指定目标框架
--mcpu=cortex-m4指定cpu系列
--exception-model=sjlj指定exception处理方式
--defaultlib=清空默认加载库
--platformlib=清空默认框架库
--betterC使用betterC子集
--static静态
--link-internally使用内置LLD
-L=-Tldscript.ld使用的linker脚本
-L=-nostdlib传递给LLD的参数,禁止默认库
-L=--oformat -L=binary传递给LLD参数,设置输出格式,参阅LLD的oformat
start.d目标文件,说明一下LDC支持通配符和文件列表 @<文件列表>
--of start.bin指定输出文件

不出意外应该会得到一个 start.bin

连接仿真模拟

在仿真器内运行:
qemu-system-gnuarmeclipse -mcu STM32F405RG -no-reboot -nographic --image start.bin

如果打算通过GDB一类的调试启动命令应修改为
qemu-system-gnuarmeclipse -mcu STM32F405RG -no-reboot -nographic -s -S --image start.bin
-s,gdb端口监听在 127.0.0.1:1234
-S启动时等待gdb调试

gdb连接:
arm-none-eabi-gdb.exe start.bin
(gdb) target remote 127.0.0.1:1234
...
<其余的查阅相关gdb手册>

想得到更多调试信息,ldc编译参数加上--gc 输出格式采用elf,可以得到更多调试信息

其余说明

可以使用vscode的调试功能来调试,之后会写一个说明文档.

文档建立日期 : 2021年1月11日,01点23分

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值