UART getc() does not work

I want to communicate with an Arty board implemented with FE310 from my PC via USB serial (UART). Sending data to the PC, e.g., printf(), works but reading data, e.g., getc() and scanf(), from my PC does not work.

To send data from my PC while JTAG debugging, I tried both of FreedomStudio’s Terminal and pySerial (serial communication library for Python). But neither of them works.

How can I read data via UART? Or is there any other way to exchange data between an Arty board and a PC?

I tried following SiFive’s examples, but neither of them works.

  • sifive/uart-test
    In main(), simple_out() works but simple_in() does not. None of fprintf(), getchar(), fgets(), and scanf() can receive data from my PC.

    In main(), metal_uart_get_device() is undeclared. I cannot find the function even in the latest freedom-metal library (v201908-branch).


Hi Shoei, a while back I was able to get UART input to work by using the master branch of freedom-metal (which I found provides metal_uart_get_device()), and then to use metal_uart_getc(), and it was returning incoming UART data. You might give that a try. However the UART receive buffer is small, around 8 bytes and without hardware flow control, so silent overflow and data loss is possible if the incoming traffic is bursty and if software isn’t polling the UART in a tight loop at the right time, or set up to be interrupt-driven and draining all immediately available input as soon as there is any input. You might give that a try. I’ll also ask the Freedom Metal team about whether metal_uart_det_device() not being in 201908-branch is a bug that can be fixed for subsequent release.


It appears that “master” branch is now the default branch for Freedom Metal on GitHub, and metal_uart_get_device() is present still on that branch, so I assume that means that metal_uart_get_device() will be in a future tagged release.

Thanks Greg
Freedom-e-sdk of latest branch does not work just as it is but your advice is valuable. I will take further investigation.

I newly cloned the sdk from GitHub.
The following errors occurred when I built the example of ‘uart-interrupt’.
$ make software BOARD=freedom-e310-arty PROGRAM=uart-interrupt
freedom-e-sdk/freedom-metal/src/drivers/riscv_plic0.c:44:28: error: ‘METAL_RISCV_PLIC0_CONTEXT_THRESHOLD’ undeclared (first use in this function); did you mean ‘METAL_RISCV_PLIC0_THRESHOLD’?

$ make software BOARD=sifive-hifive1-revb PROGRAM=uart-interrupt
./metal/machine.h:1102:7: error: ‘__metal_dt_led_0red’ undeclared here (not in a function); did you mean ‘__metal_dt_led_0’?

Branch version:
freedom-e-sdk: master (f2d085610143f5e1b7cc08b4fbad2c8daccf3efc)
freedom-metal: master (3abf11da1a6d638aecd648487f15adf5e99442ff)


For what it’s worth, I checked which freedom-e-sdk commit I was using when I was trying UART input, and the commit was: 4c93cba66623408d546cd0d3e67583059a8986c5

I believe I was seeing successful example project builds with that (along with whatever freedom-metal submodule commit was associated with that).


Unfortunately, it does not work. What I tried is as follows:

$ git clone
$ cd freedom-e-sdk
$ git submodule update --init --recursive
$ git checkout 4c93cba66623408d546cd0d3e67583059a8986c5
$ make software BOARD=freedom-e310-arty PROGRAM=uart-interrupt
freedom-e-sdk/freedom-metal/src/scrub.S:40: undefined reference to '__metal_eccscrub_bit'
freedom-e-sdk/freedom-metal/src/drivers/riscv_cpu.c:835: undefined reference to '__metal_driver_cpu_buserror'

‘BOARD=sifive-hifive1-revb’ option also does not work with the same errors.

By the way, I found some hints through my investigation using FreedomStudio whose freedom-e-sdk version is v201908. HiFive1-revb can get characters via UART with direct register accesses, but Freedom-E310-Arty cannot do though bit 0 of rxctrl (rxen) is 0b1.
This means the problem is not caused by freedom-e-sdk.
I used following code.

#include <stdio.h>
#include <string.h>
#include <metal/machine/platform.h>

int main(int argc, char **argv) {
    uint32_t i = 0;
    uint32_t *reg;

    char buffer[50];

    printf("uart-test start\n");

    printf("reg txctrl: %x, %p\n", *reg, reg);
    printf("reg rxctrl: %x, %p\n", *reg, reg);

    while (1){
      for (i = 0; i < sizeof(buffer); i++){
        if (!(*reg & (1<<31))){
          buffer[i] = (char)((*reg) & 0xff);
        } else {
          buffer[i] = 0x00;
      for (i = 0; buffer[i] != 0x00; i++) {
        printf("ret: %c (%x)\n", buffer[i], buffer[i]);
    memset(buffer, 0x00, sizeof(buffer));

    return 0;

Now I give up getting UART input with the Arty board. I will try it again when I have time.


I solved the problem. The reason why Arty board could not get UART input was that sw3 (switch 3) had turned on unintentionally. sw3 determines whether input to UART comes from FDTI chip or gpio16 as FPGAChip.scala says.