Crash in timer interupt when data type "float" is used

Hans Dorn
Posts: 62
Joined: Tue Feb 21, 2017 2:21 am

Crash in timer interupt when data type "float" is used

Postby Hans Dorn » Sun Feb 26, 2017 8:58 am

I'm seeing a weird crash here when I try to use "float" in a timer ISR.

Example:

Code: Select all

hw_timer_t *timer0; uint32_t timer0_int = 0; float timer0_float = 0.0; double timer0_double = 0.0; void IRAM_ATTR timer0_intr() // Interrupt handler for timer 0 { timer0_int++; timer0_float = timer0_int; timer0_double = timer0_int; } void setup() { timer0 = timerBegin(0, 80, true); // divider 80 = 1MHz timerAlarmWrite(timer0, 999, true); // Alarm every 1000 µs, auto-reload timerAttachInterrupt(timer0, timer0_intr, true); // attach timer0_inter, edge type interrupt timerAlarmEnable(timer0); Serial.begin(115200); } void loop() { Serial.println(timer0_int); delay(100); }
This sketch will crash and generate the following output:

Code: Select all

ets Jun 8 2016 00:22:57 rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) ets Jun 8 2016 00:22:57 rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0x00 clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:1 load:0x3fff0008,len:8 load:0x3fff0010,len:1760 load:0x40078000,len:6668 load:0x40080000,len:252 entry 0x40080034 0 Guru Meditation Error: Core 1 panic'ed (Unhandled debug exception) Debug exception reason: BREAK instr Register dump: PC : 0x40080930 PS : 0x00060036 A0 : 0x800809c8 A1 : 0x3ffc1100 A2 : 0x00000000 A3 : 0x00000001 A4 : 0x20000000 A5 : 0x00000000 A6 : 0x00000400 A7 : 0x00060823 A8 : 0x3ffc2504 A9 : 0x3ffc80f0 A10 : 0x00000001 A11 : 0x00060023 A12 : 0x80082a29 A13 : 0x3ffc81b0 A14 : 0x00000003 A15 : 0x00000000 SAR : 0x00000018 EXCCAUSE: 0x00000001 EXCVADDR: 0x00000000 LBEG : 0x00000000 LEND : 0x00000000 LCOUNT : 0x00000000 Backtrace: 0x40080930:0x3ffc1100 0x400809c8:0x3ffc11e0 0x40081651:0x3ffc1200 CPU halted.
The weird part is, if I comment out this line:

// timer0_float = timer0_int;

then the sketch will run without problems, despite a double precision variable being accessed

So "float" will crash, but "double" is OK to use?

Cheers
Hans

P.S: I'd rather be using floats, they're quite a bit faster than double.

ESP_igrr
Posts: 1190
Joined: Tue Dec 01, 2015 8:37 am

Re: Crash in timer interupt when data type "float" is used

Postby ESP_igrr » Sun Feb 26, 2017 2:18 pm

Floats use the FPU while doubles are calculated in software. For reasons, using the FPU inside an interrupt handler is currently not supported.

Hans Dorn
Posts: 62
Joined: Tue Feb 21, 2017 2:21 am

Re: Crash in timer interupt when data type "float" is used

Postby Hans Dorn » Sun Feb 26, 2017 2:37 pm

Thanks for the quick answer, good to know.

I'll use doubles (sparingly) or integer math in the meantime.

Is the problem fixable?


Cheers
Hans Dorn

ESP_Sprite
Posts: 1994
Joined: Thu Nov 26, 2015 4:08 am

Re: Crash in timer interupt when data type "float" is used

Postby ESP_Sprite » Mon Feb 27, 2017 1:29 am

Yes, it is solvable: it means messing with the asssembler in the coprocessor handler to add the code to store the FPU state when an interrupt happens and restoring it when the interrupt is done. I have it on my list, but it's fairly low-priority: you can expect a fix evenrually, but I don't know the timeframe for that.

Hans Dorn
Posts: 62
Joined: Tue Feb 21, 2017 2:21 am

Re: Crash in timer interupt when data type "float" is used

Postby Hans Dorn » Wed Mar 01, 2017 5:23 am

I managed to switch on the FPU in my ISR by doing the following:

Code: Select all

