generic interrupt registry
ci / Check formatting (push) Has been cancelled
ci / Check Documentation Build (push) Has been cancelled
ci / Clippy (push) Has been cancelled
ci / Check formatting (pull_request) Has been cancelled
ci / Check Documentation Build (pull_request) Has been cancelled
ci / Clippy (pull_request) Has been cancelled
ci / Check build (push) Has been cancelled
ci / Check build (pull_request) Has been cancelled

This commit is contained in:
2026-05-08 16:28:18 +02:00
parent 8f6200cf63
commit 0a29b8cec4
24 changed files with 137 additions and 147 deletions
@@ -13,7 +13,7 @@ use zynq7000_hal::{
BootMode,
clocks::Clocks,
generic_interrupt_handler,
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gic::Configurator,
gpio::{Flex, Output, PinState, mio},
gtc::GlobalTimerCounter,
l2_cache,
@@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) -> ! {
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller.
let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd);
let mut gic = Configurator::new_with_init(dp.gicc, dp.gicd);
gic.enable_all_interrupts();
gic.set_all_spi_interrupt_targets_cpu0();
gic.enable();
@@ -8,7 +8,9 @@ use embassy_time::{Duration, Ticker};
use embedded_hal::digital::StatefulOutputPin;
use embedded_io::Write;
use log::{error, info};
use zynq7000_hal::{BootMode, InteruptConfig, clocks, gic, gpio, gtc, time::Hertz, uart};
use zynq7000_hal::{
BootMode, InteruptConfig, clocks, generic_interrupt_handler, gpio, gtc, time::Hertz, uart,
};
use zynq7000_rt as _;
@@ -71,23 +73,12 @@ async fn main(_spawner: Spawner) -> ! {
}
#[zynq7000_rt::irq]
fn irq_handler() {
let mut gic_helper = gic::GicInterruptHelper::new();
let irq_info = gic_helper.acknowledge_interrupt();
match irq_info.interrupt() {
gic::Interrupt::Sgi(_) => (),
gic::Interrupt::Ppi(ppi_interrupt) => {
if ppi_interrupt == zynq7000_hal::gic::PpiInterrupt::GlobalTimer {
unsafe {
zynq7000_embassy::on_interrupt();
}
}
}
gic::Interrupt::Spi(_spi_interrupt) => (),
gic::Interrupt::Invalid(_) => (),
gic::Interrupt::Spurious => (),
pub fn irq_handler() {
// Safety: Called here once.
let result = unsafe { generic_interrupt_handler() };
if let Err(e) = result {
panic!("Generic interrupt handler failed handling {:?}", e);
}
gic_helper.end_of_interrupt(irq_info);
}
#[zynq7000_rt::exception(DataAbort)]
@@ -14,12 +14,12 @@ use zynq7000_hal::{
BootMode,
clocks::Clocks,
generic_interrupt_handler,
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gic::Configurator,
gpio::{Output, PinState, mio},
gtc::GlobalTimerCounter,
l2_cache,
time::Hertz,
uart::{ClockConfig, Config, TxAsync, Uart, on_interrupt_tx},
uart::{ClockConfig, Config, TxAsync, Uart},
};
use zynq7000_rt as _;
@@ -41,7 +41,7 @@ async fn main(spawner: Spawner) -> ! {
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller.
let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd);
let mut gic = Configurator::new_with_init(dp.gicc, dp.gicd);
gic.enable_all_interrupts();
gic.set_all_spi_interrupt_targets_cpu0();
gic.enable();
+2 -2
View File
@@ -19,7 +19,7 @@ use zynq7000_hal::{
BootMode,
clocks::Clocks,
generic_interrupt_handler,
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gic::Configurator,
gpio::{Output, PinState, mio},
gtc::GlobalTimerCounter,
l2_cache,
@@ -47,7 +47,7 @@ async fn main(_spawner: Spawner) -> ! {
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller.
let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd);
let mut gic = Configurator::new_with_init(dp.gicc, dp.gicd);
gic.enable_all_interrupts();
gic.set_all_spi_interrupt_targets_cpu0();
gic.enable();
+1 -3
View File
@@ -7,9 +7,7 @@ use embassy_executor::Spawner;
use embassy_time::{Duration, Ticker};
use embedded_hal::digital::StatefulOutputPin;
use log::error;
use zynq7000_hal::{
InteruptConfig, clocks, generic_interrupt_handler, gic, gpio, gtc, time::Hertz,
};
use zynq7000_hal::{InteruptConfig, clocks, generic_interrupt_handler, gpio, gtc, time::Hertz};
// Define the clock frequency as a constant
const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300);
@@ -8,8 +8,9 @@ use embedded_hal::digital::StatefulOutputPin;
use embedded_io::Write;
use log::{error, info};
use zynq7000_hal::{
Interrupt,
clocks::Clocks,
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gic,
gpio::{Output, PinState, mio},
gtc::GlobalTimerCounter,
l2_cache,
@@ -31,7 +32,7 @@ fn main() -> ! {
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller.
let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd);
let mut gic = gic::Configurator::new_with_init(dp.gicc, dp.gicd);
gic.enable_all_interrupts();
gic.set_all_spi_interrupt_targets_cpu0();
gic.enable();
@@ -83,8 +84,8 @@ fn main() -> ! {
#[zynq7000_rt::irq]
fn irq_handler() {
let mut gic_helper = GicInterruptHelper::new();
let irq_info = gic_helper.acknowledge_interrupt();
let mut gic_helper = gic::InterruptGuard::new();
let irq_info = gic_helper.interrupt_info();
match irq_info.interrupt() {
Interrupt::Sgi(_) => (),
Interrupt::Ppi(ppi_interrupt) => {
+4 -4
View File
@@ -10,7 +10,7 @@ use log::{error, info};
use zynq7000_hal::{
BootMode,
clocks::Clocks,
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gic::{self, Configurator, Interrupt},
gpio::{Output, PinState, mio},
gtc::GlobalTimerCounter,
l2_cache,
@@ -32,7 +32,7 @@ fn main() -> ! {
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller.
let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd);
let mut gic = Configurator::new_with_init(dp.gicc, dp.gicd);
gic.enable_all_interrupts();
gic.set_all_spi_interrupt_targets_cpu0();
gic.enable();
@@ -85,8 +85,8 @@ fn main() -> ! {
#[zynq7000_rt::irq]
fn irq_handler() {
let mut gic_helper = GicInterruptHelper::new();
let irq_info = gic_helper.acknowledge_interrupt();
let mut gic_helper = gic::InterruptGuard::new();
let irq_info = gic_helper.interrupt_info();
match irq_info.interrupt() {
Interrupt::Sgi(_) => (),
Interrupt::Ppi(ppi_interrupt) => {
@@ -43,7 +43,7 @@ use zynq7000_hal::{
AlignedBuffer, ClockDivSet, EthernetConfig, EthernetLowLevel, embassy_net::InterruptResult,
},
generic_interrupt_handler,
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
gic::{Configurator, Interrupt},
gpio::{GpioPins, Output, PinState},
gtc::GlobalTimerCounter,
l2_cache,
@@ -217,7 +217,7 @@ async fn main(spawner: Spawner) -> ! {
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller.
let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd);
let mut gic = Configurator::new_with_init(dp.gicc, dp.gicd);
gic.enable_all_interrupts();
gic.set_all_spi_interrupt_targets_cpu0();
gic.enable();
@@ -21,7 +21,7 @@ use zynq7000_hal::{
BootMode,
clocks::Clocks,
configure_level_shifter, generic_interrupt_handler,
gic::GicConfigurator,
gic::Configurator,
gpio::{GpioPins, Output, PinState},
gtc::GlobalTimerCounter,
i2c, l2_cache,
@@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) -> ! {
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller.
let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd);
let mut gic = Configurator::new_with_init(dp.gicc, dp.gicd);
gic.enable_all_interrupts();
gic.set_all_spi_interrupt_targets_cpu0();
gic.enable();
@@ -22,7 +22,7 @@ use zynq7000_hal::{
BootMode,
clocks::Clocks,
configure_level_shifter, generic_interrupt_handler,
gic::GicConfigurator,
gic::Configurator,
gpio::{GpioPins, Output, PinState},
gtc::GlobalTimerCounter,
l2_cache,
@@ -70,7 +70,7 @@ async fn main(spawner: Spawner) -> ! {
);
// Set up the global interrupt controller.
let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd);
let mut gic = Configurator::new_with_init(dp.gicc, dp.gicd);
gic.enable_all_interrupts();
gic.set_all_spi_interrupt_targets_cpu0();
gic.enable();
@@ -16,7 +16,7 @@ use log::{error, info};
use ssd1306::{Ssd1306Async, prelude::*};
use zedboard::PS_CLOCK_FREQUENCY;
use zynq7000_hal::{
BootMode, clocks, generic_interrupt_handler, gic, gpio, gtc,
BootMode, clocks, generic_interrupt_handler, gpio, gtc,
spi::{self, SpiAsync},
time::Hertz,
uart::{self, TxAsync},
+1 -1
View File
@@ -16,7 +16,7 @@ use log::{error, info};
use ssd1306::{Ssd1306, prelude::*};
use zedboard::PS_CLOCK_FREQUENCY;
use zynq7000_hal::{
BootMode, clocks, generic_interrupt_handler, gic, gpio, gtc, spi,
BootMode, clocks, generic_interrupt_handler, gpio, gtc, spi,
time::Hertz,
uart::{self, TxAsync},
};
+1 -1
View File
@@ -12,7 +12,7 @@ use log::{error, info};
use zedboard::PS_CLOCK_FREQUENCY;
use zedboard_bsp::qspi_spansion;
use zynq7000_hal::{
BootMode, clocks, generic_interrupt_handler, gic, gpio, gtc, prelude::*, qspi, uart,
BootMode, clocks, generic_interrupt_handler, gpio, gtc, prelude::*, qspi, uart,
};
use zynq7000_rt as _;
+7 -18
View File
@@ -10,9 +10,9 @@ use embedded_io::Write;
use log::error;
use zedboard::PS_CLOCK_FREQUENCY;
use zynq7000_hal::gpio::Input;
use zynq7000_hal::prelude::*;
use zynq7000_hal::sd::SdClockConfig;
use zynq7000_hal::{BootMode, clocks, gic, gpio, gtc, sd::SdCardUninit, uart};
use zynq7000_hal::{BootMode, clocks, gpio, gtc, sd::SdCardUninit, uart};
use zynq7000_hal::{generic_interrupt_handler, prelude::*};
use zynq7000_rt as _;
@@ -227,23 +227,12 @@ async fn main(_spawner: Spawner) -> ! {
}
#[zynq7000_rt::irq]
fn irq_handler() {
let mut gic_helper = gic::GicInterruptHelper::new();
let irq_info = gic_helper.acknowledge_interrupt();
match irq_info.interrupt() {
gic::Interrupt::Sgi(_) => (),
gic::Interrupt::Ppi(ppi_interrupt) => {
if ppi_interrupt == gic::PpiInterrupt::GlobalTimer {
unsafe {
zynq7000_embassy::on_interrupt();
}
}
}
gic::Interrupt::Spi(_spi_interrupt) => (),
gic::Interrupt::Invalid(_) => (),
gic::Interrupt::Spurious => (),
pub fn irq_handler() {
// Safety: Called here once.
let result = unsafe { generic_interrupt_handler() };
if let Err(e) = result {
panic!("Generic interrupt handler failed handling {:?}", e);
}
gic_helper.end_of_interrupt(irq_info);
}
#[zynq7000_rt::exception(DataAbort)]
@@ -14,8 +14,7 @@ use zedboard::PS_CLOCK_FREQUENCY;
use zynq7000_hal::{
BootMode,
clocks::Clocks,
configure_level_shifter,
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
configure_level_shifter, generic_interrupt_handler, gic,
gpio::{GpioPins, Output, PinState},
gtc::GlobalTimerCounter,
l2_cache,
@@ -104,7 +103,7 @@ async fn main(_spawner: Spawner) -> ! {
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller.
let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd);
let mut gic = gic::Configurator::new_with_init(dp.gicc, dp.gicd);
gic.enable_all_interrupts();
gic.set_all_spi_interrupt_targets_cpu0();
gic.enable();
@@ -215,23 +214,12 @@ async fn main(_spawner: Spawner) -> ! {
}
#[zynq7000_rt::irq]
fn irq_handler() {
let mut gic_helper = GicInterruptHelper::new();
let irq_info = gic_helper.acknowledge_interrupt();
match irq_info.interrupt() {
Interrupt::Sgi(_) => (),
Interrupt::Ppi(ppi_interrupt) => {
if ppi_interrupt == zynq7000_hal::gic::PpiInterrupt::GlobalTimer {
unsafe {
zynq7000_embassy::on_interrupt();
}
}
}
Interrupt::Spi(_spi_interrupt) => (),
Interrupt::Invalid(_) => (),
Interrupt::Spurious => (),
pub fn irq_handler() {
// Safety: Called here once.
let result = unsafe { generic_interrupt_handler() };
if let Err(e) = result {
panic!("Generic interrupt handler failed handling {:?}", e);
}
gic_helper.end_of_interrupt(irq_info);
}
#[zynq7000_rt::exception(DataAbort)]
@@ -42,7 +42,7 @@ use zynq7000_hal::{
BootMode,
clocks::Clocks,
configure_level_shifter, generic_interrupt_handler,
gic::{GicConfigurator, Interrupt},
gic::{Configurator, Interrupt},
gpio::{GpioPins, Output, PinState},
gtc::GlobalTimerCounter,
l2_cache,
@@ -171,7 +171,7 @@ async fn main(spawner: Spawner) -> ! {
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up the global interrupt controller.
let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd);
let mut gic = Configurator::new_with_init(dp.gicc, dp.gicd);
gic.enable_all_interrupts();
gic.set_all_spi_interrupt_targets_cpu0();
// AXI UARTLite documentation mentions that a rising-edge sensitive interrupt is generated,
+6 -17
View File
@@ -9,7 +9,7 @@ use embedded_hal::digital::StatefulOutputPin;
use embedded_io::Write;
use log::{error, info};
use zedboard::PS_CLOCK_FREQUENCY;
use zynq7000_hal::{BootMode, clocks, gic, gpio, gtc, uart};
use zynq7000_hal::{BootMode, clocks, generic_interrupt_handler, gpio, gtc, uart};
use zynq7000_rt as _;
@@ -88,23 +88,12 @@ async fn main(_spawner: Spawner) -> ! {
}
#[zynq7000_rt::irq]
fn irq_handler() {
let mut gic_helper = gic::GicInterruptHelper::new();
let irq_info = gic_helper.acknowledge_interrupt();
match irq_info.interrupt() {
gic::Interrupt::Sgi(_) => (),
gic::Interrupt::Ppi(ppi_interrupt) => {
if ppi_interrupt == gic::PpiInterrupt::GlobalTimer {
unsafe {
zynq7000_embassy::on_interrupt();
}
}
}
gic::Interrupt::Spi(_spi_interrupt) => (),
gic::Interrupt::Invalid(_) => (),
gic::Interrupt::Spurious => (),
pub fn irq_handler() {
// Safety: Called here once.
let result = unsafe { generic_interrupt_handler() };
if let Err(e) = result {
panic!("Generic interrupt handler failed handling {:?}", e);
}
gic_helper.end_of_interrupt(irq_info);
}
#[zynq7000_rt::exception(DataAbort)]
+7 -18
View File
@@ -17,7 +17,7 @@ use log::{error, info};
use zedboard_bsp::qspi_spansion::{self, QspiSpansionS25Fl256SLinearMode};
use zynq7000_boot_image::DestinationDevice;
use zynq7000_hal::clocks::ArmClocks;
use zynq7000_hal::priv_tim;
use zynq7000_hal::{generic_interrupt_handler, priv_tim};
use zynq7000_hal::{
BootMode,
clocks::{
@@ -119,7 +119,7 @@ fn main() -> ! {
};
// Set up the global interrupt controller.
let mut gic = gic::GicConfigurator::new_with_init(periphs.gicc, periphs.gicd);
let mut gic = gic::Configurator::new_with_init(periphs.gicc, periphs.gicd);
gic.enable_all_interrupts();
gic.set_all_spi_interrupt_targets_cpu0();
gic.enable();
@@ -353,23 +353,12 @@ fn qspi_boot(mut qspi: QspiSpansionS25Fl256SLinearMode, _priv_tim: priv_tim::Cpu
}
#[zynq7000_rt::irq]
fn interrupt_handler() {
let mut gic_helper = gic::GicInterruptHelper::new();
let irq_info = gic_helper.acknowledge_interrupt();
match irq_info.interrupt() {
gic::Interrupt::Sgi(_) => (),
gic::Interrupt::Ppi(ppi_interrupt) => {
log::warn!("unexpected PPI interrupt: {:?}", ppi_interrupt);
}
gic::Interrupt::Spi(spi_interrupt) => {
log::warn!("unexpected SPI interrupt: {:?}", spi_interrupt);
}
gic::Interrupt::Invalid(_) => (),
gic::Interrupt::Spurious => {
log::warn!("spurious interrupt");
}
pub fn irq_handler() {
// Safety: Called here once.
let result = unsafe { generic_interrupt_handler() };
if let Err(e) = result {
log::warn!("Generic interrupt handler failed handling {:?}", e);
}
gic_helper.end_of_interrupt(irq_info);
}
#[zynq7000_rt::exception(DataAbort)]
+5
View File
@@ -28,12 +28,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
respectively.
- `log::rb` module replaced by `log::asynch` module which uses an asynchronous embassy pipe
for logging.
- GIC data structures: Removed the `Gic` prefix which already is part of the module name.
- Renamed `GicInterruptHelper` to `InterruptGuard`. It acknowledges the end of interrupts on drop.
## Added
- Method to de-assert PL reset.
- ARM clock initialization for the `ArmClocks` structure
- The `ArmClocks` structure now caches the CPU clock ratio
- New generic interrupt registry and generic interrupt handler which uses the registry.
Primary interface is the `crate::generic_interrupt_handler` function and the
`crate::register_interrupt` function.
# [v0.1.1] 2025-10-10
+47 -16
View File
@@ -1,7 +1,10 @@
//! # Global Interrupt Controller (GIC) module
//!
//! The primary interface to configure and allow handling the interrupts are the
//! [GicConfigurator] and the [GicInterruptHelper] structures.
//! [Configurator] and the [InterruptGuard] structures.
//!
//! The HAL provides a more convenient interface through the [crate::register_interrupt] and
//! [crate::generic_interrupt_handler] functions.
#![deny(missing_docs)]
use arbitrary_int::prelude::*;
@@ -250,8 +253,9 @@ pub enum Interrupt {
}
/// Interrupt information structure.
#[derive(Debug)]
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InterruptInfo {
raw_reg: InterruptSignalRegister,
interrupt: Interrupt,
@@ -337,16 +341,16 @@ pub struct InvalidSgiInterruptId(pub usize);
/// with [Self::enable] which assumes a certain configuration.
/// 5. Enable interrupts for the Cortex-A core by calling [Self::enable_interrupts].
///
/// For the handling of the interrupts, you can use the [GicInterruptHelper] which assumes a
/// For the handling of the interrupts, you can use the [InterruptGuard] which assumes a
/// properly configured GIC.
pub struct GicConfigurator {
pub struct Configurator {
/// GIC CPU interface registers.
pub gicc: MmioCpuInterfaceRegisters<'static>,
/// GIC Distributor interface registers.
pub gicd: MmioDistributorRegisters<'static>,
}
impl GicConfigurator {
impl Configurator {
/// Create a new GIC controller instance and calls [Self::initialize] to perform
/// strongly recommended initialization routines for the GIC.
#[inline]
@@ -354,7 +358,7 @@ impl GicConfigurator {
gicc: MmioCpuInterfaceRegisters<'static>,
gicd: MmioDistributorRegisters<'static>,
) -> Self {
let mut gic = GicConfigurator { gicc, gicd };
let mut gic = Configurator { gicc, gicd };
gic.initialize();
gic
}
@@ -368,7 +372,7 @@ impl GicConfigurator {
/// used inside the interrupt handler.
#[inline]
pub unsafe fn steal() -> Self {
GicConfigurator {
Configurator {
gicc: unsafe { CpuInterfaceRegisters::new_mmio_fixed() },
gicd: unsafe { DistributorRegisters::new_mmio_fixed() },
}
@@ -651,21 +655,31 @@ impl GicConfigurator {
}
/// Helper structure which should only be used inside the interrupt handler once the GIC has
/// been configured with the [GicConfigurator].
pub struct GicInterruptHelper(MmioCpuInterfaceRegisters<'static>);
/// been configured with the [Configurator].
pub struct InterruptGuard {
regs: MmioCpuInterfaceRegisters<'static>,
interrupt_info: InterruptInfo,
acknowledged: bool,
}
impl GicInterruptHelper {
impl InterruptGuard {
/// Create the interrupt helper with the fixed GICC MMIO instance.
pub const fn new() -> Self {
GicInterruptHelper(unsafe { CpuInterfaceRegisters::new_mmio_fixed() })
pub fn new() -> Self {
let mut regs = unsafe { CpuInterfaceRegisters::new_mmio_fixed() };
let interrupt_info = Self::acknowledge_interrupt(&mut regs);
InterruptGuard {
regs: unsafe { CpuInterfaceRegisters::new_mmio_fixed() },
interrupt_info,
acknowledged: false,
}
}
/// Acknowledges an interrupt by reading the IAR register and returning the interrupt context
/// information structure.
///
/// This should be called at the start of an interrupt handler.
pub fn acknowledge_interrupt(&mut self) -> InterruptInfo {
let iar = self.0.read_iar();
fn acknowledge_interrupt(regs: &mut MmioCpuInterfaceRegisters<'static>) -> InterruptInfo {
let iar = regs.read_iar();
let int_id = iar.ack_int_id().as_u32();
let interrupt = match int_id {
0..=15 => Interrupt::Sgi(int_id as usize),
@@ -681,16 +695,33 @@ impl GicInterruptHelper {
}
}
/// Returns the interrupt information structure which was read from the IAR register.
///
/// This is used to determine the cause of the interrupt.
#[inline]
pub fn interrupt_info(&self) -> InterruptInfo {
self.interrupt_info
}
/// Acknowledges the end of an interrupt by writing the EOIR register of the GICC.
///
/// This should be called at the end of an interrupt handler.
pub fn end_of_interrupt(&mut self, irq_info: InterruptInfo) {
self.0.write_eoir(irq_info.raw_reg())
self.acknowledged = true;
self.regs.write_eoir(irq_info.raw_reg())
}
}
impl Default for GicInterruptHelper {
impl Default for InterruptGuard {
fn default() -> Self {
Self::new()
}
}
impl Drop for InterruptGuard {
fn drop(&mut self) {
if !self.acknowledged {
self.regs.write_eoir(self.interrupt_info.raw_reg());
}
}
}
+15 -10
View File
@@ -1,12 +1,17 @@
use crate::gic::{GicInterruptHelper, Interrupt};
use crate::gic::{Interrupt, InterruptGuard};
static INTERRUPT_MAP: critical_section::Mutex<
core::cell::RefCell<heapless::index_map::FnvIndexMap<Interrupt, unsafe fn(), 128>>,
> = critical_section::Mutex::new(core::cell::RefCell::new(
heapless::index_map::FnvIndexMap::new(),
));
pub type InterruptMap = heapless::index_map::FnvIndexMap<Interrupt, unsafe fn(), 128>;
static INTERRUPT_MAP: critical_section::Mutex<core::cell::RefCell<InterruptMap>> =
critical_section::Mutex::new(core::cell::RefCell::new(
heapless::index_map::FnvIndexMap::new(),
));
/// Register an interrupt handler for a specific [Interrupt].
///
/// It should be noted that the current implementation only allows one function for each interrupts.
/// If the HAL provided interrupt handler does not fulfill all your requirements, you need
/// to define your own interrupt handler and register it.
/// For example, you might need to handle both UART RX and TX, and the HAL handler only handles TX.
pub fn register_interrupt(interrupt: Interrupt, handler: unsafe fn()) {
critical_section::with(|cs| {
let mut map = INTERRUPT_MAP.borrow(cs).borrow_mut();
@@ -25,11 +30,11 @@ pub fn register_interrupt(interrupt: Interrupt, handler: unsafe fn()) {
/// This needs to be called ONCE in the interrupt handler function, which is any function annotated
/// with the `irq` attribute provided by `aarch32-rt`.
pub unsafe fn generic_interrupt_handler() -> Result<(), Interrupt> {
let mut gic_helper = GicInterruptHelper::new();
let irq_info = gic_helper.acknowledge_interrupt();
let mut gic_guard = InterruptGuard::new();
let irq_info = gic_guard.interrupt_info();
let interrupt = irq_info.interrupt();
if let Interrupt::Invalid(_) = interrupt {
gic_helper.end_of_interrupt(irq_info);
gic_guard.end_of_interrupt(irq_info);
return Err(interrupt);
}
let opt_interrupt_handler = critical_section::with(|cs| {
@@ -43,7 +48,7 @@ pub unsafe fn generic_interrupt_handler() -> Result<(), Interrupt> {
interrupt_handler();
}
}
gic_helper.end_of_interrupt(irq_info);
gic_guard.end_of_interrupt(irq_info);
opt_interrupt_handler.ok_or(interrupt)?;
Ok(())
}
+2 -2
View File
@@ -10,7 +10,7 @@
//!
//! ## Examples
//!
//! All exaples can be found inside the [examples folder](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/examples)
//! All examples can be found inside the [examples folder](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware/examples)
//! and [firmware folder](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/firmware) of the project
#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
@@ -83,7 +83,7 @@ pub fn init(config: Config) -> Result<zynq7000::Peripherals, InitError> {
configure_level_shifter(config);
}
if let Some(interrupt_config) = config.interrupt_config {
let mut gic = gic::GicConfigurator::new_with_init(periphs.gicc, periphs.gicd);
let mut gic = gic::Configurator::new_with_init(periphs.gicc, periphs.gicd);
match interrupt_config {
InteruptConfig::AllInterruptsToCpu0 => {
gic.enable_all_interrupts();
+1 -1
View File
@@ -1172,7 +1172,7 @@ pub fn reset(id: SpiId) {
/// The Zynq7000 SPI peripheral has the following requirement for the SPI reference clock:
/// It must be larger than the CPU 1X clock. Therefore, the divisor used to calculate the reference
/// clock has a maximum value, which can be calculated with this function.
/// [configure_spi_ref_clk_with_divisor] can be used to configure the SPI reference clock with a
/// [configure_spi_ref_clock_with_divisor] can be used to configure the SPI reference clock with a
/// divisor.
///
/// *NOTE* - It is recommended to avoid the largest theoretical value which was proven to be
@@ -198,6 +198,10 @@ pub struct TxAsync {
impl TxAsync {
/// Constructor.
///
/// The second argument specifies whether the [on_interrupt_tx] function will be registered
/// in the HAL interrupt map. You might need to skip this in case you have your own
/// interrupt handler which also handles RX interrupts.
pub fn new(tx: Tx, register_interrupt_handler: bool) -> Self {
if register_interrupt_handler {
match tx.uart_id() {