基于NANO 9K 开发板加载PICORV32软核,并建立交叉编译环境

news2024/11/20 12:36:39

目录

0. 环境准备

1. 安装交叉编译器 

2. 理解makefile工作机理

3. 熟悉示例程序的代码结构,理解软核代码的底层驱动原理

4. 熟悉烧录环节的工作机理, 建立下载环境 

5. 编写例子blink, printf等, 加载运行

6. 后续任务

 


0. 环境准备

NANO 9K低成本体验FPGA开发,还是挺香的,官方例子有加载PICORV32软核的例子,可以建立简单的ISP编程环境,通过串口就可以加载程序,很方便。 

Tang Nano 9K picoRV 简单示例 - Sipeed Wiki

运行效果 

可以通过命令行进行点灯喝运行benchmark等操作。 

相当于例子包括了: 

  • 串口打印,
  • 串口接收指令
  • GPIO控制

等基本操作。 

如果要基于RISCV软核,进一步熟悉工作机制和编程环境,需要参考例子建立交叉编译环境。 

step by step.......,以下基于虚拟机运行ubuntu18.04环境,少一点干扰。 

为帮助理解, 可以看看高云的官方文档对于picorv32内核架构的介绍: 

1. 安装交叉编译器 

 在虚拟机环境下,解压toolchain到目标目录即可。编译器路径可以在makefile文件里进行指定。 

当然,虚拟机依赖环境至少需要安装make工具,gcc也一起

sudo apt-get install make gcc 

下载地址: 

riscv32交叉编译器,ubuntu18.04亲测可用资源-CSDN文库

2. 理解makefile工作机理

参考文章: 

 从零开始:一步步教你如何写Makefile_makefile菜鸟教程-CSDN博客

makefile组成三要素:目标,依赖, 命令 

picotiny工作示例里有两层makefile, 先看主目录下的: 

PYTHON_NAME ?= python
RISCV_NAME 	?= riscv-none-embed
RISCV_PATH 	?= /home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004
MAKE		?= make

FW_FILE 	 = fw/fw-flash/build/fw-flash.v

PROG_FILE	?= $(FW_FILE)
COMx	 	?= COM14

export PYTHON_NAME
export RISCV_NAME
export RISCV_PATH


.PHONY: all brom flash clean program

all: brom flash

$(FW_FILE): flash

brom:
	$(MAKE) -C fw/fw-brom

flash:
	$(MAKE) -C fw/fw-flash

clean:
	$(MAKE) -C fw/fw-brom clean
	$(MAKE) -C fw/fw-flash clean

program: $(PROG_FILE)
	$(PYTHON_NAME) sw/pico-programmer.py $(PROG_FILE) $(COMx)

第一部分:指定环境变量

第二部分:指定分支

第三部分:分支命令编写

这个根目录下的makefile主要功能:一是执行不同的子目录下 ,二是program命令分支。 

真正编译项目代码的makefile是在子目录下。 

再来看子目录下的makefile

PROJ_NAME=blink-flash
DEBUG=no
BENCH=no
MULDIV=no
COMPRESSED=no

SRCS = 	$(wildcard *.c)       		\
		$(wildcard *.S)

LDSCRIPT = ./linker_flash.ld

RISCV_NAME ?= riscv-none-embed
RISCV_PATH ?= /home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004

MABI=ilp32
MARCH := rv32i
ifeq ($(MULDIV),yes)
	MARCH := $(MARCH)m
endif
ifeq ($(COMPRESSED),yes)
	MARCH := $(MARCH)ac
endif

CFLAGS += -march=$(MARCH)  -mabi=$(MABI)  -ffunction-sections -fdata-sections
LDFLAGS += -march=$(MARCH)  -mabi=$(MABI)  -Wl,--gc-sections

ifeq ($(DEBUG),yes)
	CFLAGS += -g3 -O0 
endif

ifeq ($(DEBUG),no)
	CFLAGS += -g -O3 
endif

ifeq ($(BENCH),yes)
	CFLAGS += -fno-inline  
endif

RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/$(MARCH)/$(MABI)/

RISCV_OBJCOPY = $(RISCV_PATH)/bin/$(RISCV_NAME)-objcopy
RISCV_OBJDUMP = $(RISCV_PATH)/bin/$(RISCV_NAME)-objdump
RISCV_CC = $(RISCV_PATH)/bin/$(RISCV_NAME)-gcc

CFLAGS +=  -MD -fstrict-volatile-bitfields 
LDFLAGS +=  -nostdlib -lgcc -mcmodel=medany -nostartfiles -ffreestanding -Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map,--print-memory-usage

