Page 1 of 1
ExtInt and i2c Memory Error
Posted: Wed Oct 10, 2018 2:35 pm
by rhubarbdog
why am i getting this exception?
Code: Select all
Uncaught exception in ExtInt interrupt handler line 1
MemoryError:
this is my callback, it's part of an object
Code: Select all
def _read_keys(self, pin):
self._i2c.send(b'\x00', self._address)
#keys = bytearray(self._i2c.recv(2, self._address))
self._buffer = self._i2c.recv(2, self._address)
keycode = (self._buffer[1] & 0x1f) << 8 | self._buffer[0]
#keycode = (keys[1] & 0x1f) << 8 | keys[0]
# keys 0 to 9 and # & *
for i in range(12):
mask = 0x01 << i
if mask & keycode:
self._pads[i]._touch()
else:
self._pads[i]._release()
it appears to be happening at the i2c.recv
Re: ExtInt and i2c Memory Error
Posted: Wed Oct 10, 2018 2:36 pm
by jickster
Is this in an interrupt?
Re: ExtInt and i2c Memory Error
Posted: Wed Oct 10, 2018 2:42 pm
by jickster
rhubarbdog wrote: ↑Wed Oct 10, 2018 2:35 pm
why am i getting this exception?
Code: Select all
Uncaught exception in ExtInt interrupt handler line 1
MemoryError:
this is my callback, it's part of an object
Code: Select all
def _read_keys(self, pin):
self._i2c.send(b'\x00', self._address)
#keys = bytearray(self._i2c.recv(2, self._address))
self._buffer = self._i2c.recv(2, self._address)
keycode = (self._buffer[1] & 0x1f) << 8 | self._buffer[0]
#keycode = (keys[1] & 0x1f) << 8 | keys[0]
# keys 0 to 9 and # & *
for i in range(12):
mask = 0x01 << i
if mask & keycode:
self._pads[i]._touch()
else:
self._pads[i]._release()
it appears to be happening at the i2c.recv
You cannot do anything that allocates memory in an interrupt.
https://docs.micropython.org/en/latest/ ... -practices
Re: ExtInt and i2c Memory Error
Posted: Wed Oct 10, 2018 2:45 pm
by rhubarbdog
So is the i2c.recv() allocating memory internally
Re: ExtInt and i2c Memory Error
Posted: Wed Oct 10, 2018 2:46 pm
by jickster
Doesn't mean line in python code
Code: Select all
/**
* @brief These functions handle the EXTI interrupt requests.
* @param None
* @retval None
*/
void EXTI0_IRQHandler(void) {
IRQ_ENTER(EXTI0_IRQn);
Handle_EXTI_Irq(0);
IRQ_EXIT(EXTI0_IRQn);
}
void EXTI1_IRQHandler(void) {
IRQ_ENTER(EXTI1_IRQn);
Handle_EXTI_Irq(1);
IRQ_EXIT(EXTI1_IRQn);
}
void EXTI2_IRQHandler(void) {
IRQ_ENTER(EXTI2_IRQn);
Handle_EXTI_Irq(2);
IRQ_EXIT(EXTI2_IRQn);
}
Code: Select all
// Interrupt handler
void Handle_EXTI_Irq(uint32_t line) {
if (__HAL_GPIO_EXTI_GET_FLAG(1 << line)) {
__HAL_GPIO_EXTI_CLEAR_FLAG(1 << line);
if (line < EXTI_NUM_VECTORS) {
mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line];
if (*cb != mp_const_none) {
// If it's a soft IRQ handler then just schedule callback for later
if (!pyb_extint_hard_irq[line]) {
mp_sched_schedule(*cb, pyb_extint_callback_arg[line]);
return;
}
mp_sched_lock();
// When executing code within a handler we must lock the GC to prevent
// any memory allocations. We must also catch any exceptions.
gc_lock();
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_call_function_1(*cb, pyb_extint_callback_arg[line]);
nlr_pop();
} else {
// Uncaught exception; disable the callback so it doesn't run again.
*cb = mp_const_none;
extint_disable(line);
printf("Uncaught exception in ExtInt interrupt handler line %u\n", (unsigned int)line);
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
}
gc_unlock();
mp_sched_unlock();
}
}
}
}
Re: ExtInt and i2c Memory Error
Posted: Wed Oct 10, 2018 2:50 pm
by jickster
rhubarbdog wrote: ↑Wed Oct 10, 2018 2:45 pm
So is the i2c.recv() allocating memory internally
Lots of things could be. You'd have to use C-debugger to step through code to discover which functions are allocating memory.
This is not recommended route.
In a Python interrupt, you're supposed to use micropython.schedule to schedule a function to be executed later in non-interrupt context.
Re: ExtInt and i2c Memory Error
Posted: Wed Oct 10, 2018 5:01 pm
by pythoncoder
The line
Code: Select all
keys = bytearray(self._i2c.recv(2, self._address))
would allocate memory. First recv(2,...) allocates a 2-byte bytes instance. Then you allocate a bytearray. Solutions are either
- Pre-allocate the array (can be done as a default argument to the callback) and use the form of recv(my_array, ...).
- Or, simpler, use micropython.schedule(). Then you don't need to worry about allocation.
Re: ExtInt and i2c Memory Error
Posted: Wed Oct 10, 2018 5:10 pm
by SpotlightKid
rhubarbdog wrote: ↑Wed Oct 10, 2018 2:45 pm
So is the i2c.recv() allocating memory internally
You are allocating a bytearray object, when you are assigning the return value of
I2C.recv(). Instead of passing an integer for the number of bytes to read, you should pass a pre-allocated buffer (bytearray or memory view) of the length you wish to read.
http://docs.micropython.org/en/latest/l ... b.I2C.recv
Re: ExtInt and i2c Memory Error
Posted: Wed Oct 10, 2018 5:47 pm
by dhylands
This page covers writing interrupt handlers:
https://docs.micropython.org/en/latest/ ... rules.html
In particular, if you allocate an emergency exception buffer:
https://docs.micropython.org/en/latest/ ... ion-buffer
then you'll get more detailed information about where the error actually originates from.
The emergency exception buffer is essentially a pre-allocated buffer that the exception handler can use to fill in the information about where the exception occurred and the actual type of exception.