Rust RISC-V Quickstart Template: sprintln! UART not showing

I’m using the Rust RISC-V quickstart template from github, specifically the hello-world.rs. I modified the program to read the MISA register and print the contents instead of “hello, world.” I use

/home/dkhayes117/JLink/JLinkGDBServer -device FE310 -if JTAG -speed 4000 -port 3333 -nogui

in one terminal, then in another I cargo build then cargo run the program. Using another terminal to run

sudo screen /dev/ttyACM0 115200

to display the sprintln! from the program. This works perfectly, but I found that if I connect the HiFive1 RevB board to my laptop and run the screen command with out JLink or cargo run I never see the sprintln!. How come I only see it print if I use GDB server and cargo run? Shouldn’t the program already be loaded to the microcontroller and run by itself? below is the program

#![no_std]
#![no_main]

extern crate panic_halt;

use riscv_rt::entry;
use hifive1::hal::prelude::*;
use hifive1::hal::DeviceResources;
use hifive1::{sprintln, pin};

#[entry]
fn main() -> ! {
    let dr = DeviceResources::take().unwrap();
    let p = dr.peripherals;
    let pins = dr.pins;

    // Configure clocks
    let clocks = hifive1::clock::configure(p.PRCI, p.AONCLK, 320.mhz().into());

    // Configure UART for stdout
    hifive1::stdout::configure(p.UART0, pin!(pins, uart0_tx), pin!(pins, uart0_rx), 115_200.bps(), clocks);

    //Read the misa CSR to see all implemented extensions
    let ext = riscv::register::misa::read();
    sprintln!("MISA register Contents: {}", ext.map_or(0, |v| v.bits()));

    loop {}
}
  1. You could accidentally erase the bootloader. To check this, connect to the serial port and reset the board. You should see a few messages from the bootloader. If there aren’t any, try restoring the bootloader: https://github.com/riscv-rust/hifive1-recover/tree/master/hifive1-revb
  2. Sometimes there are problems with the very first sprintln, you can add another dummy sprintln before your “main” one.

Also, connecting the board and then connecting to the serial port will not show you the data you want because the serial port receiver on the board needs to know the correct baud rate to receive the data, so everything between poweron and serial connection will be lost.

It must be the bootloader was overwritten, I uploaded the leds_blink.rs then reset the ucontroller and it never blinked except after cargo run… I have another hifive1 that is at factory default and it always blinks green a time or two on reset. I will restore the bootloader tonight and try again.

How would I have overwritten the bootloader? I never did anything other than the basic instructions from github. Below are the details from flashing
Cargo run

warning: Loadable section ".text.dummy" outside of ELF segments

warning: Loadable section ".stack" outside of ELF segments

0x000200b8 in ?? ()

Expected an decimal digit (0-9)

Loading section .text.dummy, size 0x10000 lma 0x20000000

Loading section .text, size 0x6ee8 lma 0x20010000

Loading section .rodata, size 0xea4 lma 0x20016ef0

Loading section .stack, size 0x3ffc lma 0x80000004

Start address 0x20010000, load size 114056

Transfer rate: 41 KB/sec, 11405 bytes/write.

From Jlink

