Compare commits

...

1 Commits

Author SHA1 Message Date
muellerr 18b6ee2c41 Embassy Multi-Priority Example
ci / Check build (push) Waiting to run
ci / Check formatting (push) Waiting to run
ci / Check Documentation Build (push) Waiting to run
ci / Clippy (push) Waiting to run
2026-05-18 13:20:05 +02:00
10 changed files with 681 additions and 9 deletions
+9
View File
@@ -11,6 +11,7 @@ members = [
"examples/embassy",
"examples/zedboard",
"examples/defmt",
"examples/multiprio",
"zedboard-bsp",
"zedboard-qspi-flasher",
@@ -40,3 +41,11 @@ codegen-units = 1
lto = 'fat'
# Leave the debug symbols in (default is no debug info)
debug = 2
[patch.crates-io]
embassy-executor = { path = "../../embassy/embassy-executor" }
embassy-executor-macros = { path = "../../embassy/embassy-executor-macros" }
embassy-time-driver = { path = "../../embassy/embassy-time-driver" }
embassy-time = { path = "../../embassy/embassy-time" }
embassy-executor-timer-queue = { path = "../../embassy/embassy-executor-timer-queue" }
+4 -1
View File
@@ -28,7 +28,10 @@ fugit = "0.4"
log = "0.4"
embassy-executor = { version = "0.10", features = [
"platform-cortex-ar",
"platform-z7",
"executor-thread",
]}
# embassy-executor = { git = "https://github.com/robamu/embassy.git", branch = "add-z7-arch-support", features = ["platform-z7", "executor-thread"] }
# embassy-executor = { git = "https://github.com/robamu/embassy.git", features = ["platform-cortex-ar", "executor-thread"] }
embassy-time = { version = "0.5", features = ["tick-hz-1_000_000"] }
@@ -0,0 +1,183 @@
#![no_std]
#![no_main]
use aarch32_cpu::asm::nop;
use core::panic::PanicInfo;
use embassy_executor::Spawner;
use embassy_time::{Delay, Duration, Ticker};
use embedded_hal::digital::StatefulOutputPin;
use embedded_hal_async::delay::DelayNs as _;
use embedded_io::Write as _;
use log::error;
use zynq7000_hal::{
InteruptConfig, clocks,
executor::InterruptExecutor,
generic_interrupt_handler,
gic::{SgiInterrupt, TargetCpus},
gpio::{self, Output},
gtc,
time::Hertz,
uart,
};
// Define the clock frequency as a constant
const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300);
static INTERUPT_EXECUTOR: InterruptExecutor = InterruptExecutor::new();
/// Entry point which calls the embassy main method.
#[zynq7000_rt::entry]
fn entry_point() -> ! {
main();
}
#[embassy_executor::main(executor = "zynq7000_hal::executor::Executor")]
async fn main(_spawner: Spawner) -> ! {
let periphs = zynq7000_hal::init(zynq7000_hal::Config {
init_l2_cache: true,
level_shifter_config: Some(zynq7000_hal::LevelShifterConfig::EnableAll),
interrupt_config: Some(InteruptConfig::AllInterruptsToCpu0),
})
.unwrap();
let clocks = clocks::Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
// Set up global timer counter and embassy time driver.
let gtc = gtc::GlobalTimerCounter::new(periphs.gtc, clocks.arm_clocks());
zynq7000_embassy::init(clocks.arm_clocks(), gtc);
let mio_pins = gpio::mio::Pins::new(periphs.gpio);
let led = gpio::Output::new_for_mio(mio_pins.mio7, gpio::PinState::Low);
let sgi_interrupt = SgiInterrupt::new(0).unwrap();
// Set up the UART, we are logging with it.
let uart_clk_config = uart::ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200)
.unwrap()
.0;
let mut uart = uart::Uart::new_with_mio_for_uart_1(
periphs.uart_1,
uart::Config::new_with_clk_config(uart_clk_config),
(mio_pins.mio48, mio_pins.mio49),
)
.unwrap();
uart.write_all(b"-- Zynq 7000 Interrupt Executor --\n\r")
.unwrap();
uart.flush().unwrap();
//let (tx, _rx) = uart.split();
// let mut logger = uart::TxAsync::new(tx, true);
//let log_reader = zynq7000_hal::log::asynch::init(log::LevelFilter::Trace).unwrap();
// Safety: We are not multi-threaded yet.
unsafe {
zynq7000_hal::log::uart_blocking::init_unsafe_single_core(
uart,
log::LevelFilter::Trace,
false,
)
};
log::info!(
"interrupt counter: {}",
CNTR.load(core::sync::atomic::Ordering::Relaxed)
);
let spawner = INTERUPT_EXECUTOR.start(sgi_interrupt, TargetCpus::CPU_0);
zynq7000_hal::register_interrupt(
zynq7000_hal::Interrupt::Sgi(sgi_interrupt),
on_interrupt_low_prio,
);
spawner.spawn(led_task(led).unwrap());
log::info!(
"interrupt counter: {}",
CNTR.load(core::sync::atomic::Ordering::Relaxed)
);
//Delay.delay_ms(1).await;
/*
log::info!(
"interrupt counter: {}",
CNTR.load(core::sync::atomic::Ordering::Relaxed)
);
*/
//let mut log_buf: [u8; 2048] = [0; 2048];
loop {
log::info!("THR alive");
/*
let read_bytes = log_reader.read(&mut log_buf).await;
if read_bytes > 0 {
// Unwrap okay, checked that size is larger than 0.
logger.write(&log_buf[0..read_bytes]).unwrap().await;
}
*/
Ticker::every(Duration::from_millis(1000)).next().await;
}
}
static CNTR: core::sync::atomic::AtomicUsize = core::sync::atomic::AtomicUsize::new(0);
unsafe fn interrupt_handler(_ctx: *mut ()) {
CNTR.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
unsafe {
INTERUPT_EXECUTOR.on_interrupt();
}
CNTR.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
}
#[embassy_executor::task]
async fn led_task(mut mio_led: Output) {
static ATOMIC_COUNTER: core::sync::atomic::AtomicUsize =
core::sync::atomic::AtomicUsize::new(0);
let mut ticker = Ticker::every(Duration::from_millis(1000));
loop {
mio_led.toggle().unwrap();
log::info!(
"Toggling LED ({})",
ATOMIC_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed)
);
ticker.next().await;
}
}
#[zynq7000_rt::irq]
pub fn irq_handler() {
// Safety: Called here once.
let result = unsafe { generic_interrupt_handler() };
log::info!(
"Interrupt handled, counter: {}",
CNTR.load(core::sync::atomic::Ordering::Relaxed)
);
if let Err(e) = result {
panic!("Generic interrupt handler failed handling {:?}", e);
}
}
#[zynq7000_rt::exception(DataAbort)]
fn data_abort_handler(_faulting_addr: usize) -> ! {
loop {
nop();
}
}
#[zynq7000_rt::exception(Undefined)]
fn undefined_handler(_faulting_addr: usize) -> ! {
loop {
nop();
}
}
#[zynq7000_rt::exception(PrefetchAbort)]
fn prefetch_handler(_faulting_addr: usize) -> ! {
loop {
nop();
}
}
/// Panic handler
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
error!("Panic: {info:?}");
loop {}
}
+35
View File
@@ -0,0 +1,35 @@
[package]
name = "embassy-multiprio"
version = "0.1.0"
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
edition = "2024"
description = "Embassy examples for the Zynq7000 SoC"
homepage = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
license = "MIT OR Apache-2.0"
keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"]
categories = ["embedded", "no-std", "hardware-support"]
[dependencies]
aarch32-cpu = { version = "0.3", features = ["critical-section-single-core"] }
zynq7000-rt = { path = "../../zynq7000-rt" }
zynq7000 = { path = "../../zynq7000" }
zynq7000-hal = { path = "../../zynq7000-hal" }
zynq7000-embassy = { path = "../../zynq7000-embassy" }
dht-sensor = { git = "https://github.com/michaelbeaumont/dht-sensor.git", rev = "10319bdeae9ace3bb0fc79a15da2869c5bf50f52", features = ["async"] }
embedded-hal-async = "1"
embassy-sync = "0.8"
static_cell = "2"
critical-section = "1"
heapless = "0.9"
embedded-io = "0.7"
embedded-hal = "1"
arbitrary-int = "2"
fugit = "0.4"
log = "0.4"
embassy-time = { version = "0.5", features = ["tick-hz-1_000_000"] }
embassy-executor = { version = "0.10", features = [
"platform-z7",
"executor-thread",
"executor-interrupt",
]}
+31
View File
@@ -0,0 +1,31 @@
//! This build script copies the `memory.x` file from the crate root into
//! a directory where the linker can always find it at build time.
//! For many projects this is optional, as the linker always searches the
//! project root directory -- wherever `Cargo.toml` is. However, if you
//! are using a workspace or have a more complicated build setup, this
//! build script becomes required. Additionally, by requesting that
//! Cargo re-run the build script whenever `memory.x` is changed,
//! updating `memory.x` ensures a rebuild of the application with the
//! new memory settings.
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
fn main() {
// Put `memory.x` in our output directory and ensure it's
// on the linker search path.
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("memory.x"))
.unwrap()
.write_all(include_bytes!("memory.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());
// By default, Cargo will re-run a build script whenever
// any file in the project changes. By specifying `memory.x`
// here, we ensure the build script is only re-run when
// `memory.x` is changed.
println!("cargo:rerun-if-changed=memory.x");
}
+25
View File
@@ -0,0 +1,25 @@
MEMORY
{
/* Zedboard: 512 MB DDR3. Only use 62 MB for now, should be plenty for a bare-metal app.
1 MB stack memory and 1 MB of memory which will be configured as uncached device memory by the
MMU. This is recommended for something like DMA descriptors. */
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 62M
STACKS : ORIGIN = 0x3F00000, LENGTH = 1M
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
}
REGION_ALIAS("VECTORS", CODE);
REGION_ALIAS("DATA", CODE);
SECTIONS
{
/* Uncached memory */
.uncached (NOLOAD) : ALIGN(4) {
. = ALIGN(4);
_sbss_uncached = .;
*(.uncached .uncached.*);
. = ALIGN(4);
_ebss_uncached = .;
} > UNCACHED
}
+170
View File
@@ -0,0 +1,170 @@
#![no_std]
#![no_main]
use aarch32_cpu::asm::nop;
use arbitrary_int::u5;
use core::panic::PanicInfo;
use embassy_executor::{InterruptExecutor, Spawner};
use embassy_time::{Duration, Ticker};
use embedded_hal::digital::StatefulOutputPin;
use embedded_io::Write as _;
use log::error;
use zynq7000_hal::{
InteruptConfig, clocks, generic_interrupt_handler,
gic::SgiInterrupt,
gpio::{self, Output},
gtc,
time::Hertz,
uart,
};
// Define the clock frequency as a constant
const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300);
static INTERUPT_EXECUTOR_LOW_PRIO: InterruptExecutor = InterruptExecutor::new();
static INTERUPT_EXECUTOR_MED_PRIO: InterruptExecutor = InterruptExecutor::new();
/// Entry point which calls the embassy main method.
#[zynq7000_rt::entry]
fn entry_point() -> ! {
main();
}
#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
let periphs = zynq7000_hal::init(zynq7000_hal::Config {
init_l2_cache: true,
level_shifter_config: Some(zynq7000_hal::LevelShifterConfig::EnableAll),
interrupt_config: Some(InteruptConfig::AllInterruptsToCpu0),
})
.unwrap();
let clocks = clocks::Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap();
let mut gic = unsafe { zynq7000_hal::gic::Configurator::steal() };
gic.set_all_sgi_interrupt_targets_cpu0();
// Set up global timer counter and embassy time driver.
let gtc = gtc::GlobalTimerCounter::new(periphs.gtc, clocks.arm_clocks());
zynq7000_embassy::init(clocks.arm_clocks(), gtc);
let mio_pins = gpio::mio::Pins::new(periphs.gpio);
let led = gpio::Output::new_for_mio(mio_pins.mio7, gpio::PinState::Low);
let sgi_interrupt_low_prio = SgiInterrupt::new(0).unwrap();
let sgi_interrupt_med_prio = SgiInterrupt::new(1).unwrap();
// Set up the UART, we are logging with it.
let uart_clk_config = uart::ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200)
.unwrap()
.0;
let mut uart = uart::Uart::new_with_mio_for_uart_1(
periphs.uart_1,
uart::Config::new_with_clk_config(uart_clk_config),
(mio_pins.mio48, mio_pins.mio49),
)
.unwrap();
uart.write_all(b"-- Zynq 7000 Interrupt Executor --\n\r")
.unwrap();
uart.flush().unwrap();
let (tx, _rx) = uart.split();
let mut logger = uart::TxAsync::new(tx, true);
let log_reader = zynq7000_hal::log::asynch::init(log::LevelFilter::Trace).unwrap();
gic.set_sgi_interrupt_priority(sgi_interrupt_low_prio, u5::new(2));
gic.set_sgi_interrupt_priority(sgi_interrupt_med_prio, u5::new(1));
zynq7000_hal::register_interrupt(
zynq7000_hal::Interrupt::Sgi(sgi_interrupt_low_prio),
on_interrupt_low_prio,
);
zynq7000_hal::register_interrupt(
zynq7000_hal::Interrupt::Sgi(sgi_interrupt_med_prio),
on_interrupt_med_prio,
);
let spawner = INTERUPT_EXECUTOR_LOW_PRIO.start(sgi_interrupt_low_prio.as_u4());
spawner.spawn(led_task(led).unwrap());
let spawner = INTERUPT_EXECUTOR_MED_PRIO.start(sgi_interrupt_med_prio.as_u4());
spawner.spawn(hello_task().unwrap());
let mut log_buf: [u8; 2048] = [0; 2048];
loop {
let read_bytes = log_reader.read(&mut log_buf).await;
if read_bytes > 0 {
// Unwrap okay, checked that size is larger than 0.
logger.write(&log_buf[0..read_bytes]).unwrap().await;
}
Ticker::every(Duration::from_millis(1000)).next().await;
}
}
#[embassy_executor::task]
async fn led_task(mut mio_led: Output) {
static ATOMIC_COUNTER: core::sync::atomic::AtomicUsize =
core::sync::atomic::AtomicUsize::new(0);
let mut ticker = Ticker::every(Duration::from_millis(1000));
loop {
mio_led.toggle().unwrap();
log::info!(
"Toggling LED ({})",
ATOMIC_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed)
);
ticker.next().await;
}
}
#[embassy_executor::task]
async fn hello_task() {
let mut ticker = Ticker::every(Duration::from_millis(1000));
loop {
log::info!("Hello from the low priority task");
ticker.next().await;
}
}
unsafe fn on_interrupt_low_prio() {
unsafe {
INTERUPT_EXECUTOR_LOW_PRIO.on_interrupt();
}
}
unsafe fn on_interrupt_med_prio() {
unsafe {
INTERUPT_EXECUTOR_MED_PRIO.on_interrupt();
}
}
#[zynq7000_rt::irq]
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);
}
}
#[zynq7000_rt::exception(DataAbort)]
fn data_abort_handler(_faulting_addr: usize) -> ! {
loop {
nop();
}
}
#[zynq7000_rt::exception(Undefined)]
fn undefined_handler(_faulting_addr: usize) -> ! {
loop {
nop();
}
}
#[zynq7000_rt::exception(PrefetchAbort)]
fn prefetch_handler(_faulting_addr: usize) -> ! {
loop {
nop();
}
}
/// Panic handler
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
error!("Panic: {info:?}");
loop {}
}
+123
View File
@@ -0,0 +1,123 @@
//! Example which uses the UART1 to send log messages.
#![no_std]
#![no_main]
use aarch32_cpu::asm::nop;
use core::{panic::PanicInfo, sync::atomic::AtomicU64};
use embedded_hal::digital::StatefulOutputPin;
use embedded_io::Write;
use log::{error, info};
use zynq7000_hal::{
BootMode,
clocks::Clocks,
gic::{self, Configurator, Interrupt, SgiInterrupt},
gpio::{Output, PinState, mio},
l2_cache,
time::Hertz,
uart::{ClockConfig, Config, Uart},
};
// Define the clock frequency as a constant
const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300);
static SGI_COUNTER: AtomicU64 = AtomicU64::new(0);
#[zynq7000_rt::entry]
fn main() -> ! {
let mut dp = zynq7000::Peripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);
// 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 = Configurator::new_with_init(dp.gicc, dp.gicd);
gic.enable_all_interrupts();
gic.set_all_spi_interrupt_targets_cpu0();
gic.set_all_sgi_interrupt_targets_cpu0();
gic.enable();
// Enable interrupt exception.
unsafe { gic.enable_interrupts() };
// Set up the UART, we are logging with it.
let uart_clk_config = ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200)
.unwrap()
.0;
let mio_pins = mio::Pins::new(dp.gpio);
let mut uart = Uart::new_with_mio_for_uart_1(
dp.uart_1,
Config::new_with_clk_config(uart_clk_config),
(mio_pins.mio48, mio_pins.mio49),
)
.unwrap();
uart.write_all(b"-- Zynq 7000 Software Interrupt example --\n\r")
.unwrap();
// Safety: We are not multi-threaded yet.
unsafe {
zynq7000_hal::log::uart_blocking::init_unsafe_single_core(
uart,
log::LevelFilter::Trace,
false,
)
};
let boot_mode = BootMode::new_from_regs();
info!("Boot mode: {boot_mode:?}");
let mut led = Output::new_for_mio(mio_pins.mio7, PinState::Low);
loop {
let gtc = SGI_COUNTER.load(core::sync::atomic::Ordering::Relaxed);
info!("Hello, world!");
info!("SGI counter: {gtc}");
gic.trigger_software_interrupt(SgiInterrupt::new(0).unwrap());
led.toggle().unwrap();
for _ in 0..5_000_000 {
nop();
}
}
}
#[zynq7000_rt::irq]
fn irq_handler() {
let mut gic_helper = gic::InterruptGuard::new();
let irq_info = gic_helper.interrupt_info();
match irq_info.interrupt() {
Interrupt::Sgi(_sgi) => {
// TODO: Send ID to main thread.
SGI_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
}
Interrupt::Ppi(_ppi_interrupt) => (),
Interrupt::Spi(_spi_interrupt) => (),
Interrupt::Invalid(_) => (),
Interrupt::Spurious => (),
}
gic_helper.end_of_interrupt(irq_info);
}
#[zynq7000_rt::exception(DataAbort)]
fn data_abort_handler(_faulting_addr: usize) -> ! {
loop {
nop();
}
}
#[zynq7000_rt::exception(Undefined)]
fn undefined_handler(_faulting_addr: usize) -> ! {
loop {
nop();
}
}
#[zynq7000_rt::exception(PrefetchAbort)]
fn prefetch_handler(_faulting_addr: usize) -> ! {
loop {
nop();
}
}
/// Panic handler
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
error!("Panic: {info:?}");
loop {}
}
+94 -6
View File
@@ -12,7 +12,7 @@ use aarch32_cpu::interrupt;
use zynq7000::gic::{
CpuInterfaceRegisters, DistributorControlRegister, DistributorRegisters, InterfaceControl,
InterruptProcessorTargetRegister, InterruptSignalRegister, MmioCpuInterfaceRegisters,
MmioDistributorRegisters, PriorityRegister,
MmioDistributorRegisters, PriorityRegister, SoftwareGeneratedInterruptRegister,
};
/// Spurious interrupt ID.
@@ -235,13 +235,41 @@ pub enum SpiInterrupt {
ScuParity = 92,
}
/// SGI interrupt ID wrapper.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SgiInterrupt(usize);
impl SgiInterrupt {
/// Create a new SGI interrupt ID wrapper.
pub const fn new(int_id: usize) -> Result<Self, InvalidSgiInterruptId> {
if int_id >= 16 {
return Err(InvalidSgiInterruptId(int_id));
}
Ok(SgiInterrupt(int_id))
}
/// Returns the raw interrupt ID of the SGI.
#[inline]
pub const fn raw_id(&self) -> usize {
self.0
}
/// Returns the raw interrupt ID of the SGI as [u4].
#[inline]
pub const fn as_u4(&self) -> u4 {
u4::new(self.0 as u8)
}
}
/// Interrupt ID wrapper.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Interrupt {
/// Software-generated interrupt (SGI).
Sgi(usize),
Sgi(SgiInterrupt),
/// Private peripheral interrupt (PPI).
Ppi(PpiInterrupt),
/// Shared peripheral interrupt (SPI).
@@ -498,7 +526,29 @@ impl Configurator {
.unwrap();
}
/// Utility function to set all SGI interrupt targets to CPU0.
/// Set the interrupt priority for a SGI interrupt.
///
/// There are 32 priority levels, and a lower value means a higher priority.
#[inline]
pub fn set_sgi_interrupt_priority(&mut self, sgi: SgiInterrupt, priority: u5) {
// The IPR arrays are byte accessible.
let base_ptr = self.gicd.pointer_to_ipr_start() as *mut u8;
let raw_index = sgi.raw_id();
unsafe {
core::ptr::write_volatile(base_ptr.add(raw_index), priority.as_u8() << 3);
}
}
/// Read the interrupt priority for a SGI interrupt.
#[inline]
pub fn read_sgi_interrupt_priority(&mut self, sgi: SgiInterrupt) -> u5 {
// The IPR arrays are byte accessible.
let base_ptr = self.gicd.pointer_to_ipr_start() as *const u8;
let raw_index = sgi.raw_id();
unsafe { u5::new(core::ptr::read_volatile(base_ptr.add(raw_index)) >> 3) }
}
/// Utility function to set all SPI interrupt targets to CPU0.
///
/// This does not clear interrupt target bits for CPU1, it only activates the interrupts for
/// CPU 0 as well.
@@ -517,6 +567,25 @@ impl Configurator {
}
}
/// Utility function to set all SGI interrupt targets to CPU0.
///
/// This does not clear interrupt target bits for CPU1, it only activates the interrupts for
/// CPU 0 as well.
/// This is useful if only CPU0 is active in a system, or if CPU0 handles most interrupts in
/// the system.
#[inline]
pub fn set_all_sgi_interrupt_targets_cpu0(&mut self) {
for i in 0..4 {
self.gicd
.modify_iptr_sgi(i, |v| {
InterruptProcessorTargetRegister::new_with_raw_value(
v.raw_value() | TARGETS_ALL_CPU_0_IPTR_VAL.raw_value(),
)
})
.unwrap();
}
}
/// Enable a specific SGI interrupt.
#[inline]
pub fn enable_sgi_interrupt(&mut self, int_id: usize) -> Result<(), InvalidSpiInterruptId> {
@@ -561,6 +630,19 @@ impl Configurator {
})
};
}
/// Enable all PPI interrupts.
#[inline]
pub fn trigger_software_interrupt(&mut self, sgi_id: SgiInterrupt) {
self.gicd.write_sgir(
SoftwareGeneratedInterruptRegister::builder()
.with_target_list_filter(zynq7000::gic::TargetListFilter::SendToSelf)
.with_security_condition(zynq7000::gic::SecurityCondition::IfConfiguredAsSecure)
.with_sbz(u11::ZERO)
.with_cpu_target_list(0)
.with_interrupt_id(u4::new(sgi_id.raw_id() as u8))
.build(),
);
}
/// Enable specific SPI interrupt.
#[inline]
@@ -682,9 +764,15 @@ impl InterruptGuard {
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),
27..=31 => Interrupt::Ppi(PpiInterrupt::try_from(int_id as u8).unwrap()),
32..=92 => Interrupt::Spi(SpiInterrupt::try_from(int_id as u8).unwrap()),
0..=15 => Interrupt::Sgi(
SgiInterrupt::new(int_id as usize).expect("invalid SGI interrupt number"),
),
27..=31 => Interrupt::Ppi(
PpiInterrupt::try_from(int_id as u8).expect("invalid PPI interrupt number"),
),
32..=92 => Interrupt::Spi(
SpiInterrupt::try_from(int_id as u8).expect("invalid SPI interrupt number"),
),
SPURIOUS_INTERRUPT_ID => Interrupt::Spurious,
_ => Interrupt::Invalid(int_id as usize),
};
+7 -2
View File
@@ -46,9 +46,14 @@ impl TypeRegister {
pub type Typer = TypeRegister;
#[bitbybit::bitfield(u32, debug)]
#[bitbybit::bitfield(
u32,
debug,
default = 0x0,
defmt_bitfields(feature = "defmt"),
forbid_overlaps
)]
#[derive(PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InterruptProcessorTargetRegister {
/// Target array. Every register holds the information for 4 interrupts.
#[bits(0..=1, rw, stride = 8)]