【平头哥Sipeed LicheeRV 86 Panel测评】D1作为单片机裸奔编程点灯——LED-Blinky
<p>网上有大牛开发了D1的baremetal裸金属编程,此时D1是一个名副其实的单片机。开源项目在此:https://github.com/bigmagic123/d1-nezha-baremeta</p><p>借鉴如此,也学习一下D1内部各个组件的寄存器编程。先从点灯开始——LED-Blinky</p>
<p> </p>
<hr />
<p>暂时没有搭建JTAG调试环境,只能采取编译-下载-运行,通过运行效果来确定是否正常工作。下载是采用xfel工具:https://github.com/xboot/xfel/,下载windows版本即可。</p>
<p>需要取下SD卡,或者上电的时候按住核心板上的FEL按钮。才能进入FEL下载模式。</p>
<p>进入FEL模式后,电脑检测到USB设备,通过Zadig安装USB通用驱动,然后才能使用xfel检测是否连接正确并且进入了FEL模式:</p>
<p>xfel version<br />
AWUSBFEX ID=0x00185900(D1/F133) dflag=0x44 dlength=0x08 scratchpad=0x00045000</p>
<p>xfel sid<br />
d20011005c00481448000505093f760b</p>
<p> </p>
<hr />
<p>前提确定已经安装好了riscv64工具链,可以采用elf,也可以采用linux-gnu工具链。(本人是在WSL环境下安装,跟虚拟机或者Linux主机应该都一样)</p>
<p>通过查看D1-H_User Mannual.pdf,找到GPIO的文档,然后对照开发板原理图,可以发现,Lichee RV 86Panel的LED是连接在PC1上(86Panel底板的BT_WAKE_AP信号也接在PC1上,但在裸机编程环境下,BT没有启用,可以忽略。不放心可以拔下来,单独运行核心板);</p>
<p></p>
<p>首先通过XFEL的读写命令,来测试操作读写GPIO的寄存器,看看是否能够闪烁LED:</p>
<p>首先读取PC的配置寄存器PC_CFG0(0x02000060),其中PC1应当从上电默认的Disable模式,修改为OUTPUT模式。</p>
<p><br />
// led-blinky: PC1 to output<br />
xfel hexdump 0x02000060 100<br />
xfel write32 0x02000060 0xFFFFFF1F<br />
// Toggle PC1<br />
xfel write32 0x02000070 0x00000002<br />
xfel write32 0x02000070 0x00000000</p>
<p></p>
<p>每次往PC_DAT寄存器的PC1对应的位置写入0/1,则LED相应的熄灭/点亮,因此LED-Blinky程序只需要按照相同的步骤,即可实现;</p>
<p>led-blinky.c</p>
<pre>
<code class="language-cpp">void delay(int);
static int k = 23;
int main(int argc, char argv) {
int GPIO_BASE_ADDR = 0x02000000;
int PC_CFG0 = 0x0060;
int PC_DAT = 0x0070;
unsigned int *PC_CFG0_Addr = (unsigned int *)(GPIO_BASE_ADDR + PC_CFG0);
unsigned int *PC_DAT_Addr= (unsigned int *)(GPIO_BASE_ADDR + PC_DAT);
unsigned int PC_CFG0_Value = *PC_CFG0_Addr;
PC_CFG0_Value &= 0xFFFFFF0F;
PC_CFG0_Value |= 0x00000010;
*PC_CFG0_Addr = PC_CFG0_Value;
while(1) {
delay(1000);
*PC_DAT_Addr ^= 0x00000002;
}
k++;
return k;
}
void delay(int count)
{
volatile int x = count;
while(1) {
volatile int y = 2000;
for(; y >0; y--)
__asm__("nop");
if(x > 0) x--;
else break;
}
return ;
}
</code></pre>
<p>led-blinky.ld</p>
<pre>
<code>OUTPUT_ARCH( "riscv" )
OUTPUT_FORMAT("elf64-littleriscv")
ENTRY( main )
SECTIONS
{
/* text: test code section */
. = 0x00020000;
.text : { *(.text) }
/* data: Initialized data segment */
.gnu_build_id : { *(.note.gnu.build-id) }
.data : { *(.data) }
.rodata : { *(.rodata) }
.sdata : { *(.sdata) }
.debug : { *(.debug) }
. += 0x8000;
stack_top = .;
/* End of uninitalized data segement */
_end = .;
}
</code></pre>
<p>Makefile</p>
<pre>
<code class="language-makefile">
PROJECT ?= led-blinky
CROSS_COMPILE ?= riscv64-unknown-linux-gnu
CFLAGS += -fPIC
.PHONY: ${PROJECT}.bin
${PROJECT}.bin: ${PROJECT}.elf
${CROSS_COMPILE}-objcopy -O binary $< $@
${PROJECT}.elf: ${PROJECT}.o
${CROSS_COMPILE}-ld -T ${PROJECT}.ld-o $@ $<
${PROJECT}.o: ${PROJECT}.c
${CROSS_COMPILE}-gcc ${CFLAGS}-c -o $@ $<
clean:
rm *.o *.elf *.bin
</code></pre>
<p> </p>
<p>需要注意的是,链接文件中,指定了0x00020000为起始地址,即D1芯片内部SRAM的地址,之后测试发现,当使用gcc的PIC(位置无关代码)标志后,不管将代码放置到何处,都能正确执行。</p>
<p> </p>
<p>代码以及.ld, Makefile写好后,make 即可完成编译、连接,并且将elf转为bin文件,(需要确保riscv64-unknown-linux-gnu-gcc位于PATH中)</p>
<p> </p>
<p>之后使用xfel将生成的bin文件下载到D1芯片的SRAM中,如图;</p>
<p></p>
<p>此时核心板上的LED正常闪烁。</p>
<p> </p>
<p>get一个新名词,裸金属,查了查,指的是没有操作系统的编程</p>
<p>城会玩啊,那是不是很多嵌入式开发,不基于操作系统的,都是裸金属啦</p>
<p> </p>
<p>pic应该是加载时用的,还是得有个基地址才行吧。</p>
<p>这个玩法挺好</p>
页:
[1]