Add new user_irq claim APIs to make it easier for independent code using them to interoperate (#854)
This commit is contained in:
parent
f3c446ae14
commit
d3dcbb8292
@ -21,6 +21,7 @@
|
|||||||
#define NUM_DMA_CHANNELS _u(12)
|
#define NUM_DMA_CHANNELS _u(12)
|
||||||
#define NUM_DMA_TIMERS _u(4)
|
#define NUM_DMA_TIMERS _u(4)
|
||||||
#define NUM_IRQS _u(32)
|
#define NUM_IRQS _u(32)
|
||||||
|
#define NUM_USER_IRQS _u(6)
|
||||||
#define NUM_PIOS _u(2)
|
#define NUM_PIOS _u(2)
|
||||||
#define NUM_PIO_STATE_MACHINES _u(4)
|
#define NUM_PIO_STATE_MACHINES _u(4)
|
||||||
#define NUM_PWM_SLICES _u(8)
|
#define NUM_PWM_SLICES _u(8)
|
||||||
|
@ -289,6 +289,69 @@ void irq_set_pending(uint num);
|
|||||||
* \note This is an internal method and user should generally not call it.
|
* \note This is an internal method and user should generally not call it.
|
||||||
*/
|
*/
|
||||||
void irq_init_priorities(void);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,12 +8,15 @@
|
|||||||
#include "hardware/regs/m0plus.h"
|
#include "hardware/regs/m0plus.h"
|
||||||
#include "hardware/platform_defs.h"
|
#include "hardware/platform_defs.h"
|
||||||
#include "hardware/structs/scb.h"
|
#include "hardware/structs/scb.h"
|
||||||
|
#include "hardware/claim.h"
|
||||||
|
|
||||||
#include "pico/mutex.h"
|
#include "pico/mutex.h"
|
||||||
#include "pico/assert.h"
|
#include "pico/assert.h"
|
||||||
|
|
||||||
extern void __unhandled_user_irq(void);
|
extern void __unhandled_user_irq(void);
|
||||||
|
|
||||||
|
static uint8_t user_irq_claimed[NUM_CORES];
|
||||||
|
|
||||||
static inline irq_handler_t *get_vtable(void) {
|
static inline irq_handler_t *get_vtable(void) {
|
||||||
return (irq_handler_t *) scb_hw->vtor;
|
return (irq_handler_t *) scb_hw->vtor;
|
||||||
}
|
}
|
||||||
@ -410,3 +413,31 @@ void irq_init_priorities() {
|
|||||||
}
|
}
|
||||||
#endif
|
#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));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -39,9 +39,9 @@
|
|||||||
#define PICO_STDIO_USB_TASK_INTERVAL_US 1000
|
#define PICO_STDIO_USB_TASK_INTERVAL_US 1000
|
||||||
#endif
|
#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
|
#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
|
#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
|
// 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
|
||||||
|
@ -13,7 +13,13 @@
|
|||||||
#include "pico/mutex.h"
|
#include "pico/mutex.h"
|
||||||
#include "hardware/irq.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 mutex_t stdio_usb_mutex;
|
||||||
|
|
||||||
static void low_priority_worker_irq(void) {
|
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) {
|
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;
|
return PICO_STDIO_USB_TASK_INTERVAL_US;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,8 +102,13 @@ bool stdio_usb_init(void) {
|
|||||||
// initialize TinyUSB
|
// initialize TinyUSB
|
||||||
tusb_init();
|
tusb_init();
|
||||||
|
|
||||||
irq_set_exclusive_handler(PICO_STDIO_USB_LOW_PRIORITY_IRQ, low_priority_worker_irq);
|
#ifdef PICO_STDIO_USB_LOW_PRIORITY_IRQ
|
||||||
irq_set_enabled(PICO_STDIO_USB_LOW_PRIORITY_IRQ, true);
|
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);
|
mutex_init(&stdio_usb_mutex);
|
||||||
bool rc = add_alarm_in_us(PICO_STDIO_USB_TASK_INTERVAL_US, timer_task, NULL, true);
|
bool rc = add_alarm_in_us(PICO_STDIO_USB_TASK_INTERVAL_US, timer_task, NULL, true);
|
||||||
|
Loading…
Reference in New Issue
Block a user