Hello,
While working on a device equipped with the AT86RF231 transceiver, I face a strange and disrupting behavior.
After I have put the transceiver to sleep mode, then back in reception mode, I am just not able receive transceiver-related IRQs any more. It means I can't receive packets, since the RX_START and (more importantly) TRX_END interrupts, which allow me to know when to read the transceiver's frame buffer, have disappeared.
After some tests, this problem happens only when I turn the transceiver into and out of sleep mode: if I leave the transceiver constantly "on", the IRQs continue to work normally.
Consequently, I am posting hereafter the C functions I use to turn the trasceiver into and out of sleep mode, in the hope that someone can tell me what's wrong with them.
To put the transceiver in sleep mode ("turn off"):
void at86rf231_off(void) { /* Send a FORCE TRX OFF command */ at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__FORCE_TRX_OFF); /* busy wait for TRX_OFF state */ do { int delay = _MAX_RETRIES; if (!--delay) { FATAL("at86rf231 : ERROR : could not enter TRX_OFF mode\n"); return; } } while (at86rf231_current_mode() != AT86RF231_TRX_STATUS__TRX_OFF); /* assert SLP_TR line */ gpio_set(AT86RF231_SLEEP); at86rf231_active = false; DEBUG("AT86RF231 transceiver goes off.\n"); }
To get the transceiver out of sleep mode ("on"):
int at86rf231_on(void) { /* negate SLP_TR line */ gpio_clear(AT86RF231_SLEEP); /* busy wait for TRX_OFF state */ do { int delay = _MAX_RETRIES; if (!--delay) { FATAL("at86rf231 : ERROR : could not wake up transceiver!\n"); return 0; } } while (at86rf231_current_mode() != AT86RF231_TRX_STATUS__TRX_OFF); at86rf231_active = true; /* change into reception mode */ at86rf231_switch_to_rx(); DEBUG("AT86RF231 transceiver is up and running.\n"); return 1; } void at86rf231_switch_to_rx(void) { gpio_irq_disable(AT86RF231_INT); /* now change to PLL_ON state for extended operating mode */ at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__PLL_ON); do { int max_wait = _MAX_RETRIES; if (!--max_wait) { FATAL("at86rf231 : ERROR : could not enter PLL_ON mode\n"); break; } } while (at86rf231_current_mode() != AT86RF231_TRX_STATUS__PLL_ON); /* Read IRQ status register to clear it */ at86rf231_reg_read(AT86RF231_REG__IRQ_STATUS); /* Enable IRQ interrupt */ gpio_irq_enable(AT86RF231_INT); /* Enter RX_AACK_ON state */ at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__RX_AACK_ON); do { int max_wait = _MAX_RETRIES; if (!--max_wait) { FATAL("at86rf231 : ERROR : could not enter RX_AACK_ON mode\n"); break; } } while (at86rf231_current_mode() != AT86RF231_TRX_STATUS__RX_AACK_ON); }
These functions use the following utility code:
#define _MAX_RETRIES (100) static volatile bool at86rf231_active; uint8_t at86rf231_current_mode(void) { return (at86rf231_reg_read(AT86RF231_REG__TRX_STATUS) & AT86RF231_TRX_STATUS_MASK__TRX_STATUS); }
I don't understand why transceiver interrupts do not fire anymore when going out of sleep mode, since the contents of AT86RF231 registers are supposed to preserved in SLEEP state, according to datasheet.
Any ideas or comments are warmly welcomed!
Thanks in advance,