Interrupt setup on ESP32-H2

This is a 32-bit RISC-V chip from Espressif.

In portable/GCC/RISC-V/port.c:186, in xPortStartScheduler, there is

        /* Enable mtime and external interrupts.  1<<7 for timer interrupt,
         * 1<<11 for external interrupt.  _RB_ What happens here when mtime is
         * not present as with pulpino? */
        __asm volatile ( "csrs mie, %0" ::"r" ( 0x880 ) );

but this chip (and possibly others in the ESP32 range?) have an atypical view of mie; bit 11 in fact enables the external interrupt at vector 11, and so on.

Also, setting mie.mtie isn’t enough to get timer interrupts: there’s a memory-mapped control register MTIMECTL:

  • MTCE Configures whether to enable the CLINT timer counter.
  • MTIE Write 1 to enable the machine timer interrupt.
  • MTIP Represents the pending status of the machine timer interrupt.
  • MTOF Configures whether the machine timer overflows.

I can set up MTIMECTL before calling xPortStartScheduler, but I don’t think I have any control after that. I’d need to clear mie bit 11 as the very first thing in the very first task.

I wonder whether we could add a config variable? configENABLE_EXTERNAL_INTERRUPTS? If undefined or 0, set mie to 0x080, otherwise to 0x880 as now?

That would change the default behaviour for people who’re relying on having external interrupts enabled, which would be a Bad Thing, of course.

The line that you mentioned is guarded by configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS:

    #if ( ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 ) )
    {
        /* Enable mtime and external interrupts.  1<<7 for timer interrupt,
         * 1<<11 for external interrupt.  _RB_ What happens here when mtime is
         * not present as with pulpino? */
        __asm volatile ( "csrs mie, %0" ::"r" ( 0x880 ) );
    }
    #endif /* ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 ) */

Reading your description, it seems like you want to use a different timer. You should set configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS to 0 in your FreeRTOSConfig.h:

#define configMTIME_BASE_ADDRESS 0
#define configMTIMECMP_BASE_ADDRESS 0

You then need to implement void vPortSetupTimerInterrupt( void ) to setup your timer interrupt and implement your timer ISR something like this - FreeRTOS-Kernel/portable/GCC/RISC-V/portASM.S at main · FreeRTOS/FreeRTOS-Kernel · GitHub.

Assuming this chip does not have any extra registers, you should use this header - FreeRTOS-Kernel/portable/GCC/RISC-V/chip_specific_extensions/RISCV_no_extensions/freertos_risc_v_chip_specific_extensions.h at main · FreeRTOS/FreeRTOS-Kernel · GitHub.

Why are you not using the FreeRTOS version provided in esp-idf. It should take care of all these things.

Sorry to have given that impression.

Aside from this one issue, FreeRTOS 11.1.0 is working well, with configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS set to appropriate values, and RISCV_MTIME_CLINT_no_extensions.

Since the chip’s 65 peripheral interrupt sources have to be mapped to the 28 CPU interrupts, I can just not use CPU interrupt 11.

I’ve been using vanilla FreeRTOS for 10 years to support my Ada runtime, and Espressif’s version is quite extensively changed, so I’d prefer to continue as before.

On a separate topic, that project of mine is called Cortex GNAT RTS - that’ll not be appropriate any more, I was wondering if there’d be any objection to changing the name to FreeRTOS Ada? (I see I wouldn’t be the first - e.g. FreeRTOS-rust)

Thank you for explaining. Is it not possible to set configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS to 0 and provide your own void vPortSetupTimerInterrupt( void )?

I think that should be fine.