Shared SPI Bus with IRQ Architecture

ChibiOS public support forum for all topics not covered by a specific support forum.

Moderators: utzig, lbednarz, tfAteba, barthess, RoccoMarco

heliochronix
Posts: 34
Joined: Thu Aug 31, 2017 6:32 pm
Has thanked: 8 times
Been thanked: 6 times

Shared SPI Bus with IRQ Architecture

Postby heliochronix » Thu Sep 10, 2020 7:15 pm

Hello everyone,

I'm curious if anyone has experience with or knows what would be the "best practice" for implementing a driver for two devices on a shared SPI bus. Basically, I have two radio chips (AX5043) on one SPI bus, and I'm writing a ChibiOS style driver for them. Both chips provide an IRQ signal, and I'd like the driver to handle these with a "palcallback_t". The argument is the AX5043Driver struct, which contains an AX5043Config containing SPIDriver and SPIConfig, as shown (abbreviated) here:

Code: Select all

struct AX5043Driver {
   const struct AX5043Config *config;
   ...
};

struct AX5043Config {
   SPIDriver *spip;
   const SPIConfig *spicfg;
   ioline_t irq;
   ...
};


The issue I am running into is, there's no real way from the IRQ context of a "palcallback_t" to ensure I am initiating a SPI transaction using the correct SPIConfig and also "Acquiring" the bus from the interrupt context because I can't invoke "spiAcquireBus(spip);" and "spiStart(((AX5043Driver*)arg)->config->spip, ((AX5043Driver*)arg)->config->spicfg);" from this context.

Is there a best practice for implementing a shared SPI bus architecture when both devices share an IRQ handler callback? The ultimate goal is to receive data from the AX5043's IRQ register and handle it for the correct device.

User avatar
Giovanni
Site Admin
Posts: 13527
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 861 times
Been thanked: 743 times
Contact:

Re: Shared SPI Bus with IRQ Architecture

Postby Giovanni » Thu Sep 10, 2020 7:20 pm

Hi,

From the PAL callbacks you could wake up threads that would then handle the SPI as you described. It could also be a single thread that then decides which SPI config to use, no need to do spiAcquireBus() in this case.

Giovanni

heliochronix
Posts: 34
Joined: Thu Aug 31, 2017 6:32 pm
Has thanked: 8 times
Been thanked: 6 times

Re: Shared SPI Bus with IRQ Architecture

Postby heliochronix » Thu Sep 10, 2020 7:24 pm

Okay, so I should implement a driver worker that handles this basically. Makes sense. I can probably incorporate the dispatch code into that as well. Thank you for the advice!

heliochronix
Posts: 34
Joined: Thu Aug 31, 2017 6:32 pm
Has thanked: 8 times
Been thanked: 6 times

Re: Shared SPI Bus with IRQ Architecture

Postby heliochronix » Mon Sep 14, 2020 5:53 pm

Hello again,

I'm continuing work on this implementation, and I'm trying to understand the Events system to see if I can leverage it to wake up the appropriate threads via an event, but I think I might be missing something.

Basically, as it currently stands I have the following IRQ related code, and I'm trying to determine the best way to signal all threads that are waiting on a particular IRQ:

Code: Select all

/**
 * @brief   Interrupt handler for AX5043 IRQ signals.
 *
 * @param[in]   arg         Pointer to the @p AX5043Driver object
 *
 * @notapi
 */
void ax5043IRQHandler(void *arg) {
    AX5043Driver *devp = arg;

    osalDbgCheck(devp != NULL, devp->irq_worker != NULL);

    chSysLockFromISR();
    chEvtSignalI(devp->irq_worker, EVENT_MASK(0));
    chSysUnlockFromISR();
}

/**
 * @brief   Interrupt worker thread for AX5043 IRQ signals.
 *
 * @param[in]   arg         Pointer to the @p AX5043Driver object
 *
 * @notapi
 */
THD_WORKING_AREA(irq_wa, 0x100);
THD_FUNCTION(irq_worker, arg) {
    AX5043Driver *devp = arg;
    eventmask_t irq = 0;

    osalDbgCheck(devp != NULL);

    while (!chThdShouldTerminateX()) {
        chEvtWaitAny(ALL_EVENTS);

        /* Retrieve the pending interrupt requests */
        irq = ax5043ReadU16(devp, AX5043_REG_IRQREQUEST);

        /* Signal all waiting threads with pending interrupts */
        /*chEvt...(&devp->irq_event, irq);*/
    }
    chThdExit(MSG_OK);
}


My initial thought was that I could simply register a thread on a particular interrupt, like the following...

Code: Select all

...
event_listener_t el;
chEvtRegisterMask(&devp->irq_event, &el, AX5043_IRQ_FIFONOTEMPTY);
chEvtWaitAll(ALL_EVENTS);
chEvtUnregister(&devp->irq_event, &el);
...

but then I realized there is no chEvtBroadcast for event masks, only for event flags. Should I not be using event masks in this way? Would event flags be better, or am I misunderstanding some fundamental aspect of how the Events system is meant to work or be used?

User avatar
Giovanni
Site Admin
Posts: 13527
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 861 times
Been thanked: 743 times
Contact:

Re: Shared SPI Bus with IRQ Architecture

Postby Giovanni » Mon Sep 14, 2020 6:24 pm

Hi,

There are two ways to use events:

1) You signal directly a thread, no registration, the two parts know each other. There are no flags here, just event masks, your thread waits for one or more events in the "mask".
2) You have an "event source" where one or more threads may or may not register on. This is more indirect and you can have "flags" associated to the listener, the event carries some extra information, those flags.

You should use the scenario 1, your code does that. In addition, you could also use other mechanisms to wake up a thread, some are described here: http://www.chibios.org/dokuwiki/doku.ph ... tos:wakeup

In addition there are also semaphores, message boxes, etc. I would use a semaphore initialized to zero, your thread waits on the semahore, the ISR resets it waking up the thread, there is also an option to pass a message on reset.

Giovanni


Return to “General Support”

Who is online

Users browsing this forum: No registered users and 2 guests