Add new user_irq claim APIs to make it easier for independent code using them to interoperate (#854)

This commit is contained in:
Graham Sanderson 2022-06-07 14:27:38 -05:00 committed by GitHub
parent f3c446ae14
commit d3dcbb8292
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 112 additions and 6 deletions

View File

@ -21,6 +21,7 @@
#define NUM_DMA_CHANNELS _u(12)
#define NUM_DMA_TIMERS _u(4)
#define NUM_IRQS _u(32)
#define NUM_USER_IRQS _u(6)
#define NUM_PIOS _u(2)
#define NUM_PIO_STATE_MACHINES _u(4)
#define NUM_PWM_SLICES _u(8)

View File

@ -289,6 +289,69 @@ void irq_set_pending(uint num);
* \note This is an internal method and user should generally not call it.
*/
void irq_init_priorities(void);
/*! \brief Claim ownership of a user IRQ on the calling core
* \ingroup hardware_irq
*
* User IRQs are numbered 26-31 and are not connected to any hardware, but can be triggered by \ref irq_set_pending.
*
* \note User IRQs are a core local feature; they cannot be used to communicate between cores. Therfore all functions
* dealing with Uer IRQs affect only the calling core
*
* This method explicitly claims ownership of a user IRQ, so other code can know it is being used.
*
* \param irq_num the user IRQ to claim
*/
void user_irq_claim(uint irq_num);
/*! \brief Mark a user IRQ as no longer used on the calling core
* \ingroup hardware_irq
*
* User IRQs are numbered 26-31 and are not connected to any hardware, but can be triggered by \ref irq_set_pending.
*
* \note User IRQs are a core local feature; they cannot be used to communicate between cores. Therfore all functions
* dealing with Uer IRQs affect only the calling core
*
* This method explicitly releases ownership of a user IRQ, so other code can know it is free to use.
*
* \note it is customary to have disabled the irq and removed the handler prior to calling this method.
*
* \param irq_num the irq irq_num to unclaim
*/
void user_irq_unclaim(uint irq_num);
/*! \brief Claim ownership of a free user IRQ on the calling core
* \ingroup hardware_irq
*
* User IRQs are numbered 26-31 and are not connected to any hardware, but can be triggered by \ref irq_set_pending.
*
* \note User IRQs are a core local feature; they cannot be used to communicate between cores. Therfore all functions
* dealing with Uer IRQs affect only the calling core
*
* This method explicitly claims ownership of an unused user IRQ if there is one, so other code can know it is being used.
*
* \param required if true the function will panic if none are available
* \return the user IRQ number or -1 if required was false, and none were free
*/
int user_irq_claim_unused(bool required);
/*
*! \brief Check if a user IRQ is in use on the calling core
* \ingroup hardware_irq
*
* User IRQs are numbered 26-31 and are not connected to any hardware, but can be triggered by \ref irq_set_pending.
*
* \note User IRQs are a core local feature; they cannot be used to communicate between cores. Therfore all functions
* dealing with Uer IRQs affect only the calling core
*
* \param irq_num the irq irq_num
* \return true if the irq_num is claimed, false otherwise
* \sa user_irq_claim
* \sa user_irq_unclaim
* \sa user_irq_claim_unused
*/
bool user_irq_is_claimed(uint irq_num);
#ifdef __cplusplus
}
#endif

View File