J-Link found 1 JTAG device, Total IRLen = 5
JTAG ID: 0x20000913 (RISC-V)
Connected to target
Waiting for GDB connection...Connected to 127.0.0.1
Reading all registers
Read 2 bytes @ address 0x00000000 (Data = 0x0000)
Read 2 bytes @ address 0x00000002 (Data = 0x0000)
Read 2 bytes @ address 0x00000004 (Data = 0x0000)
Read 2 bytes @ address 0x00000006 (Data = 0x0000)
Read 2 bytes @ address 0x00000008 (Data = 0x0000)
Read 2 bytes @ address 0x0000000A (Data = 0x0000)
Read 2 bytes @ address 0x0000000C (Data = 0x0000)
Read 2 bytes @ address 0x0000000E (Data = 0x0000)
Read 2 bytes @ address 0x00000010 (Data = 0x0000)
Read 2 bytes @ address 0x00000012 (Data = 0x0000)
Read 2 bytes @ address 0x00000014 (Data = 0x0000)
Read 2 bytes @ address 0x00000016 (Data = 0x0000)
Read 2 bytes @ address 0x00000018 (Data = 0x0000)
Read 2 bytes @ address 0x0000001A (Data = 0x0000)
Read 2 bytes @ address 0x0000001C (Data = 0x0000)
Read 2 bytes @ address 0x0000001E (Data = 0x0000)
Read 2 bytes @ address 0x00000020 (Data = 0x0000)
Read 2 bytes @ address 0x00000022 (Data = 0x0000)
Read 2 bytes @ address 0x00000024 (Data = 0x0000)
Read 2 bytes @ address 0x00000026 (Data = 0x0000)
Read 2 bytes @ address 0x00000028 (Data = 0x0000)
Read 2 bytes @ address 0x0000002A (Data = 0x0000)
Read 2 bytes @ address 0x0000002C (Data = 0x0000)
Read 2 bytes @ address 0x0000002E (Data = 0x0000)
Read 2 bytes @ address 0x00000030 (Data = 0x0000)
Read 2 bytes @ address 0x00000032 (Data = 0x0000)
Read 2 bytes @ address 0x00000034 (Data = 0x0000)
Read 2 bytes @ address 0x00000036 (Data = 0x0000)
Read 2 bytes @ address 0x00000038 (Data = 0x0000)
Read 2 bytes @ address 0x0000003A (Data = 0x0000)
Read 2 bytes @ address 0x0000003C (Data = 0x0000)
Read 2 bytes @ address 0x0000003E (Data = 0x0000)
Read 2 bytes @ address 0x00000040 (Data = 0x0000)
Read 2 bytes @ address 0x00000042 (Data = 0x0000)
Read 2 bytes @ address 0x00000044 (Data = 0x0000)
Read 2 bytes @ address 0x00000046 (Data = 0x0000)
Read 2 bytes @ address 0x00000048 (Data = 0x0000)
Read 2 bytes @ address 0x0000004A (Data = 0x0000)
Read 2 bytes @ address 0x0000004C (Data = 0x0000)
Read 2 bytes @ address 0x0000004E (Data = 0x0000)
Read 2 bytes @ address 0x00000050 (Data = 0x0000)
Read 2 bytes @ address 0x00000052 (Data = 0x0000)
Read 2 bytes @ address 0x00000054 (Data = 0x0000)
Read 2 bytes @ address 0x00000056 (Data = 0x0000)
Read 2 bytes @ address 0x00000058 (Data = 0x0000)
Read 2 bytes @ address 0x0000005A (Data = 0x0000)
Read 2 bytes @ address 0x0000005C (Data = 0x0000)
Read 2 bytes @ address 0x0000005E (Data = 0x0000)
Read 2 bytes @ address 0x00000060 (Data = 0x0000)
Read 2 bytes @ address 0x00000062 (Data = 0x0000)
Received monitor command: reset halt
Expected an decimal digit (0-9)
Downloading 16352 bytes @ address 0x20000000
Downloading 16352 bytes @ address 0x20003FE0
Downloading 16352 bytes @ address 0x20007FC0
Downloading 16352 bytes @ address 0x2000BFA0
Downloading 128 bytes @ address 0x2000FF80
Downloading 15248 bytes @ address 0x20010000
Downloading 12816 bytes @ address 0x20013B90
Downloading 3748 bytes @ address 0x20016DA0
Downloading 16364 bytes @ address 0x80000004
Comparing flash   [....................] Done.
Erasing flash     [....................] Done.
Programming flash [....................] Done.
Verifying flash   [....................] Done.
Downloading 16 bytes @ address 0x80003FF0
Writing register (pc = 0x20010000)
Starting target CPU...

IIRC there was a bug in LLVM (and therefore in Rust) a while ago, that, together with the hacky linker script in riscv-rt, produced an ELF file that was loaded to the beginning of the flash, effectively destroying the bootloader. I was about to add a big red warning to the quickstart repo, but then the bug was apparently fixed, so I ended up with the hifive1-recover repo I mentioned above.

Hmm, actually, according to the logs you posted, you have this problem right now, so I recommend you switching to the beta or nightly Rust compiler for now.

1 Like

I don’t understand how to reload the bootloader from your link. I downloaded the .bin file into my JLink folder, along with the recover.jlink file. I cd into the JLink directory then tried to run

JLinkExe -device FE310 -if JTAG -speed 4000 -jtagconf -1,-1 -CommandFile recover.jlink

but it just says JLinkExe: command not found

EDIT
I figured out it should be

/home/dkhayes117/JLink/JLinkExe -device FE310 -if JTAG -speed 4000 -jtagconf -1,-1 -CommandFile recover.jlink

now it says Could not open J-Link Command File 'recover.jlink'
I tried chmod +x recover.jlink and that didn’t help

Okay I got it work this time :slight_smile: I made “recover” a shell script and executed it and all went well. The board is working correctly now. Appreciate the link, now can I upload my program without wiping it out again :thinking:

I should have made proper docs, but generally you only need to run ./recover inside the hifive1-revb directory.

With beta or nightly toolchain, yes.

1 Like

I set my defaults to nightly and beta via

rustup default nightly
rustup default beta

Neither one will compile any of the quick start examples, it says

error[E0463]: can't find crate for `core`
  |
  = note: the `riscv32imac-unknown-none-elf` target may not be installed

error: aborting due to previous error

For more information about this error, try `rustc --explain E0463`.
error: could not compile `bit_field`.

To learn more, run the command again with --verbose.
warning: build failed, waiting for other jobs to finish...
error: build failed

If I switch back to stable rust, it compiles without fail.

Never mind, I didn’t realize I had to run this command again until I reviewed the repo read me file again

rustup target add riscv32imac-unknown-none-elf

I am able to build again with beta rust. :slight_smile:

1 Like

Just to confirm, using beta Rust 1.46.0, the bootloader remains intact after cargo run.