mars4zhu 发表于 2022-4-10 21:08

【平头哥Sipeed LicheeRV 86 Panel测评】D1作为单片机裸奔编程点灯——LED-Blinky

<p>网上有大牛开发了D1的baremetal裸金属编程,此时D1是一个名副其实的单片机。开源项目在此:https://github.com/bigmagic123/d1-nezha-baremeta</p>

<p>借鉴如此,也学习一下D1内部各个组件的寄存器编程。先从点灯开始&mdash;&mdash;LED-Blinky</p>

<p>&nbsp;</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>&nbsp;</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 &amp;= 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 &gt;0; y--)
                        __asm__("nop");

                if(x &gt; 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 $&lt; $@

${PROJECT}.elf:        ${PROJECT}.o
        ${CROSS_COMPILE}-ld -T ${PROJECT}.ld-o $@ $&lt;

${PROJECT}.o:        ${PROJECT}.c
        ${CROSS_COMPILE}-gcc ${CFLAGS}-c -o $@ $&lt;

clean:
        rm *.o *.elf *.bin

</code></pre>

<p>&nbsp;</p>

<p>需要注意的是,链接文件中,指定了0x00020000为起始地址,即D1芯片内部SRAM的地址,之后测试发现,当使用gcc的PIC(位置无关代码)标志后,不管将代码放置到何处,都能正确执行。</p>

<p>&nbsp;</p>

<p>代码以及.ld, Makefile写好后,make 即可完成编译、连接,并且将elf转为bin文件,(需要确保riscv64-unknown-linux-gnu-gcc位于PATH中)</p>

<p>&nbsp;</p>

<p>之后使用xfel将生成的bin文件下载到D1芯片的SRAM中,如图;</p>

<p></p>

<p>此时核心板上的LED正常闪烁。</p>

<p>&nbsp;</p>

nmg 发表于 2022-4-11 10:25

<p>get一个新名词,裸金属,查了查,指的是没有操作系统的编程</p>

<p>城会玩啊,那是不是很多嵌入式开发,不基于操作系统的,都是裸金属啦</p>

<p>&nbsp;</p>

freebsder 发表于 2022-4-11 17:07

<p>pic应该是加载时用的,还是得有个基地址才行吧。</p>

我爱下载 发表于 2022-4-14 09:32

<p>这个玩法挺好</p>
页: [1]
查看完整版本: 【平头哥Sipeed LicheeRV 86 Panel测评】D1作为单片机裸奔编程点灯——LED-Blinky