uint32_t timer0_int = 0; float timer0_float = 0.0; uint32_t cp0_regs[18]; void IRAM_ATTR timer0_intr() // Interrupt handler for timer 0 { // enable FPU xthal_set_cpenable(1); // Save FPU registers xthal_save_cp0(cp0_regs); timer0_int++; timer0_float = timer0_int * 1.1111111111; timer0_double = timer0_int; // Restore FPU xthal_restore_cp0(cp0_regs); // and turn it back off xthal_set_cpenable(0); }
Will this break anything?
Do I have to save the FPU registers, or will the FPU be unusable anyway once FreeRTOS returns to the interrupted task?

Cheers

ESP_Sprite
Posts: 1994
Joined: Thu Nov 26, 2015 4:08 am

Re: Crash in timer interupt when data type "float" is used

Postby ESP_Sprite » Wed Mar 01, 2017 9:40 am

It may work, if you restore the FPU-enabled state to the same state it was in. Depending on what the interrupted task was doing, it can actually be on or off, and because Xtensa uses lazy switching, this actually contains information about the FPU state itself. It's kinda-sortta here-be-dragons, though: I'd advise you just to use ints and do any float calculation in a task if you can get away with it.

Hans Dorn
Posts: 62
Joined: Tue Feb 21, 2017 2:21 am

Re: Crash in timer interupt when data type "float" is used

Postby Hans Dorn » Thu Mar 02, 2017 12:27 am

It may work, if you restore the FPU-enabled state to the same state it was in. Depending on what the interrupted task was doing, it can actually be on or off, and because Xtensa uses lazy switching, this actually contains information about the FPU state itself.
Thanks, I was wondering about what happens if the ISR interrupts a task that is running with an enabled CPU.
It's kinda-sortta here-be-dragons, though: I'd advise you just to use ints and do any float calculation in a task if you can get away with it.
I hear you. Me being curious, I'll try to make stuff break in interesting ways first, and maybe learn something this way.

Cheers
Hans

P.S:
I just found that accessing a floating point literal in your code will clear cpenable, inducing a hefty penalty in wasted cycles.
Keeping your constants stored like this:

Code: Select all

DRAM_ATTR float f3 = 1.0001;
will prevent GCC from mis-optimizing your code.

Hans Dorn
Posts: 62
Joined: Tue Feb 21, 2017 2:21 am

Re: Crash in timer interupt when data type "float" is used

Postby Hans Dorn » Fri Mar 03, 2017 2:20 am

Ok here we go :)


This version works nicely for me:

Code: Select all

uint32_t timer0_int = 0; float timer0_float = 0.0; DRAM_ATTR float timer0_k = 1.111111; uint32_t cp0_regs[18]; void IRAM_ATTR timer0_intr() // Interrupt handler for timer 0 { // get FPU state uint32_t cp_state = xthal_get_cpenable(); if(cp_state) { // Save FPU registers xthal_save_cp0(cp0_regs); } else { // enable FPU xthal_set_cpenable(1); } timer0_int++; timer0_float = timer0_int * timer0_k; if(cp_state) { // Restore FPU registers xthal_restore_cp0(cp0_regs); } else { // turn it back off xthal_set_cpenable(0); } }
I let a long running float calculation run in the main loop and verified that
either failing to return the cpenable flag in the state I found it,
or failing to save and restore the FPU registers will make the main loop fail.

Extended precision integer math doesn't look like much fun on xtensa, because the CPU doesn't have any arithmetic flags...
(for performance reasons I guess)


Thx for the hint.

Cheers
Hans

P.S:
I know I'm on my own here when I do something in my code that causes the FPU to become disabled,
but I'd rather cope with this and keep using the fast FPU

ESP_Sprite
Posts: 1994
Joined: Thu Nov 26, 2015 4:08 am

Re: Crash in timer interupt when data type "float" is used

Postby ESP_Sprite » Fri Mar 03, 2017 4:49 am

Ah, you probably want to save/restore the state of the FPU regardless if it's enabled or disabled. The way Xtensa FreeRTOS works is that if a task that uses the FPU is switched out, the FPU gets disabled but the data stays in the FPU registers. If the same task is later switched in, the FPU only needs to be re-enabled. If another task uses the FPU as well, the coprocessor exception will take care of saving/loading states at that time. So, when the FPU is used in a program, the contents of the registers are always 'live' and can never be discarded.

Hans Dorn
Posts: 62
Joined: Tue Feb 21, 2017 2:21 am

Re: Crash in timer interupt when data type "float" is used

Postby Hans Dorn » Fri Mar 03, 2017 4:59 am

OK, will do.


I'm always trying to shave off a few cycles, as IME there are never enough.

Cheers

Who is online

Users browsing this forum: No registered users and 8 guests