OBJDIR = build
OBJS := $(SRCS)
OBJS := $(OBJS:.c=.o)
OBJS := $(OBJS:.cpp=.o)
OBJS := $(OBJS:.S=.o)
OBJS := $(addprefix $(OBJDIR)/,$(OBJS))

SUBOBJ := $(addprefix $(OBJDIR)/,$(SUBDIRS))
SUBOBJ := $(addsuffix /*.o,$(SUBOBJ))

export RISCV_CC CFLAGS LDFLAGS OBJDIR

all: $(SUBDIRS) $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).v

$(SUBDIRS): ECHO
	make -C $@

ECHO:
	@echo $(SUBDIRS)

$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR)
	$(RISCV_CC) $(CFLAGS) -o $@ $^ $(SUBOBJ) $(LDFLAGS) $(LIBS)

%.hex: %.elf
	$(RISCV_OBJCOPY) -O ihex $^ $@

%.bin: %.elf
	$(RISCV_OBJCOPY) -O binary $^ $@
	
%.v: %.elf
	$(RISCV_OBJCOPY) -O verilog $^ $@

%.asm: %.elf
	$(RISCV_OBJDUMP) -S -d $^ > $@

$(OBJDIR)/%.o: %.c
	mkdir -p $(dir $@)
	$(RISCV_CC) -c $(CFLAGS)  $(INC) -o $@ $^
	
$(OBJDIR)/%.o: %.cpp
	mkdir -p $(dir $@)
	$(RISCV_CC) -c $(CFLAGS)  $(INC) -o $@ $^	

$(OBJDIR)/%.o: %.S
	mkdir -p $(dir $@)
	$(RISCV_CC) -c $(CFLAGS) -o $@ $^ -D__ASSEMBLY__=1

$(OBJDIR):
	mkdir -p $@

clean:
	rm -f $(OBJDIR)/$(PROJ_NAME).elf
	rm -f $(OBJDIR)/$(PROJ_NAME).hex
	rm -f $(OBJDIR)/$(PROJ_NAME).map
	rm -f $(OBJDIR)/$(PROJ_NAME).v
	rm -f $(OBJDIR)/$(PROJ_NAME).asm
	find $(OBJDIR) -type f -name '*.d' -print0 | xargs -0 -r rm
	find $(OBJDIR) -type f -name '*.o' -print0 | xargs -0 -r rm

.SECONDARY: $(OBJS)


			

主要完成的工作: 指定了环境变量,编译输出目标文件,编译后的处理(文件转换等) 。 

编写完示例代码后,可以在子目录下运行make命令,执行响应的makefile即可完成目标代码编译。 

3. 熟悉示例程序的代码结构,理解软核代码的底层驱动原理

4. 熟悉烧录环节的工作机理, 建立下载环境 

 烧录的riscv软核支持ISP(串口在线烧录)功能。 所以make program xxx命令调用的python脚本主要是握手协议和烧录固件的传输。 

简单理解: 软核的ISP功能完成了flash固件的调用启动和程序引导运行工作。 

小知识: 理解ISP

ISP的全称是:In System Programming,即在系统编程,该操作是通过MCU厂商出厂BootLoader来实现,通过ISP可以对主flash区域进行擦除、编程操作,还可以修改芯片的选项字节等。

ISP的实现逻辑是出厂“芯片”(我们这里是软核)自带了BootLoader程序,即出厂引导程序,通过BootLoader可以将程序从串口(上位机)下载到Flash中,实际的时序是通过RST来区分正常启动还是烧录状态,然后上位机的烧录脚本来控制串口时序, 用户程序实际上是通过串口最终下载到了FLASH中,然后程序从flash启动。

5. 编写例子blink, printf等, 加载运行

 1)点灯--blink

blink主要是调用GPIO寄存器写入功能

#include <stdint.h>
#include <stdbool.h>

// a pointer to this is a null pointer, but the compiler does not
// know that because "sram" is a linker symbol from sections.lds.
extern uint32_t sram;

typedef struct {
    volatile uint32_t OUT;
    volatile uint32_t IN;
    volatile uint32_t OE;
} PICOGPIO;

// 寄存器地址
#define GPIO0 ((PICOGPIO*)0x82000000)


#define FLASHIO_ENTRY_ADDR ((void *)0x80000054)


volatile int i;
// --------------------------------------------------------


void main()
{
    GPIO0->OE = 0x3F;
    GPIO0->OUT = 0x3F;


   while (1)
    {
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F ^ 0x01;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F ^ 0x02;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F ^ 0x04;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F ^ 0x08;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F ^ 0x10;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F ^ 0x20;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x00;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F;
    for ( i = 0 ; i < 10000; i++);

    }
       
}

void irqCallback() {

}

 makefile,其实之修改了PROJ_NAME

PROJ_NAME=blink-demo
DEBUG=no
BENCH=no
MULDIV=no
COMPRESSED=no

SRCS = 	$(wildcard *.c)       		\
		$(wildcard *.S)

LDSCRIPT = ./linker_flash.ld

RISCV_NAME ?= riscv-none-embed
RISCV_PATH ?= /home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004

MABI=ilp32
MARCH := rv32i
ifeq ($(MULDIV),yes)
	MARCH := $(MARCH)m
endif
ifeq ($(COMPRESSED),yes)
	MARCH := $(MARCH)ac
endif

CFLAGS += -march=$(MARCH)  -mabi=$(MABI)  -ffunction-sections -fdata-sections
LDFLAGS += -march=$(MARCH)  -mabi=$(MABI)  -Wl,--gc-sections

ifeq ($(DEBUG),yes)
	CFLAGS += -g3 -O0 
endif

ifeq ($(DEBUG),no)
	CFLAGS += -g -O3 
endif

ifeq ($(BENCH),yes)
	CFLAGS += -fno-inline  
endif

RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/$(MARCH)/$(MABI)/

RISCV_OBJCOPY = $(RISCV_PATH)/bin/$(RISCV_NAME)-objcopy
RISCV_OBJDUMP = $(RISCV_PATH)/bin/$(RISCV_NAME)-objdump
RISCV_CC = $(RISCV_PATH)/bin/$(RISCV_NAME)-gcc

CFLAGS +=  -MD -fstrict-volatile-bitfields 
LDFLAGS +=  -nostdlib -lgcc -mcmodel=medany -nostartfiles -ffreestanding -Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map,--print-memory-usage

OBJDIR = build
OBJS := $(SRCS)
OBJS := $(OBJS:.c=.o)
OBJS := $(OBJS:.cpp=.o)
OBJS := $(OBJS:.S=.o)
OBJS := $(addprefix $(OBJDIR)/,$(OBJS))

SUBOBJ := $(addprefix $(OBJDIR)/,$(SUBDIRS))
SUBOBJ := $(addsuffix /*.o,$(SUBOBJ))

export RISCV_CC CFLAGS LDFLAGS OBJDIR

all: $(SUBDIRS) $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).v

$(SUBDIRS): ECHO
	make -C $@

ECHO:
	@echo $(SUBDIRS)

$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR)
	$(RISCV_CC) $(CFLAGS) -o $@ $^ $(SUBOBJ) $(LDFLAGS) $(LIBS)

%.hex: %.elf
	$(RISCV_OBJCOPY) -O ihex $^ $@

%.bin: %.elf
	$(RISCV_OBJCOPY) -O binary $^ $@
	
%.v: %.elf
	$(RISCV_OBJCOPY) -O verilog $^ $@

%.asm: %.elf
	$(RISCV_OBJDUMP) -S -d $^ > $@

$(OBJDIR)/%.o: %.c
	mkdir -p $(dir $@)
	$(RISCV_CC) -c $(CFLAGS)  $(INC) -o $@ $^
	
$(OBJDIR)/%.o: %.cpp
	mkdir -p $(dir $@)
	$(RISCV_CC) -c $(CFLAGS)  $(INC) -o $@ $^	

$(OBJDIR)/%.o: %.S
	mkdir -p $(dir $@)
	$(RISCV_CC) -c $(CFLAGS) -o $@ $^ -D__ASSEMBLY__=1

$(OBJDIR):
	mkdir -p $@

clean:
	rm -f $(OBJDIR)/$(PROJ_NAME).elf
	rm -f $(OBJDIR)/$(PROJ_NAME).hex
	rm -f $(OBJDIR)/$(PROJ_NAME).map
	rm -f $(OBJDIR)/$(PROJ_NAME).v
	rm -f $(OBJDIR)/$(PROJ_NAME).asm
	find $(OBJDIR) -type f -name '*.d' -print0 | xargs -0 -r rm
	find $(OBJDIR) -type f -name '*.o' -print0 | xargs -0 -r rm

.SECONDARY: $(OBJS)


			

项目目录下编译: 

/blink-demo$ make
mkdir -p build/
/home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004/bin/riscv-none-embed-gcc -c -march=rv32i  -mabi=ilp32  -ffunction-sections -fdata-sections -g -O3  -MD -fstrict-volatile-bitfields    -o build/main.o main.c
/home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004/bin/riscv-none-embed-gcc -march=rv32i  -mabi=ilp32  -ffunction-sections -fdata-sections -g -O3  -MD -fstrict-volatile-bitfields  -o build/blink-demo.elf build/main.o build/crt_flash.o  -march=rv32i  -mabi=ilp32  -Wl,--gc-sections -nostdlib -lgcc -mcmodel=medany -nostartfiles -ffreestanding -Wl,-Bstatic,-T,./linker_flash.ld,-Map,build/blink-demo.map,--print-memory-usage 
Memory region         Used Size  Region Size  %age Used
           FLASH:         728 B         8 MB      0.01%
             RAM:        1040 B         8 KB     12.70%
/home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004/bin/riscv-none-embed-objcopy -O ihex build/blink-demo.elf build/blink-demo.hex
/home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004/bin/riscv-none-embed-objdump -S -d build/blink-demo.elf > build/blink-demo.asm
/home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004/bin/riscv-none-embed-objcopy -O verilog build/blink-demo.elf build/blink-demo.v

生成的.v文件即用于执行的文件。 

执行根目录下的make program来烧录

 烧录成功: 

...../picotiny$ make programBlink
python sw/pico-programmer.py fw/blink-demo/build/blink-demo.v /dev/ttyUSB1
Read program with 736 bytes
  - Waiting for reset -
    ...
Total sectors 1
Total pages 3
Flashing 1 / 1

Flashing completed

 RISCV例程执行--blink-CSDN直播

 

 2)单独编写串口交互: 

main.c: 



#include <stdint.h>
#include <stdbool.h>

// a pointer to this is a null pointer, but the compiler does not
// know that because "sram" is a linker symbol from sections.lds.
extern uint32_t sram;

typedef struct {
    volatile uint32_t DATA;
    volatile uint32_t CLKDIV;
} PICOUART;

typedef struct {
    volatile uint32_t OUT;
    volatile uint32_t IN;
    volatile uint32_t OE;
} PICOGPIO;

typedef struct {
    union {
        volatile uint32_t REG;
        volatile uint16_t IOW;
        struct {
            volatile uint8_t IO;
            volatile uint8_t OE;
            volatile uint8_t CFG;
            volatile uint8_t EN; 
        };
    };
} PICOQSPI;

#define QSPI0 ((PICOQSPI*)0x81000000)
#define GPIO0 ((PICOGPIO*)0x82000000)
#define UART0 ((PICOUART*)0x83000000)

#define FLASHIO_ENTRY_ADDR ((void *)0x80000054)

void (*spi_flashio)(uint8_t *pdata, int length, int wren) = FLASHIO_ENTRY_ADDR;

int putchar(int c)
{	
    if (c == '\n')
        UART0->DATA = '\r';
    UART0->DATA = c;
    
    return c;
}

void print(const char *p)
{
    while (*p)
        putchar(*(p++));
}

void print_hex(uint32_t v, int digits)
{
    for (int i = 7; i >= 0; i--) {
        char c = "0123456789abcdef"[(v >> (4*i)) & 15];
        if (c == '0' && i >= digits) continue;
        putchar(c);
        digits = i;
    }
}

void print_dec(uint32_t v)
{
    if (v >= 100) {
        print(">=100");
        return;
    }

    if      (v >= 90) { putchar('9'); v -= 90; }
    else if (v >= 80) { putchar('8'); v -= 80; }
    else if (v >= 70) { putchar('7'); v -= 70; }
    else if (v >= 60) { putchar('6'); v -= 60; }
    else if (v >= 50) { putchar('5'); v -= 50; }
    else if (v >= 40) { putchar('4'); v -= 40; }
    else if (v >= 30) { putchar('3'); v -= 30; }
    else if (v >= 20) { putchar('2'); v -= 20; }
    else if (v >= 10) { putchar('1'); v -= 10; }

    if      (v >= 9) { putchar('9'); v -= 9; }
    else if (v >= 8) { putchar('8'); v -= 8; }
    else if (v >= 7) { putchar('7'); v -= 7; }
    else if (v >= 6) { putchar('6'); v -= 6; }
    else if (v >= 5) { putchar('5'); v -= 5; }
    else if (v >= 4) { putchar('4'); v -= 4; }
    else if (v >= 3) { putchar('3'); v -= 3; }
    else if (v >= 2) { putchar('2'); v -= 2; }
    else if (v >= 1) { putchar('1'); v -= 1; }
    else putchar('0');
}

char getchar_prompt(char *prompt)
{
    int32_t c = -1;

    uint32_t cycles_begin, cycles_now, cycles;
    __asm__ volatile ("rdcycle %0" : "=r"(cycles_begin));

    if (prompt)
        print(prompt);

    // if (prompt)
        // GPIO0->OUT = ~0;
        // reg_leds = ~0;

    while (c == -1) {
        __asm__ volatile ("rdcycle %0" : "=r"(cycles_now));
        cycles = cycles_now - cycles_begin;
        if (cycles > 12000000) {
            if (prompt)
                print(prompt);
            cycles_begin = cycles_now;
            // if (prompt)
                // GPIO0->OUT = ~GPIO0->OUT;
                // reg_leds = ~reg_leds;
        }
        c = UART0->DATA;
    }
    // if (prompt)
        // GPIO0->OUT = 0;
        // reg_leds = 0;
    return c;
}

char getchar()
{
    return getchar_prompt(0);
}

#define QSPI_REG_CRM  0x00100000
#define QSPI_REG_DSPI 0x00400000

void cmd_set_crm(int on)
{
    if (on) {
        QSPI0->REG |= QSPI_REG_CRM;
    } else {
        QSPI0->REG &= ~QSPI_REG_CRM;
    }
}

int cmd_get_crm() {
    return QSPI0->REG & QSPI_REG_CRM;
}

volatile int i;
// --------------------------------------------------------

#define CLK_FREQ        25175000
#define UART_BAUD       115200

void main()
{
    UART0->CLKDIV = CLK_FREQ / UART_BAUD - 2;

    GPIO0->OE = 0x3F;
    GPIO0->OUT = 0x3F;

    cmd_set_crm(1);


    print("\n");
    print("  ____  _          ____         ____\n");
    print(" |  _ \\(_) ___ ___/ ___|  ___  / ___|\n");
    print(" | |_) | |/ __/ _ \\___ \\ / _ \\| |\n");
    print(" |  __/| | (_| (_) |__) | (_) | |___\n");
    print(" |_|   |_|\\___\\___/____/ \\___/ \\____|\n");
    print("\n");
    print("        On Lichee Tang Nano-9K\n");
    print("\n");

    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F ^ 0x01;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F ^ 0x02;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F ^ 0x04;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F ^ 0x08;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F ^ 0x10;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F ^ 0x20;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x00;
    for ( i = 0 ; i < 10000; i++);
    GPIO0->OUT = 0x3F;
    for ( i = 0 ; i < 10000; i++);

    while (1)
    {
        print("\n");
        print("Select an action:\n");
        print("\n");
        print("   [1] Toggle led 1\n");
        print("   [2] Toggle led 2\n");
        print("   [3] Toggle led 3\n");
        print("   [4] Toggle led 4\n");
        print("   [5] Toggle led 5\n");
        print("   [6] Toggle led 6\n");
       
        
        for (int rep = 10; rep > 0; rep--)
        {
            print("\n");
            print("IO State: ");
            print_hex(GPIO0->IN, 8);
            print("\n");

            print("\n");

            print("Command> ");
            char cmd = getchar();
            if (cmd > 32 && cmd < 127)
                putchar(cmd);
            print("\n");

            switch (cmd)
            {
            

            case '1':
                GPIO0->OUT ^= 0x00000001;
                break;

            case '2':
                GPIO0->OUT ^= 0x00000002;
                break;

            case '3':
                GPIO0->OUT ^= 0x00000004;
                break;

            case '4':
                GPIO0->OUT ^= 0x00000008;
                break;

            case '5':
                GPIO0->OUT ^= 0x00000010;
                break;

            case '6':
                GPIO0->OUT ^= 0x00000020;
                break;

            default:
                continue;
            }
        }
    }
}

void irqCallback() {

}

makefile: 

PROJ_NAME=uart-demo
DEBUG=no
BENCH=no
MULDIV=no
COMPRESSED=no

SRCS = 	$(wildcard *.c)       		\
		$(wildcard *.S)

LDSCRIPT = ./linker_flash.ld

RISCV_NAME ?= riscv-none-embed
RISCV_PATH ?= /home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004

MABI=ilp32
MARCH := rv32i
ifeq ($(MULDIV),yes)
	MARCH := $(MARCH)m
endif
ifeq ($(COMPRESSED),yes)
	MARCH := $(MARCH)ac
endif

CFLAGS += -march=$(MARCH)  -mabi=$(MABI)  -ffunction-sections -fdata-sections
LDFLAGS += -march=$(MARCH)  -mabi=$(MABI)  -Wl,--gc-sections

ifeq ($(DEBUG),yes)
	CFLAGS += -g3 -O0 
endif

ifeq ($(DEBUG),no)
	CFLAGS += -g -O3 
endif

ifeq ($(BENCH),yes)
	CFLAGS += -fno-inline  
endif

RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/$(MARCH)/$(MABI)/

RISCV_OBJCOPY = $(RISCV_PATH)/bin/$(RISCV_NAME)-objcopy
RISCV_OBJDUMP = $(RISCV_PATH)/bin/$(RISCV_NAME)-objdump
RISCV_CC = $(RISCV_PATH)/bin/$(RISCV_NAME)-gcc

CFLAGS +=  -MD -fstrict-volatile-bitfields 
LDFLAGS +=  -nostdlib -lgcc -mcmodel=medany -nostartfiles -ffreestanding -Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map,--print-memory-usage

OBJDIR = build
OBJS := $(SRCS)
OBJS := $(OBJS:.c=.o)
OBJS := $(OBJS:.cpp=.o)
OBJS := $(OBJS:.S=.o)
OBJS := $(addprefix $(OBJDIR)/,$(OBJS))

SUBOBJ := $(addprefix $(OBJDIR)/,$(SUBDIRS))
SUBOBJ := $(addsuffix /*.o,$(SUBOBJ))

export RISCV_CC CFLAGS LDFLAGS OBJDIR

all: $(SUBDIRS) $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).v

$(SUBDIRS): ECHO
	make -C $@

ECHO:
	@echo $(SUBDIRS)

$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR)
	$(RISCV_CC) $(CFLAGS) -o $@ $^ $(SUBOBJ) $(LDFLAGS) $(LIBS)

%.hex: %.elf
	$(RISCV_OBJCOPY) -O ihex $^ $@

%.bin: %.elf
	$(RISCV_OBJCOPY) -O binary $^ $@
	
%.v: %.elf
	$(RISCV_OBJCOPY) -O verilog $^ $@

%.asm: %.elf
	$(RISCV_OBJDUMP) -S -d $^ > $@

$(OBJDIR)/%.o: %.c
	mkdir -p $(dir $@)
	$(RISCV_CC) -c $(CFLAGS)  $(INC) -o $@ $^
	
$(OBJDIR)/%.o: %.cpp
	mkdir -p $(dir $@)
	$(RISCV_CC) -c $(CFLAGS)  $(INC) -o $@ $^	

$(OBJDIR)/%.o: %.S
	mkdir -p $(dir $@)
	$(RISCV_CC) -c $(CFLAGS) -o $@ $^ -D__ASSEMBLY__=1

$(OBJDIR):
	mkdir -p $@

clean:
	rm -f $(OBJDIR)/$(PROJ_NAME).elf
	rm -f $(OBJDIR)/$(PROJ_NAME).hex
	rm -f $(OBJDIR)/$(PROJ_NAME).map
	rm -f $(OBJDIR)/$(PROJ_NAME).v
	rm -f $(OBJDIR)/$(PROJ_NAME).asm
	find $(OBJDIR) -type f -name '*.d' -print0 | xargs -0 -r rm
	find $(OBJDIR) -type f -name '*.o' -print0 | xargs -0 -r rm

.SECONDARY: $(OBJS)


			

项目子目录下编译结果,生成目标文件: 

/uart-demo$ make
mkdir -p build/
/home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004/bin/riscv-none-embed-gcc -c -march=rv32i  -mabi=ilp32  -ffunction-sections -fdata-sections -g -O3  -MD -fstrict-volatile-bitfields    -o build/main.o main.c
mkdir -p build/
/home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004/bin/riscv-none-embed-gcc -c -march=rv32i  -mabi=ilp32  -ffunction-sections -fdata-sections -g -O3  -MD -fstrict-volatile-bitfields  -o build/crt_flash.o crt_flash.S -D__ASSEMBLY__=1
/home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004/bin/riscv-none-embed-gcc -march=rv32i  -mabi=ilp32  -ffunction-sections -fdata-sections -g -O3  -MD -fstrict-volatile-bitfields  -o build/uart-demo.elf build/main.o build/crt_flash.o  -march=rv32i  -mabi=ilp32  -Wl,--gc-sections -nostdlib -lgcc -mcmodel=medany -nostartfiles -ffreestanding -Wl,-Bstatic,-T,./linker_flash.ld,-Map,build/uart-demo.map,--print-memory-usage 
Memory region         Used Size  Region Size  %age Used
           FLASH:        3152 B         8 MB      0.04%
             RAM:        1040 B         8 KB     12.70%
/home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004/bin/riscv-none-embed-objcopy -O ihex build/uart-demo.elf build/uart-demo.hex
/home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004/bin/riscv-none-embed-objdump -S -d build/uart-demo.elf > build/uart-demo.asm
/home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004/bin/riscv-none-embed-objcopy -O verilog build/uart-demo.elf build/uart-demo.v

根目录下烧录运行: 

makefile增加选项programUart: 


PYTHON_NAME ?= python
RISCV_NAME 	?= riscv-none-embed
RISCV_PATH 	?= /home/hy/riscv/gnu-mcu-eclipse/riscv-none-gcc/8.2.0-2.2-20190521-0004
MAKE		?= make

FW_FILE_BLINK 	 = fw/blink-demo/build/blink-demo.v
FW_FILE_UART	 = fw/uart-demo/build/uart-demo.v


PROG_FILE_BLINK	?= $(FW_FILE_BLINK)
PROG_FILE_UART	?= $(FW_FILE_UART)

COMx	 	?= /dev/ttyUSB1

export PYTHON_NAME
export RISCV_NAME
export RISCV_PATH


.PHONY: all brom flash clean program

all: brom flash

$(FW_FILE): flash

brom:
	$(MAKE) -C fw/fw-brom

flash:
	$(MAKE) -C fw/blink-demo

clean:
	$(MAKE) -C fw/fw-brom clean
	$(MAKE) -C fw/fw-flash clean


program: $(PROG_FILE)
	$(PYTHON_NAME) sw/pico-programmer.py $(PROG_FILE) $(COMx)

programBlink: $(PROG_FILE_BLINK)
	$(PYTHON_NAME) sw/pico-programmer.py $(PROG_FILE_BLINK) $(COMx)	

programUart: $(PROG_FILE_UART)
	$(PYTHON_NAME) sw/pico-programmer.py $(PROG_FILE_UART) $(COMx)		

运行烧录: 

/picotiny$ make programUart
python sw/pico-programmer.py fw/uart-demo/build/uart-demo.v /dev/ttyUSB1
Read program with 3152 bytes
  - Waiting for reset -
    ..
Total sectors 1
Total pages 13
Flashing 1 / 1

Flashing completed

调用cutecom运行页面: 

 

输入框输入1-6可以控制对应的LED亮灭。 

6. 后续任务

1)延申理解,通过官方开发包,编写更易于移植和开发的库

2)理解配合软核的SDK架构(理解指令集) 和HAL库的基本逻辑。 理解SDK应该按什么逻辑来规划

3)移植FREERTOS, 理解操作系统移植的基本逻辑

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1720321.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无线领夹麦克风哪个品牌音质最好?领夹麦克风品牌排行榜前十名

​短视频、直播已成为现代生活中不可或缺的一部分&#xff0c;而领夹式无线麦克风则是这些活动中不可或缺的重要工具。它们能够轻松捕捉声音&#xff0c;让内容更加生动、真实。然而&#xff0c;市场上的无线麦克风种类繁多&#xff0c;价格各异&#xff0c;如何挑选一款适合自…

红外超声波雷达测距(water)

文章目录 一 RS-232二 RS485三 Modbus四 stm32多路超声波测距4.1 设计方案4.2 代码 参考资料总结 实验要求 一. 采用stm32F103和HC-SR04超声波模块&#xff0c; 使用标准库或HAL库 定时器中断&#xff0c;完成1或2路的超声波障碍物测距功能。 1&#xff09;测试数据包含噪声&am…

环境变量 | 是不是必须配置?怎么配置?

本文基于mysql和python环境&#xff0c;简单介绍了“什么是环境变量”、“环境变量是不是必须配置”、“环境变量配置方法”及“常用环境变量 path ”。 1、什么是环境变量 释义&#xff1a;一般是指在操作系统中&#xff0c;用来指定操作系统运行环境的一些参数&#xff0c;…

C++ 多重继承的内存布局和指针偏移

在 C 程序里&#xff0c;在有多重继承的类里面。指向派生类对象的基类指针&#xff0c;其实是指向了派生类对象里面&#xff0c;该基类对象的起始位置&#xff0c;该位置相对于派生类对象可能有偏移。偏移的大小&#xff0c;等于派生类的继承顺序表里面&#xff0c;排在该类前面…

162.二叉树:填充每个节点的下一个右侧节点指针(力扣)

代码解决 /* // Definition for a Node. class Node { public:int val;Node* left;Node* right;Node* next;Node() : val(0), left(NULL), right(NULL), next(NULL) {}Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}Node(int _val, Node* _left, Node* _…

【linux】线程同步和生产消费者模型

线程同步 当我们多线程访问同一个临界资源时&#xff0c;会造成并发访问一个临界资源&#xff0c;使得临界资源数据不安全&#xff0c;我们引入了锁的概念&#xff0c;解决了临界资源访问不安全的情况&#xff0c;对于线程而言竞争锁的能力有强有弱&#xff0c;对于之前就抢到…

在CentOS7下构建TeamSpeak服务器并增加网易云点歌插件

文章目录 部署TeamSpeak创建一个新用户下载并解压服务端下载解压 启动服务端同意许可协议启动与配置开放端口设置开机自启 客户端连接 部署TS3AudioBot并添加网易云插件安装ffmpeg下载TS3AudioBot本体与插件并解压配置TS3AudioBot启动设置开机自启 部署网易云API安装git安装Nod…

【模型架构】学习RNN、LSTM、TextCNN和Transformer以及PyTorch代码实现

一、前言 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;模型架构的不断发展极大地推动了技术的进步。从早期的循环神经网络&#xff08;RNN&#xff09;到长短期记忆网络&#xff08;LSTM&#xff09;、Transformer再到当下火热的Mamba&#xff08;放在下一节&a…

Linux|虚拟机|Windows 11 家庭版的Hyper虚拟机服务开启

前言&#xff1a; Windows11的版本是比较多的&#xff0c;但有的时候笔记本预装的可能是家庭版&#xff0c;而家庭版的Windows通常是不支持虚拟机的&#xff0c;也就是说Hyper服务根本就看不到 Windows的程序和功能大体如下&#xff1a; &#x1f197;&#xff0c;那么如何开…

ChaosBlade混沌测试实践

ChaosBlade: 一个简单易用且功能强大的混沌实验实施工具 官方仓库&#xff1a;https://github.com/chaosblade-io/chaosblade 1. 项目介绍 ChaosBlade 是阿里巴巴开源的一款遵循混沌工程原理和混沌实验模型的实验注入工具&#xff0c;帮助企业提升分布式系统的容错能力&…

Nuxt3项目实现 OG:Image

目录 前言 1、安装 2、设置网站 URL 3、启用 Nuxt DevTools 4、创建您的第一个Og:Image a. 定义OG镜像 b. 查看您的Og:Image 5、自定义NuxtSeo模板 a. 定义 NuxtSeo模板 b. 使用其他可用的社区模板 6、创建自己的模板 a. 定义组件 BlogPost.vue b. 使用新模板 c.…

【爱空间_登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞 …

模型 FABE(特性 优势 好处 证据)法则

说明&#xff1a;系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。特性、优势、好处、证据&#xff0c;一气呵成。 1 FABE法则的应用 1.1 FABE法则营销商用跑步机 一家高端健身器材公司的销售代表正在向一家新开的健身房推销他们的商用跑步机。以下…

孩子用的灯什么样的好?安利几款适合孩子用的护眼台灯

随着学生们重返校园&#xff0c;家长和孩子们忙于新学期的准备工作&#xff0c;眼睛健康的考量自然也在其中。这也是为何近年来护眼台灯越来越受到欢迎的原因之一。作为一个长期近视并且日常用眼时间较长的人&#xff0c;我本人对护眼台灯有着长期的使用经历&#xff0c;并对它…

如何创建一个Angular项目(超简单)

1、安装Node.js&#xff08;官网Node.js下载&#xff09; 2、运行node -v和npm -v两条命令&#xff08;检验是否下载成功Node.js&#xff09; 3、npm i -g cnpm --registryhttps://registry.npmmirror.com&#xff08;用npm安装cnpm&#xff0c;将镜像源设置为国内镜像源&…

接入knife4j-openapi3访问/doc.html页面空白问题

大概率拦截器拦截下来了&#xff0c;我们F12看网络请求进行排查 都是 /webjars/ 路径下的资源被拦截了&#xff0c;只需在拦截器中添加该白名单即可"/webjars/**" 具体配置如下&#xff1a; Configuration public class WebConfig implements WebMvcConfigurer {priv…

云端数据提取:安全、高效地利用无限资源

在当今的大数据时代&#xff0c;企业和组织越来越依赖于云平台存储和处理海量数据。然而&#xff0c;随着数据的指数级增长&#xff0c;数据的安全性和高效的数据处理成为了企业最为关心的议题之一。本文将探讨云端数据安全的重要性&#xff0c;并提出一套既高效又安全的数据提…

图像加雾算法的研究与应用

目录 前言 一、图像加雾 1、基于传统方法的雾图合成 2、基于深度学习的雾图合成 3、基于Lightroom Classic实现软件加雾 4、基于深度图的方法实现加雾 二、开源的数据集 三、参考文章 前言 在去雾任务当中&#xff0c;训练和评估去雾算法需要大量的带有雾霾和无雾霾的…

超维小课堂 | 1、Pixhawk硬件平台和PX4固件以及QGC地面站之间的关联和区别

Pixhawk硬件平台和PX4固件以及QGC地面站之间的关联和区别 一、Pixhawk是无人机飞控的硬件平台。 主要集成了相关的单片机芯片和各种传感器的外围电路&#xff0c;因此&#xff0c;可以直观的认为Pixhawk一个由各种硬件模块整合成的硬件平台&#xff0c;类似于集成好的单片机开…

【Qt知识】Qt中的对象树是什么?

在深入Qt编程的世界时&#xff0c;你会频繁遇到一个核心概念——对象树&#xff08;Object Tree&#xff09;。这个概念是Qt框架管理内存、处理事件和组织用户界面元素的基础。 什么是Qt对象树&#xff1f; 如果你的Qt应用程序就像一片茂盛的森林&#xff0c;而这片森林中的每…