I have a need to make use of GPIO interrupts in an EX driver for a radio transceiver that I'm working on, and I'm struggling to see the best way to go about that. Here are the approaches I've looked at:
1) Just write GPIO interrupts directly using hardware functionality. This is obviously wrong because then the EX driver won't be portable. It should depend on the other HAL modules only. It appears that EXT is the one to use - while I'm aware it's intended to do more than just GPIO interrupts, it does seem to have dominion over them.
2) Use the EXT module directly - that is, write an EXTConfig struct and call extStart from my EX driver. This is bad because it prevents the user of the EX driver from using the EXT driver, and also won't allow more than 1 EX driver to be used at a time.
3) Modify an already-running EXT module's config to add the required interrupts based on lines passed in with the config struct for the EX driver. This seemed like a good idea until I actually dug into the EXT module in more detail. Because of its abstraction of channels, there's not a 1-to-1 correspondence in EXT between channels and lines. So we can't say "channel 1 will be the FIFO Full line from the transceiver" because channel 1 might have been configured as something totally different already. We would need some kind of "extGetNextFreeChannel" to make this work.
4) Pass in an EXT channel (expchannel_t - and is that a typo by the way?) instead of, or in addition to, a line. This seems like an OK idea, and honestly I could even make it work, but only because I know from reading the low level driver sources that expchannel_t is always an integer type in current implementations. I'd have to violate the abstraction implied by the typedef to make this work. To expand further:
I could put fields like this in the transceiver driver's config struct:
Code: Select all
typedef struct {
...
/** @brief Channel to use to configure FIFO interrupt */
expchannel_t fifo_channel;
...
} txvrConfig;
And I could put this in the transceiver driver's Start function:
Code: Select all
void txvrStart(txvrDriver *devp, txvrConfig *config) {
...
/* Configure the FIFO interrupt channel */
extSetChannelMode(&EXTD1, config->fifo_channel, &fifo_channel_config);
...
}
But when initializing the transceiver config struct I would have to use something like this:
Code: Select all
txvrConfig default_config = {
...
15, /* fifo_channel */
...
}
and that feels like violating the abstraction. To make this work cleanly we would need some sort of extGetChannelByIndex(n) macro that in all existing cases just expands to n. Or we could drop the expchannel_t thing entirely and just pass around indexes instead of opaque identifiers.
5) Write the required interrupt callback functions in the EX driver and rely on the user to make sure they actually get set up in the EXT driver somewhere. I dislike this because it leaks out implementation details of the EX driver into user code.
After that big fat wall of text - are there better solutions to this problem? I dug around the forum somewhat and found a lengthy discussion here: viewtopic.php?f=3&t=3249&start=10 with no real resolution, as well as here: viewtopic.php?t=387&start=10 which proposed my solution #4 but still has the abstraction problem I discuss.
I think these kinds of problems are likely to continue to come up as we build out the EX project, it would be to all of our advantages to come up with a mutually acceptable way to solve them. For my money, my two favorites would be my solution #3, with the proposed extGetNextFreeChannel or similar, or rolling GPIO-specific interrupt functionality into the PAL (which is a major change) so that there is a 1-to-1 correspondence and I can use a line identifier to configure an interrupt on that line. Other opinions are of course actively sought, and obviously Giovanni it's ultimately your call.
Thanks for your time!