flagxor / ueforth

Apache License 2.0
95 stars 26 forks source link

timers might not be initialized when using Espressif 32 4.0 or above in PlatformIO #36

Open movingfox opened 1 year ago

movingfox commented 1 year ago

I am not sure what the platform version number means in PlatformIO. But if I install the Espressif 32 version 4.0 or above, when I call to "interval" or some timer related words, there's an error message output as:

E (70920) timer_group: timer_isr_register(258): HW TIMER NEVER INIT ERROR

Eszartek commented 1 year ago

I use the ESP32c3 which uses a different TIMG_BASE of $6001F000, so once I set that I got the same error that you did. Searching on HW TIMER NEVER INIT ERROR got me to https://www.esp32.com/viewtopic.php?t=25202 which implies it's an error from the RTOS. Later I'll try adding the timer_init() call, and if needed, some of the other arduino based calls, bypassing the lower level register setup that currently implemented.

Eszartek commented 1 year ago

I shoehorned in some of the arduino timer commands. I can make the HW TIMER NEVER INIT ERROR go away by just initializing the timer first via the timer_init() function, but the timer still doesn't fire.

After implementing 7 more words from the arduino lib, I got the timer to work, but only for words that don't do serial i/o. Blinking LED's was no problem.

I think the uforth timer attaches to the isr in a clever way which may enable triggering words that print text to serial. I just haven't been able to make it work at all. Hopefully the author will give an example on how to properly use it if it does work.

I'm using the example from https://esp32forth.appspot.com/ESP32forth.html :

timers
: hi   ." hi" cr   0 rerun ;
' hi 1000000 0 interval ( run hi every second )
Eszartek commented 1 year ago

I got the timer working now without all the extra the arduino words i was testing. Note that I've only tested this on an ESP32c3, so maybe the timerinit word is all that is needed on the other ESP32 variants. There are slight differences in the timer operation and registers of the ESP32c3 vs the others.

I created the word timerinit that is defined:

timer_config_t timerConfig = {
            .alarm_en = TIMER_ALARM_EN,
            .counter_en = TIMER_START,
            .intr_type = (timer_intr_mode_t)ESP_INTR_FLAG_EDGE,
            .counter_dir = TIMER_COUNT_UP,
            .auto_reload = (timer_autoreload_t)1,
            .divider = 80, // Timer Clock = 80Mhz -> Divider of 80 -> 1Mhz 
        };
  YV(timers, timerinit, n0 = timer_init((timer_group_t)n1, (timer_idx_t)n0, &timerConfig); DROP; DROP) 

Adding that to interval like:

: interval ( xt usec t ) dup t>nx timerinit 
                         80 over divider!
                         swap over 0 swap alarm 2!
                         1 over increase!
                         1 over autoreload!
                         1 over alarm-enable!
                         1 over edgeint! 
 ( this needed too )     1 over int-enable!
                         0 over 0 swap timer
                         ...

makes the error go away when running interval.

Lastly, I created the word alarmclr :

: alarmclr ( t -- ) 
    1 swap t>nx swap >r dup 1 swap lshift r> TIMGn_Tx_INT_CLR_REG m! ;

that I added to rerun in order to stop the timer alarms from rapid firing instead of only at the timeout. : rerun ( t -- ) dup alarmclr 1 swap alarm-enable! ;

I'm not suggesting this is a proper fix, I'm just showing how I got the timer working as I expect it should work based on the example code:

timers
: hi   ." hi" cr   0 rerun ;
' hi 1000000 0 interval ( run hi every second )
MPETREMANN11 commented 1 year ago

hi, The proposed code don't work.... Sorry

Eszartek commented 1 year ago

No, my timer code no longer works either. I am also working on tracking down the change that has broke it.

MPETREMANN11 commented 1 year ago

I tried to find the portion of code from the ESP32 library that generates this error: HW TIMER NEVER INIT ERROR

Brad NELSON programmed interval which uses onalarm which uses timer_isr_register....

I tried to figure out why this definition worked before and doesn't work anymore. More exactly, what causes this error?

The word timer_isr_register is linked to the TimerIsrRegister function and whose code is as follows:

static cell_t TimerIsrRegister(cell_t group, cell_t timer, cell_t xt, cell_t arg, cell_t flags, void *ret) {
  // NOTE: Leaks memory.
  struct handle_interrupt_args *args = (struct handle_interrupt_args *) malloc(sizeof(struct handle_interrupt_args));
  args->xt = xt;
  args->arg = arg;
  return timer_isr_register((timer_group_t) group, (timer_idx_t) timer, HandleInterrupt, args, flags, (timer_isr_handle_t *) ret);
}

I'm not familiar with the C language. But I think there is an interrupt side flag that is tested somewhere. The concern is to understand which flag is tested....

Eszartek commented 1 year ago

"HW TIMER NEVER INIT ERROR" is mitigated by calling timer_init(), this makes the new version of the RTOS code happy. There is no way that I have found to get around it. But now, use of #include "driver/timer.h" is deprecated, although it is still there and called legacy timer. The new gptimer interface is what ultimately will need to be used, but for now I am trying to make my existing timer code work since the legacy timer code is still in the sdk.

All that aside, I'm suprised you were'nt able to supress the error using the timerinit bits above. I think the alarmclr bits I wrote about only apply to the ESP32c3, which is all I am working with at the moment, which have a bunch of other differences compared to the other ESP32 variants, for example: "$3ff5f000 constant TIMG_BASE" is for the Xtensa ESP32 "$6001F000 constant TIMG_BASE" is for the Riscv ESP32c3 as well as many timer register offset differences.

The key is, don't get too hung up on why you now have to call timer_init().

My concern is that there is another breaking change in play as well, since my timers are not fuctioning any more. I was getting Panics, but now I'm at the point where my timers fire, but repeatedly without yeilding back to the forth REPL and without delay, instead of once, as that is how i am testing. If I can get setup the timer to exec a word in a few seconds in the future, get returned to the forth REPL, and then later see the output of the word, then I know I can procede to test interval timers.

Eszartek commented 1 year ago

I found that in order for my interval timers to work again, I had to change the onalarm word to use ESP_INTR_FLAG_IRAM instead of ESP_INTR_FLAG_EDGE. Again, this is for the RISC-V ESP32c3, I haven't had time to compile/test code on a Xtensa ESP32.