Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers/at86rf215: The activation of the address match interrupt is missing in the at86rf215_reset function #20505

Open
Lennart-Lutz opened this issue Mar 26, 2024 · 0 comments

Comments

@Lennart-Lutz
Copy link

Description

In the current RIOT version, the address match interrupt is only activated in the _init function in the driver for the AT86RF215 radio module. This interrupt is required so that the callback of the MAC layer is called with RX_STARTED.

drivers/at86rf215/at86rf215_netdev.c 105
static int _init(netdev_t *netdev)
{
    ...

    /* reset device to default values and put it into RX state */
    at86rf215_reset_and_cfg(dev);

    ...
}
drivers/at86rf215/at86rf215.c 62
void at86rf215_reset_and_cfg(at86rf215_t *dev)
{
    ...

    /* enable RX start IRQs */
    at86rf215_reg_or(dev, dev->BBC->RG_IRQM, BB_IRQ_RXAM);
}

The problem with this is, that when the radio wakes up from sleep mode, the configuration is lost. This means that the BBC_IRQM register is completely set to 0 after the module wakes up, resulting in no interrupts being generated. To overcome this, all necessary interrupts are reset in the reset function after wake-up. However, the BB_IRQ_RXAM interrupt is missing.

drivers/at86rf215/at86rf215_getset.c 310
static void _wake_from_sleep(at86rf215_t *dev)
{
    ...

    /* config is lost after SLEEP */
    at86rf215_reset(dev);

    ...
}
drivers/at86rf215/at86rf215.c 103
void at86rf215_reset(at86rf215_t *dev)
{
    ...

    /* enable TXFE & RXFE IRQ */
    at86rf215_reg_write(dev, dev->BBC->RG_IRQM, BB_IRQ_TXFE | BB_IRQ_RXFE); // <-- BB_IRQ_RXAM missing!!

    /* enable EDC IRQ */
    at86rf215_reg_write(dev, dev->RF->RG_IRQM, RF_IRQ_EDC | RF_IRQ_TRXRDY);

    ...
{

In earlier RIOT versions this was not a problem because the address match interrupt could be reactivated with a set function using a net option. This functionality has been removed in the current version, so it is necessary to activate the BB_IRQ_RXAM interrupt in the reset function.

Steps to reproduce the issue

You need at least two microcontrollers (for exmaple a nucleo-f411re) with an at86rf215 connected to it. Now write a script that does the following things: For both nodes the script should put the at86rf215 radio module to sleep and wakes it up directly after. This step is important to reproduce the issue! After that, one of the nodes should periodically send a message to the other node.

The application should look like this:

Makefile
APPLICATION = at86rf215-issue

BOARD ?= nucleo-f411re
RIOTBASE ?= $(CURDIR)/../..

USEMODULE += netdev_default
USEMODULE += auto_init_gnrc_netif

USEMODULE += ztimer

# Include the radio
USEMODULE += at86rf215
USEMODULE += at86rf215_24ghz

# Configure the radio
SPI ?= SPI_DEV(0)
PIN_CS ?= GPIO_PIN(PORT_B, 6)
PIN_IRQ ?= GPIO_PIN(PORT_A, 9)
PIN_RST ?= GPIO_PIN(PORT_C, 7)

ifneq (, $(SPI))
  CFLAGS += '-DAT86RF215_PARAM_SPI=$(SPI)'
endif
ifneq (, $(PIN_CS))
  CFLAGS += '-DAT86RF215_PARAM_CS=$(PIN_CS)'
endif
ifneq (, $(PIN_IRQ))
  CFLAGS += '-DAT86RF215_PARAM_INT=$(PIN_IRQ)'
endif
ifneq (, $(PIN_RST))
  CFLAGS += '-DAT86RF215_PARAM_RESET=$(PIN_RST)'
endif

include $(RIOTBASE)/Makefile.include

# Set a custom channel if needed
include $(RIOTMAKE)/default-radio-settings.inc.mk

main.c
#include <stdio.h>
#include <string.h>

#include "board.h"
#include "net/gnrc.h"
#include "net/gnrc/netif.h"

#ifdef tx_node

typedef struct
{
    uint8_t arr[106]; // Dummy data
} message_t;

static int l2_send(netif_t *iface, char *str_addr, uint8_t *data, size_t len)
{
    /* Only short addr */
    size_t addr_len = 2; 
    gnrc_pktsnip_t *pkt, *hdr;
    gnrc_netif_hdr_t *nethdr;
    uint8_t flags = 0x00;

    uint8_t addr[addr_len];
    l2util_addr_from_str(str_addr, addr);

    /* Put packet together */
    pkt = gnrc_pktbuf_add(NULL, data, len, GNRC_NETTYPE_UNDEF);
    if (pkt == NULL)
    {
        printf("error: packet buffer full\n");
        return 1;
    }
    hdr = gnrc_netif_hdr_build(NULL, 0, addr, addr_len);
    if (hdr == NULL)
    {
        printf("error: packet buffer full\n");
        gnrc_pktbuf_release(pkt);
        return 1;
    }

    pkt = gnrc_pkt_prepend(pkt, hdr);
    nethdr = (gnrc_netif_hdr_t *)hdr->data;
    nethdr->flags = flags;

    /* Send */

    if (gnrc_netif_send(container_of(iface, gnrc_netif_t, netif), pkt) < 1)
    {
        printf("error: unable to send\n");
        gnrc_pktbuf_release(pkt);
        return 1;
    }

    return 0;
}

#endif

void turn_off_netif(netif_t *netif)
{   
    int res = -1;
    while (res != NETOPT_STATE_SLEEP)
    {
        netopt_state_t state = NETOPT_STATE_SLEEP;
        res = netif_set_opt(netif, NETOPT_STATE, 0, (void *) &state, sizeof(state));
    }
}

void turn_on_netif(netif_t *netif)
{   
    netopt_state_t state = NETOPT_STATE_IDLE;
    netif_set_opt(netif, NETOPT_STATE, 0, (void *) &state, sizeof(state));
}

int main(void)
{
    netif_t *netif = netif_iter(NULL);

    turn_off_netif(netif);
    // wait some time
    ztimer_sleep(ZTIMER_MSEC, 10);
    turn_on_netif(netif);

#ifdef tx_node
   // One of the node should send
   while(1)
   {
        message_t msg;
        l2_send(netif, "FF:FF", (uint8_t *) &msg, sizeof(msg));
        ztimer_sleep(ZTIMER_MSEC, 1000);
   }
#endif

    return 0;
}

To monitor the behavior use a logic analyzer and add this:

gpio_set(TX_PIN);
ztimer_sleep(ZTIMER_MSEC, 1);
gpio_clear(TX_PIN);

to the following code part:

sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c

before line 398. Add this:

gpio_set(RX_PIN);
ztimer_sleep(ZTIMER_MSEC, 1);
gpio_clear(RX_PIN);

to

sys/net/gnrc/netif/gnrc_netif.c

after line 2085 and add this:

case NETDEV_EVENT_RX_STARTED:
    gpio_set(RX_PIN);
    ztimer_sleep(ZTIMER_MSEC, 1);
    gpio_clear(RX_PIN);
    
    break;

to

sys/net/gnrc/netif/gnrc_netif.c

before the NETDEV_EVENT_RX_COMPLETE case.

Expected results

Expected_result

Thats how it should look like; The RXAM interrupt occurs, if the valid PHR has been received and after the PSDU has been received, the RXFE interrupt occurs.

Actual results

Actual_results

The reason why both interrupts are called one after the other is that the RXAM interrupt does not occur, but the bit is set. When the RXFE interrupt occurs, the RXAM bit is still set.

Versions

Operating system: Ubuntu 20.04.6 LTS (Focal Fossa)
Build environment:

  • arm-none-eabi-gcc: arm-none-eabi-gcc (15:9-2019-q4-0ubuntu1) 9.2.1 20191025 (release) [ARM/arm-9-branch revision 277599]
  • gcc: gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant