🛠 Simple UART Automation with Sapphire RV64

Efinix Sapphire RV64 : Configurable 64-bit RISC-V SoC for FPGAs · debutant · Apprenez à configurer une interface UART pour envoyer des données sérialisées depuis le cœur RISC-V vers un terminal.

Objectives

This tutorial aims to understand the interaction between embedded software and hardware on the Efinix Sapphire RV64 SoC. We will configure a UART peripheral to transmit textual messages. Although the topic mentions automation, for a beginner level, we focus on serialized communication, the essential foundation of any automation or supervision system. You will learn to initialize device registers and send character strings.

Required Equipment

Steps

  1. Open your Efinity project containing the Sapphire RV64 configuration. Ensure the UART IP block is included in the design and connected to the AXI4/APB3 bus.
  2. Generate the bitstream and program the FPGA. Verify that the VexiiRiscv core is active.
  3. Open your RISC-V development environment (IDE). Create a new C/C++ project.
  4. Define the memory addresses of the UART registers. These addresses are provided by the hardware description file generated by Efinity. For example:
#define UART_BASE 0x40000000
#define UART_DATA (UART_BASE + 0x00)
#define UART_STATUS (UART_BASE + 0x08)
#define UART_CTRL (UART_BASE + 0x10)
  1. Write a wait function to check that the transmit buffer is empty before sending a byte:
void uart_wait_tx_ready() {
    while ((*(volatile unsigned int*)UART_STATUS & 0x1) == 0) {
        // Busy wait
    }
}
  1. Implement the character send function:
void uart_putc(char c) {
    uart_wait_tx_ready();
    *(volatile unsigned int*)UART_DATA = (unsigned int)c;
}
  1. Create a function to send a complete string:
void uart_puts(const char *str) {
    while (*str) {
        uart_putc(*str++);
    }
}
  1. In main(), initialize the UART controller (set the baud rate divider according to your clock frequency, e.g., 115200 bauds) and send a message:
int main() {
    // Simplified initialization (adapt according to your registers)
    *(volatile unsigned int*)UART_CTRL = 0x1; 
    uart_puts("Sapphire RV64: System Ready\n");
    while(1);
}
  1. Compile the code for the RV64IMACFD architecture. Use compilation flags adapted to your core configuration (with or without FPU).
  2. Load the binary onto the FPGA via the JTAG debugger or bootloader.

Verification

Open a serial terminal connected to the board's UART. Configure the speed to 115200 bauds (8N1). If the configuration is correct, you should see the message "Sapphire RV64: System Ready" displayed. The absence of a message indicates a memory address error, baud rate configuration error, or UART pin mapping issue.

Going Further

Explore the use of interrupts to improve CPU efficiency. Next, integrate a sensor via I2C (available on the board) to read data and transmit it via UART, thus creating a first automated data acquisition system.

Other tutorials for this board

Code examples for this board

← Back to the board 🛠 All tutorials