d1-nezha-baremeta
d1-nezha-baremeta copied to clipboard
A beginning of bare metal SDK?
About the source codes, I have tried to compile them and finally found that actually we do NOT need to include some header files like <stdio.h>
<stdlib.h>
on bare board.
Also we can spend a little time to get the code easier to organize and reuse.I would like contribute if you could point me a direction.
Thanks for your advice,If you are interested in contributing code, You can refer to the link below:
https://github.com/bigmagic123/d1-nezha-baremeta/tree/main/src/d1_barematel_sdk
I want to do some separate routines for peripheral experiments on the development board. If you need SDK, you can add the successfully tested peripherals to the SDK, and finally you can make some demos
Using meson for project construction can be compiled on both Linux and window, which is convenient for development.
Looking forward to your suggestion for bare metal SDK!
The ddr
was actually initialized after exec xfel ddr ddr2
, furthermore the clk
, gpio
and uart0
.
So if we do nothing about configuration, we can also use them like uart0
below.
file main.c
and link.ld
are shown below:
typedef unsigned long uint64_t;
typedef unsigned int uint32_t;
typedef uint64_t virtual_addr_t;
static inline void write32(virtual_addr_t addr, uint32_t value) {
*((volatile uint32_t *)(addr)) = value;
}
static inline uint32_t read32(virtual_addr_t addr) {
return *((volatile uint32_t *)(addr));
}
static inline uint64_t counter(void)
{
uint64_t cnt;
__asm__ __volatile__("csrr %0, time\n" : "=r"(cnt) :: "memory");
return cnt;
}
static inline void sdelay(unsigned long us)
{
uint64_t t = counter() + us * 24;
while(counter() <= t);
}
static void sys_uart_putc(char c)
{
virtual_addr_t addr = 0x02500000;
while((read32(addr + 0x7c) & (0x1 << 1)) == 0);
write32(addr, c);
}
void _start(void)
{
while(1){
sys_uart_putc('h');
sys_uart_putc('e');
sys_uart_putc('l');
sys_uart_putc('l');
sys_uart_putc('o');
sys_uart_putc('\r');
sys_uart_putc('\n');
sdelay(1000*1000);
}
}
OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(_start)
STACK_SIZE = 0x100000;
MEMORY
{
ram : org = 0x40000000, len = 64M
}
SECTIONS
{
.text :
{
PROVIDE(__image_start = .);
PROVIDE(__text_start = .);
main.o (.text*)
*(.text*)
PROVIDE(__text_end = .);
} > ram
.rodata ALIGN(8) :
{
PROVIDE(__rodata_start = .);
*(.rodata*)
*(.srodata*)
PROVIDE(__rodata_end = .);
} > ram
.data ALIGN(8) :
{
PROVIDE(__data_start = .);
PROVIDE(__global_pointer$ = . + 0x800);
*(.sdata*)
*(.data*)
. = ALIGN(8);
PROVIDE(__data_end = .);
PROVIDE(__image_end = .);
} > ram
.bss ALIGN(8) (NOLOAD) :
{
PROVIDE(__bss_start = .);
*(.bss*)
*(.sbss*)
. = ALIGN(8);
PROVIDE(__bss_end = .);
} > ram
.stack ALIGN(16) (NOLOAD) :
{
PROVIDE(__stack_start = .);
. += STACK_SIZE;
. = ALIGN(16);
PROVIDE(__stack_end = .);
} > ram
}
I think these clocks and peripherals configured by xfel
may cause interference and misunderstanding to the development program, because xfel
does not reset them.
Is there a way for us to reset the board without losing the code data in the ddr
after xfel write 0x40000000 image.bin
, and then execute xfel exec 0x40000000
to simulate a normal reset boot.