Having issues with the 'uart-interrupt' example

I’m talking about this example:

I’m not sure what is the expected behavior for this, but pretty sure it’s not what happens.
I see this printed rapidly to the serial port:

Got Uart 0 interrupt. Toggle Red LED.
Sleep for 10s more secs

I never see this printed:

Awaken

And also the debugger won’t stop there.

It seems that or the UART interrupt is triggered all the time and that is not what should happen, or the timer is not working like it should for some reason… in any case the “sleep for 10 seconds” behavior does not work.

Sorry, I’m pretty noob in embedded, tried digging into this but have not found what could be wrong.
Any ideas?

Are you using Freedom Studio and creating a project using the [bundled] freedom-e-sdk version? Any additional information you can share with the steps to reproduce will help us look into it a bit further. Also, please provide how you are connected to your board (presumably your target hardware is the HiFive1 RevB, correct?). Thanks.

Indeed, tried with both FreedomStudio-4.18.0.2021 and also PlatformIO + CLion combination.
Both options behave exactly the same.

With PlatformIO this are the settings (with studio it’s the defaults):

CONFIGURATION: https://docs.platformio.org/page/boards/sifive/hifive1-revb.html
PLATFORM: SiFive (5.0.0) > HiFive1 Rev B
HARDWARE: FE310 320MHz, 16KB RAM, 16MB Flash
DEBUG: Current (jlink) On-board (jlink, renode)
PACKAGES: 
 - framework-freedom-e-sdk 2.20050003.200818 (2005.0.3) 
 - tool-jlink 1.75001.0 (7.50.1) 
 - tool-openocd-riscv 2.1000.20190927 (10.0) 
 - toolchain-riscv 1.80300.190927 (8.3.0)

I tried both the example form the studio, and this version: example-uart-interrupt/uart-interrupt.c at 0a926cdd05461391b6a51013a8ed2bfbf6c5589d · sifive/example-uart-interrupt · GitHub

Also, same behavior.

A couple of updates to the demo below for the HiFive1 board. The UART TX interrupts are disabled during the debounce period and the intro message now matches the debounce duration of 10s. Hope this works better for you.

/* Copyright 2019 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */

#include <stdio.h>
#include <metal/cpu.h>
#include <metal/led.h>
#include <metal/uart.h>
#include <metal/machine.h>

#define RTC_FREQ			32768
#define RTC_SLEEP_TICKS		RTC_FREQ*10

struct metal_cpu *cpu;
struct metal_interrupt *cpu_intr, *tmr_intr;
struct metal_interrupt *uart0_ic;
int tmr_id, uart0_irq;
struct metal_uart *uart0;

void display_instruction (void) {
    printf("\n");
    printf("SIFIVE, INC.\n!!\n");
    printf("\n");
    printf("Coreplex IP Eval Kit 'uart-interrupt' Example.\n\n");
    printf("A 10s debounce timer is used between these interrupts.\n");
    printf("\n");
}

void timer_isr (int id, void *data) {
    // Disable Timer interrupt
    metal_interrupt_disable(tmr_intr, tmr_id);

    printf("Awaken\n");

    // re-enable Uart after our debounce period is over
    metal_uart_transmit_interrupt_enable(uart0);
}

void debounce (void) {
    printf("Sleep for 10s more secs\n");

    // Set interval for next timer interrupt
    metal_cpu_set_mtimecmp(cpu, metal_cpu_get_mtime(cpu) + RTC_SLEEP_TICKS);

    // Enable Timer interrupt for debounce period
    metal_interrupt_enable(tmr_intr, tmr_id);

}

void uart0_isr (int id, void *data) {
    // Disable uart0 tx interrupt until it gets re-enabled after the debounce period
    metal_uart_transmit_interrupt_disable(uart0);

	printf("Got Uart 0 interrupt. Toggle Red LED.\n");

    metal_led_toggle((struct metal_led *)data);

    debounce();  
}

int main (void)
{
    int rc, wakeup_count = 0;
    struct metal_led *led0_red;
    size_t txcnt;

    // Lets get start with getting LEDs and turn only RED ON
    led0_red = metal_led_get_rgb("LD0", "red");
    if (led0_red == NULL) {
        printf("LED red is null.\n");
        return 1;
    }
    metal_led_enable(led0_red);
    metal_led_on(led0_red);
 
    // Lets get the CPU and and its interrupt
    cpu = metal_cpu_get(metal_cpu_get_current_hartid());
    if (cpu == NULL) {
        printf("CPU null.\n");
        return 2;
    }
    cpu_intr = metal_cpu_interrupt_controller(cpu);
    if (cpu_intr == NULL) {
        printf("CPU interrupt controller is null.\n");
        return 3;
    }
    metal_interrupt_init(cpu_intr);

    // Setup Timer and its interrupt
    tmr_intr = metal_cpu_timer_interrupt_controller(cpu);
    if (tmr_intr == NULL) {
        printf("TIMER interrupt controller is  null.\n");
        return 4;
    }
    metal_interrupt_init(tmr_intr);
    tmr_id = metal_cpu_timer_get_interrupt_id(cpu);
    rc = metal_interrupt_register_handler(tmr_intr, tmr_id, timer_isr, cpu);
    if (rc < 0) {
        printf("TIMER interrupt handler registration failed\n");
        return (rc * -1);
    }

    // Setup UART 0 and its interrupt
    uart0 = metal_uart_get_device(0);
    uart0_ic = metal_uart_interrupt_controller(uart0);
    if (uart0_ic == NULL) {
        printf("UART0 interrupt controller is null.\n");
        return 4;
    }
    metal_interrupt_init(uart0_ic);
    uart0_irq = metal_uart_get_interrupt_id(uart0);
    rc = metal_interrupt_register_handler(uart0_ic, uart0_irq, uart0_isr, led0_red);
    if (rc < 0) {
        printf("Uart0 interrupt handler registration failed\n");
        return (rc * -1);
    }

    // Lets enable the Uart interrupt
    txcnt =  metal_uart_get_transmit_watermark(uart0);
    metal_uart_set_transmit_watermark(uart0, 1);
    metal_uart_transmit_interrupt_enable(uart0);
    display_instruction();
    if (metal_interrupt_enable(uart0_ic, uart0_irq) == -1) {
        printf("Uart0 interrupt enable failed\n");
        return 5;
    }

    // Lastly CPU interrupt
    if (metal_interrupt_enable(cpu_intr, 0) == -1) {
        printf("CPU interrupt enable failed\n");
        return 6;
    }

    metal_uart_set_transmit_watermark(uart0, txcnt);
    metal_uart_transmit_interrupt_enable(uart0);

    while (1) {
        __asm__ volatile("wfi");
    }

    return 0;
}

Thank you @dconn!
This indeed fixed the issue and now it’s working like expected.
Maybe the example code should be changed to this one.

1 Like