@ -8,12 +8,15 @@
#include "hardware/regs/m0plus.h"
#include "hardware/platform_defs.h"
#include "hardware/structs/scb.h"
#include "hardware/claim.h"
#include "pico/mutex.h"
#include "pico/assert.h"
extern void __unhandled_user_irq(void);
static uint8_t user_irq_claimed[NUM_CORES];
static inline irq_handler_t *get_vtable(void) {
return (irq_handler_t *) scb_hw->vtor;
}
@ -410,3 +413,31 @@ void irq_init_priorities() {
}
#endif
}
#define FIRST_USER_IRQ (NUM_IRQS - NUM_USER_IRQS)
static uint get_user_irq_claim_index(uint irq_num) {
invalid_params_if(IRQ, irq_num < FIRST_USER_IRQ || irq_num >= NUM_IRQS);
// we count backwards from the last, to match the existing hard coded uses of user IRQs in the SDK which were previously using 31
static_assert(NUM_IRQS - FIRST_USER_IRQ <= 8, ""); // we only use a single byte's worth of claim bits today.
return NUM_IRQS - irq_num - 1u;
}
void user_irq_claim(uint irq_num) {
hw_claim_or_assert(&user_irq_claimed[get_core_num()], get_user_irq_claim_index(irq_num), "User IRQ is already claimed");
}
void user_irq_unclaim(uint irq_num) {
hw_claim_clear(&user_irq_claimed[get_core_num()], get_user_irq_claim_index(irq_num));
}
int user_irq_claim_unused(bool required) {
int bit = hw_claim_unused_from_range(&user_irq_claimed[get_core_num()], required, 0, NUM_USER_IRQS - 1, "No user IRQs are available");
if (bit >= 0) bit = (int)NUM_IRQS - bit - 1;
return bit;
}
bool user_irq_is_claimed(uint irq_num) {
return hw_is_claimed(&user_irq_claimed[get_core_num()], get_user_irq_claim_index(irq_num));
}

View File

@ -39,9 +39,9 @@
#define PICO_STDIO_USB_TASK_INTERVAL_US 1000
#endif
// PICO_CONFIG: PICO_STDIO_USB_LOW_PRIORITY_IRQ, low priority (non hardware) IRQ number to claim for tud_task() background execution, default=31, advanced=true, group=pico_stdio_usb
// PICO_CONFIG: PICO_STDIO_USB_LOW_PRIORITY_IRQ, Explicit User IRQ number to claim for tud_task() background execution instead of letting the implementation pick a free one dynamically (deprecated), advanced=true, group=pico_stdio_usb
#ifndef PICO_STDIO_USB_LOW_PRIORITY_IRQ
#define PICO_STDIO_USB_LOW_PRIORITY_IRQ 31
// this variable is no longer set by default (one is claimed dynamically), but will be respected if specified
#endif
// PICO_CONFIG: PICO_STDIO_USB_ENABLE_RESET_VIA_BAUD_RATE, Enable/disable resetting into BOOTSEL mode if the host sets the baud rate to a magic value (PICO_STDIO_USB_RESET_MAGIC_BAUD_RATE), type=bool, default=1, group=pico_stdio_usb

View File

@ -13,7 +13,13 @@
#include "pico/mutex.h"
#include "hardware/irq.h"
static_assert(PICO_STDIO_USB_LOW_PRIORITY_IRQ > RTC_IRQ, ""); // note RTC_IRQ is currently the last one
#ifdef PICO_STDIO_USB_LOW_PRIORITY_IRQ
static_assert(PICO_STDIO_USB_LOW_PRIORITY_IRQ >= NUM_IRQS - NUM_USER_IRQS, "");
#define low_priority_irq_num PICO_STDIO_USB_LOW_PRIORITY_IRQ
#else
static uint8_t low_priority_irq_num;
#endif
static mutex_t stdio_usb_mutex;
static void low_priority_worker_irq(void) {
@ -27,7 +33,7 @@ static void low_priority_worker_irq(void) {
}
static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
irq_set_pending(PICO_STDIO_USB_LOW_PRIORITY_IRQ);
irq_set_pending(low_priority_irq_num);
return PICO_STDIO_USB_TASK_INTERVAL_US;
}
@ -96,8 +102,13 @@ bool stdio_usb_init(void) {
// initialize TinyUSB
tusb_init();
irq_set_exclusive_handler(PICO_STDIO_USB_LOW_PRIORITY_IRQ, low_priority_worker_irq);
irq_set_enabled(PICO_STDIO_USB_LOW_PRIORITY_IRQ, true);
#ifdef PICO_STDIO_USB_LOW_PRIORITY_IRQ
user_irq_claim(PICO_STDIO_USB_LOW_PRIORITY_IRQ);
#else
low_priority_irq_num = (uint8_t) user_irq_claim_unused(true);
#endif
irq_set_exclusive_handler(low_priority_irq_num, low_priority_worker_irq);
irq_set_enabled(low_priority_irq_num, true);
mutex_init(&stdio_usb_mutex);
bool rc = add_alarm_in_us(PICO_STDIO_USB_TASK_INTERVAL_US, timer_task, NULL, true);