UART interface to a RISC-V RV32I Core

1,150 views
Skip to first unread message

Satyajit Bora

unread,
Mar 8, 2018, 10:48:35 AM3/8/18
to RISC-V HW Dev
Hello all,

I have a small riscv core which can perform all RV32I instructions. I want to interface a UART with this core on an FPGA platform, so that if I print a message using "printf" function in C code, it can display the message on terminal through uart.

Can anyone please tell me, how should I proceed ? Do I need to modify the compiler ?

I am an electronics engineer and modifying the compiler is a tough job for me. If there is a easier way to do that please let me know.

Regards,
Satyajit

Euripedes Rocha Filho

unread,
Mar 8, 2018, 10:54:24 AM3/8/18
to Satyajit Bora, RISC-V HW Dev
Hi Satyajit,
how your UART core is interfacing to the core? Is it memory mapped? You will need to write a small logging function or even implement printf and redirect it to the UART IP. It's more an embedded C/driver job than compiler. 

Regards

--
You received this message because you are subscribed to the Google Groups "RISC-V HW Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hw-dev+un...@groups.riscv.org.
To post to this group, send email to hw-...@groups.riscv.org.
Visit this group at https://groups.google.com/a/groups.riscv.org/group/hw-dev/.
To view this discussion on the web visit https://groups.google.com/a/groups.riscv.org/d/msgid/hw-dev/d4aef2fe-e5ac-4b22-aa12-4d1f300b005f%40groups.riscv.org.

Dr Jonathan Kimmitt

unread,
Mar 8, 2018, 10:55:21 AM3/8/18
to Satyajit Bora, RISC-V HW Dev

No need to modify the compiler, just write a routine similar to this:

#include <string.h>
#include <stdarg.h>

int printf (const char *fmt, ...)
{
  char buffer[99], *sptr = buffer;
  va_list va;
  int rslt;
  va_start(va, fmt);
  rslt = vsnprintf(buffer, sizeof(buffer), fmt, va);
  va_end(va);
  while (*sptr) uart_send(*sptr++);
  return rslt;
}

You will need to write the routine uart_send() which will be hardware dependent, and just needs to wait for the UART output to drain, before adding the next character.

Satyajit Bora

unread,
Mar 8, 2018, 11:25:48 AM3/8/18
to RISC-V HW Dev, satyaji...@gmail.com
Thank you for the reply.

Can you please explain, how can I write the routine for uart_send() ? Sorry, if I am asking too basic question.

Dr Jonathan Kimmitt

unread,
Mar 8, 2018, 11:33:10 AM3/8/18
to Satyajit Bora, RISC-V HW Dev

That will depend on your hardware. If it is 16550 compliant you could use something like this:

// RBR: Receiver buffer register [Read, LCR[7] == 0]
#define UART_RBR 0x0u
// THR: Transmitter Holding register [Write, LCR[7] == 0]
#define UART_THR 0x0u
// IER: Interrupt enable register [Read/Write, LCR[7] == 0]
#define UART_IER 0x1u
// IIR: Interrupt identification register [Read]
#define UART_IIR 0x2u
// FCR: FIFO control register [Write, Read only when LCR[7] == 1]
#define UART_FCR 0x2u
// LCR: Line control register [Read/Write]
#define UART_LCR 0x3u
// MCR: Modem control register [Read/Write]
#define UART_MCR 0x4u
// LSR: Line status register [Read/Write]
#define UART_LSR 0x5u
// MSR: Modem status register [Read/Write]
#define UART_MSR 0x6u
// SCR: Scratch register [Read/Write]
#define UART_SCR 0x7u
// DLL: Divisor latch (least significant byte) register [Read/Write, LCR[7] == 1]
#define UART_DLL 0x0u
// DLM: Divisor latch (most significant byte) register [Read/Write, LCR[7] == 1]
#define UART_DLM 0x1u

volatile uint32_t *uart_base_ptr = (uint32_t *)(UART_BASE);

void uart_init() {
  // set 0x0080 to UART.LCR to enable DLL and DLM write
  // configure baud rate
  *(uart_base_ptr + UART_LCR) = 0x0080;

  // System clock 25 MHz, 115200 baud rate
  // divisor = clk_freq / (16 * Baud)
  *(uart_base_ptr + UART_DLL) = 25*1000*1000u / (16u * 115200u) % 0x100u;
  *(uart_base_ptr + UART_DLM) = 25*1000*1000u / (16u * 115200u) >> 8;

  // 8-bit data, 1-bit odd parity
  *(uart_base_ptr + UART_LCR) = 0x000Bu;
}

void uart_send(uint8_t data) {
  // wait until THR empty
  while(! (*(uart_base_ptr + UART_LSR) & 0x40u));
  *(uart_base_ptr + UART_THR) = data;
}

UART_BASE is the memory mapped base address of your peripheral.

Anton Krug

unread,
Mar 8, 2018, 2:57:55 PM3/8/18
to RISC-V HW Dev
You should be able to implement your own 
ssize_t _write(int fd, const void* ptr, size_t len)
and leave the original printf to use it, you only need to implement your UART driver to output a character.
You could even detect if it's STDOUT_FILENO or STDERR_FILENO and maybe send stderr on different uart if you would wish to.
Btw your compiler is using newlib?

Guy Lemieux

unread,
Mar 8, 2018, 4:33:05 PM3/8/18
to RISC-V HW Dev
This isn't a RISC-V issue -- this is a general computer systems issue.

Unless it has to do with RISC-V specifically, this forum is inappropriate.

Sincerely,
Guy
> --
> You received this message because you are subscribed to the Google Groups
> "RISC-V HW Dev" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to hw-dev+un...@groups.riscv.org.
> To post to this group, send email to hw-...@groups.riscv.org.
> Visit this group at
> https://groups.google.com/a/groups.riscv.org/group/hw-dev/.
> To view this discussion on the web visit
> https://groups.google.com/a/groups.riscv.org/d/msgid/hw-dev/811718ad-f16c-42bf-84fe-d718d22cfa72%40groups.riscv.org.

Anton Krug

unread,
Mar 8, 2018, 4:39:02 PM3/8/18
to Guy Lemieux, RISC-V HW Dev
hw-dev for sure, but it doesn't fell that offtopic to me that it wouldn't be answered on the sw-dev riscv forum.

Or download SoftConsole, it contains examples where the printf can be enabled/disabled with one #define as pass-through to the UART.

--
You received this message because you are subscribed to the Google Groups "RISC-V HW Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hw-dev+unsubscribe@groups.riscv.org.

To post to this group, send email to hw-...@groups.riscv.org.
Visit this group at https://groups.google.com/a/groups.riscv.org/group/hw-dev/.

Satyajit Bora

unread,
Mar 9, 2018, 12:22:36 AM3/9/18
to RISC-V HW Dev, glem...@vectorblox.com
Thanks a lot Anton Krug for your valuable suggestions. Now, I am getting some idea to proceed.

> To post to this group, send email to hw-...@groups.riscv.org.
> Visit this group at
> https://groups.google.com/a/groups.riscv.org/group/hw-dev/.
> To view this discussion on the web visit
> https://groups.google.com/a/groups.riscv.org/d/msgid/hw-dev/811718ad-f16c-42bf-84fe-d718d22cfa72%40groups.riscv.org.

--
You received this message because you are subscribed to the Google Groups "RISC-V HW Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hw-dev+un...@groups.riscv.org.

To post to this group, send email to hw-...@groups.riscv.org.
Visit this group at https://groups.google.com/a/groups.riscv.org/group/hw-dev/.
Reply all
Reply to author
Forward
0 new messages