Using HTM in C on ESP32


#1

Hi there,

Currently I’m trying to implement some time critical code in C. The idea is to control a shift register with 3 multiplex lines on high frequency to drive some leds. I tried to implement this in Pyhon, it works, but python can not really keep up with this high frequency.

Therefore I’m nog trying to implement this in C:

The python part:

@c_native("init_hw_timer",["indicators.c"],[])
def my_py_function(a,b):
    pass

The C part:

// my_c_source.c

//include zerynth header
#define ZERYNTH_PRINTF //we define this macro to use “printf” function
#include "zerynth.h"


void timer_isr();


void timer_isr(uint32_t tm, void *args)
{
    printf("interrupt triggered\n");
}


C_NATIVE(init_hw_timer) 
{
    C_NATIVE_UNWARN();

    int32_t a,b;
    if (parse_py_args("ii",nargs,args,&a,&b)!=2)
        return ERR_TYPE_EXC;

    uint32_t tm = 0;
    int vhalInitHTM();
    tm = vhalHtmGetFreeTimer();
    vhalHtmRecurrent(tm, TIME_U(10, MILLIS), timer_isr, *args);
    

    *res = PSMALLINT_NEW(a+b);
    return ERR_OK;
}

The code is not fully implement yet, but I get errors when using some of the HTM parts:

[warning] There are 2 missing symbols! This VM does not support the requested features! ['vhalInitHTM', 'vhalInitHTM']
[error] Check if the device is virtualized with the last available version-patch of the virtual machine

The ESP is running r2.2.0 P03 (FreeRTOS 8.2.0)

Also I would like to see an example of vhalHtmRecurrent timer in C if this is even possible. Or do I have to use: esp_timer_start_periodic?


#2

Unfortunately, I think the VHAL Timers are not yet supported for the ESP32 devices, But I think they are supported for other architectures.

However, we provide custom development services at low cost fee. If you are interested in this service, please let me know.


#3

@karimhamdy1

Thanks! In the meantime I figured out a working example:

/****************************************************************************/
/*																			*/
/*						timer ISR   										*/
/*																			*/
/****************************************************************************/

void timer_isr(void)
{
    //printf("interrupt triggered\n");
    unsigned edge_flag = 0;
    unsigned int i = 0;
    
    while(i < 8)
    {
        if(edge_flag == 1)
        {
            vhalPinWrite(LED_CLK, 1); // rising edge
            edge_flag = 0;
            i++;
        }
        else
        {
            vhalPinWrite(LED_CLK, 0); // falling edge
            
            // Prepare data

            if(select_data[multiplex_cntr] & (1<<i))
                vhalPinWrite(LED_DATA, 1);
            else
                vhalPinWrite(LED_DATA, 0);

            if(i == 7)
                vhalPinWrite(LED_STR, 1); // strobe

            edge_flag = 1;
        }
    }
    
    for(i = 0; i < 3; i++)
        vhalPinWrite(LED_SELECT[i], 1);
    
    vhalPinWrite(LED_SELECT[multiplex_cntr], 0);
    vhalPinWrite(LED_STR, 0); // strobe reset
    
    if(multiplex_cntr < 2)
        multiplex_cntr++;
    else
        multiplex_cntr = 0;

}

And the timer init:

/****************************************************************************/
/*																			*/
/*						timer ISR init										*/
/*																			*/
/****************************************************************************/
C_NATIVE(init_hw_timer) 
{
    C_NATIVE_UNWARN();

    //int32_t a,b;
    //if (parse_py_args("ii",nargs,args,&a,&b)!=2)
    //    return ERR_TYPE_EXC;        
    
    select_data[0] = 170;
    select_data[1] = 255;
    select_data[2] = 170;
    
    unsigned int i = 0;
    for(i = 0; i < 3; i++)
        vhalPinSetMode(LED_SELECT[i],PINMODE_OUTPUT_PUSHPULL);

    vhalPinSetMode(LED_STR,PINMODE_OUTPUT_PUSHPULL);
    vhalPinSetMode(LED_DATA,PINMODE_OUTPUT_PUSHPULL);
    vhalPinSetMode(LED_CLK,PINMODE_OUTPUT_PUSHPULL);

    // default off
    for(i = 0; i < 3; i++)
        vhalPinWrite(LED_SELECT[i], 1);
    
    esp_timer_init();
    
    int64_t t_end;
    esp_timer_handle_t timer1;
    esp_timer_create_args_t targs = {
            .callback = &timer_isr,
            .arg = &t_end,
            .name = "timer1"
    };

    esp_timer_create(&targs, &timer1);
    
    const int delay_us = 1000;
    esp_timer_start_periodic(timer1, delay_us);

    //*res = PSMALLINT_NEW(a+b);
    return ERR_OK;
}

This code runs perfectly fine a 8-bit shift register with 3 mosfet multiplex lines, so I’m able to control 8*3=21 leds.The clock is running super stable @ 1ms (checked by scope).

However, if I switch on the Wi-Fi in Python, I see some flickering … :roll_eyes: The 1ms clock is not stable anymore at this moment.

Is there a posibility to give this callback a higher priority? What can be the cause of this flicker, and how to solve this?

However, we provide custom development services at low cost fee. If you are interested in this service, please let me know.

Great! Maybe some day we would like to make use of this :slight_smile:


#4

@LorenzoR

I see similar questions at the ESP IDF forum: click here
It seems I have to change to another timer group to solve this issue?

Is there a way to fix this?


#5

Hi @LorenzoR, can you elaborate why I can use the pin ISR function from the IDF, like: Link

But why can’t I implement the hardware timers of the IDF:

#include <stddef.h>
#include "esp_intr_alloc.h"
#include "esp_attr.h"
#include "driver/timer.h"

static intr_handle_t s_timer_handle;

static void timer_isr(void* arg)
{
    TIMERG0.int_clr_timers.t0 = 1;
    TIMERG0.hw_timer[0].config.alarm_en = 1;

    // your code, runs in the interrupt
}

void init_timer(int timer_period_us)
{
    timer_config_t config = {
            .alarm_en = true,
            .counter_en = false,
            .intr_type = TIMER_INTR_LEVEL,
            .counter_dir = TIMER_COUNT_UP,
            .auto_reload = true,
            .divider = 80   /* 1 us per tick */
    };
    
    timer_init(TIMER_GROUP_0, TIMER_0, &config);
    timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0);
    timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, timer_period_us);
    timer_enable_intr(TIMER_GROUP_0, TIMER_0);
    timer_isr_register(TIMER_GROUP_0, TIMER_0, &timer_isr, NULL, 0, &s_timer_handle);

    timer_start(TIMER_GROUP_0, TIMER_0);
}

void app_main()
{
    init_timer(100);
}

[warning] There are missing symbols! This VM does not support the requested features!......

Still looking for a solution to have a stable and fast timer that won’t be affected by the Wi-Fi connection :slight_smile: