introduce interrupt registry #78
@@ -12,7 +12,8 @@ use log::{error, info, warn};
|
||||
use zynq7000_hal::{
|
||||
BootMode,
|
||||
clocks::Clocks,
|
||||
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
|
||||
generic_interrupt_handler,
|
||||
gic::Configurator,
|
||||
gpio::{Flex, Output, PinState, mio},
|
||||
gtc::GlobalTimerCounter,
|
||||
l2_cache,
|
||||
@@ -45,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();
|
||||
@@ -157,23 +158,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)]
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -13,12 +13,13 @@ use zynq7000::Peripherals;
|
||||
use zynq7000_hal::{
|
||||
BootMode,
|
||||
clocks::Clocks,
|
||||
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
|
||||
generic_interrupt_handler,
|
||||
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 _;
|
||||
@@ -40,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();
|
||||
@@ -68,7 +69,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||
uart.flush().unwrap();
|
||||
|
||||
let (tx, _rx) = uart.split();
|
||||
let mut logger = TxAsync::new(tx);
|
||||
let mut logger = TxAsync::new(tx, true);
|
||||
|
||||
let log_reader = zynq7000_hal::log::asynch::init(log::LevelFilter::Trace).unwrap();
|
||||
|
||||
@@ -119,28 +120,13 @@ async fn hello_task() {
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" 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) => {
|
||||
if spi_interrupt == zynq7000_hal::gic::SpiInterrupt::Uart1 {
|
||||
on_interrupt_tx(zynq7000_hal::uart::UartId::Uart1);
|
||||
}
|
||||
}
|
||||
Interrupt::Invalid(_) => (),
|
||||
Interrupt::Spurious => (),
|
||||
#[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);
|
||||
}
|
||||
gic_helper.end_of_interrupt(irq_info);
|
||||
}
|
||||
|
||||
#[zynq7000_rt::exception(DataAbort)]
|
||||
|
||||
@@ -18,7 +18,8 @@ use log::{error, info};
|
||||
use zynq7000_hal::{
|
||||
BootMode,
|
||||
clocks::Clocks,
|
||||
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
|
||||
generic_interrupt_handler,
|
||||
gic::Configurator,
|
||||
gpio::{Output, PinState, mio},
|
||||
gtc::GlobalTimerCounter,
|
||||
l2_cache,
|
||||
@@ -46,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();
|
||||
@@ -107,23 +108,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)]
|
||||
|
||||
@@ -7,7 +7,7 @@ use embassy_executor::Spawner;
|
||||
use embassy_time::{Duration, Ticker};
|
||||
use embedded_hal::digital::StatefulOutputPin;
|
||||
use log::error;
|
||||
use zynq7000_hal::{InteruptConfig, clocks, 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);
|
||||
@@ -42,22 +42,11 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
|
||||
#[zynq7000_rt::irq]
|
||||
pub 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 => (),
|
||||
// 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)]
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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,13 +85,12 @@ 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) => {
|
||||
if ppi_interrupt == zynq7000_hal::gic::PpiInterrupt::GlobalTimer {
|
||||
// TODO: Call embassy on interrupt handler here soon.
|
||||
MS_TICKS.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@ use zynq7000_hal::{
|
||||
eth::{
|
||||
AlignedBuffer, ClockDivSet, EthernetConfig, EthernetLowLevel, embassy_net::InterruptResult,
|
||||
},
|
||||
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
|
||||
generic_interrupt_handler,
|
||||
gic::{Configurator, Interrupt},
|
||||
gpio::{GpioPins, Output, PinState},
|
||||
gtc::GlobalTimerCounter,
|
||||
l2_cache,
|
||||
@@ -216,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();
|
||||
@@ -278,6 +279,12 @@ async fn main(spawner: Spawner) -> ! {
|
||||
"Calculated RGMII clock configuration: {:?}, errors (missmatch from ideal rate in hertz): {:?}",
|
||||
clk_divs, clk_errors
|
||||
);
|
||||
|
||||
zynq7000_hal::register_interrupt(
|
||||
Interrupt::Spi(zynq7000_hal::gic::SpiInterrupt::Eth0),
|
||||
custom_eth_interupt_handler,
|
||||
);
|
||||
|
||||
// Unwrap okay, we use a standard clock config, and the clock config should never fail.
|
||||
let eth_cfg = EthernetConfig::new(
|
||||
zynq7000_hal::eth::ClockConfig::new(clk_divs.cfg_1000_mbps),
|
||||
@@ -461,36 +468,24 @@ 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) => {
|
||||
if spi_interrupt == zynq7000_hal::gic::SpiInterrupt::Eth0 {
|
||||
// This generic library provided interrupt handler takes care of waking
|
||||
// the driver on received or sent frames while also reporting anomalies
|
||||
// and errors.
|
||||
let result = zynq7000_hal::eth::embassy_net::on_interrupt(
|
||||
zynq7000_hal::eth::EthernetId::Eth0,
|
||||
);
|
||||
if result.has_errors() {
|
||||
ETH_ERR_QUEUE.try_send(result).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
Interrupt::Invalid(_) => (),
|
||||
Interrupt::Spurious => (),
|
||||
// Safety: Only called by interrupt handler, registered in global interrupt handler map.
|
||||
unsafe fn custom_eth_interupt_handler() {
|
||||
// This generic library provided interrupt handler takes care of waking
|
||||
// the driver on received or sent frames while also reporting anomalies
|
||||
// and errors.
|
||||
let result = zynq7000_hal::eth::embassy_net::on_interrupt(zynq7000_hal::eth::EthernetId::Eth0);
|
||||
if result.has_errors() {
|
||||
ETH_ERR_QUEUE.try_send(result).ok();
|
||||
}
|
||||
}
|
||||
|
||||
#[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);
|
||||
}
|
||||
gic_helper.end_of_interrupt(irq_info);
|
||||
}
|
||||
|
||||
#[zynq7000_rt::exception(DataAbort)]
|
||||
|
||||
@@ -20,8 +20,8 @@ use log::{error, info};
|
||||
use zynq7000_hal::{
|
||||
BootMode,
|
||||
clocks::Clocks,
|
||||
configure_level_shifter,
|
||||
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
|
||||
configure_level_shifter, generic_interrupt_handler,
|
||||
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();
|
||||
@@ -153,24 +153,13 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" 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 => (),
|
||||
#[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);
|
||||
}
|
||||
gic_helper.end_of_interrupt(irq_info);
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
|
||||
@@ -21,14 +21,14 @@ use log::{error, info};
|
||||
use zynq7000_hal::{
|
||||
BootMode,
|
||||
clocks::Clocks,
|
||||
configure_level_shifter,
|
||||
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
|
||||
configure_level_shifter, generic_interrupt_handler,
|
||||
gic::Configurator,
|
||||
gpio::{GpioPins, Output, PinState},
|
||||
gtc::GlobalTimerCounter,
|
||||
l2_cache,
|
||||
spi::{self, SpiAsync, SpiId, SpiWithHwCs, SpiWithHwCsAsync, on_interrupt},
|
||||
spi::{self, SpiAsync, SpiWithHwCs, SpiWithHwCsAsync},
|
||||
time::Hertz,
|
||||
uart::{self, TxAsync, on_interrupt_tx},
|
||||
uart::{self, TxAsync},
|
||||
};
|
||||
|
||||
use zynq7000::{Peripherals, slcr::LevelShifterConfig, spi::DelayControl};
|
||||
@@ -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();
|
||||
@@ -177,7 +177,7 @@ pub async fn logger_task(
|
||||
reader: embassy_sync::pipe::Reader<'static, CriticalSectionRawMutex, 4096>,
|
||||
) -> ! {
|
||||
let (tx, _) = uart.split();
|
||||
let mut tx_async = TxAsync::new(tx);
|
||||
let mut tx_async = TxAsync::new(tx, true);
|
||||
let mut log_buf: [u8; 2048] = [0; 2048];
|
||||
loop {
|
||||
let read_bytes = reader.read(&mut log_buf).await;
|
||||
@@ -248,30 +248,13 @@ pub async fn non_blocking_application(
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" 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) => {
|
||||
if spi_interrupt == zynq7000_hal::gic::SpiInterrupt::Spi1 {
|
||||
on_interrupt(SpiId::Spi1);
|
||||
} else if spi_interrupt == zynq7000_hal::gic::SpiInterrupt::Uart1 {
|
||||
on_interrupt_tx(zynq7000_hal::uart::UartId::Uart1);
|
||||
}
|
||||
}
|
||||
Interrupt::Invalid(_) => (),
|
||||
Interrupt::Spurious => (),
|
||||
#[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);
|
||||
}
|
||||
gic_helper.end_of_interrupt(irq_info);
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
|
||||
@@ -16,7 +16,7 @@ use log::{error, info};
|
||||
use ssd1306::{Ssd1306Async, prelude::*};
|
||||
use zedboard::PS_CLOCK_FREQUENCY;
|
||||
use zynq7000_hal::{
|
||||
BootMode, clocks, gic, gpio, gtc,
|
||||
BootMode, clocks, generic_interrupt_handler, gpio, gtc,
|
||||
spi::{self, SpiAsync},
|
||||
time::Hertz,
|
||||
uart::{self, TxAsync},
|
||||
@@ -221,7 +221,7 @@ pub async fn logger_task(
|
||||
reader: embassy_sync::pipe::Reader<'static, CriticalSectionRawMutex, 4096>,
|
||||
) -> ! {
|
||||
let (tx, _) = uart.split();
|
||||
let mut tx_async = TxAsync::new(tx);
|
||||
let mut tx_async = TxAsync::new(tx, true);
|
||||
let mut log_buf: [u8; 2048] = [0; 2048];
|
||||
loop {
|
||||
let read_bytes = reader.read(&mut log_buf).await;
|
||||
@@ -247,33 +247,12 @@ pub async fn blinky_task(mut mio_led: gpio::Output, mut emio_leds: [gpio::Output
|
||||
}
|
||||
|
||||
#[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) => match spi_interrupt {
|
||||
gic::SpiInterrupt::Uart1 => {
|
||||
zynq7000_hal::uart::tx_async::on_interrupt_tx(uart::UartId::Uart1);
|
||||
}
|
||||
gic::SpiInterrupt::Spi0 => {
|
||||
zynq7000_hal::spi::asynch::on_interrupt(spi::SpiId::Spi0);
|
||||
}
|
||||
_ => {
|
||||
log::warn!("Unhandled SPI interrupt: {:?}", 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)]
|
||||
|
||||
@@ -16,7 +16,7 @@ use log::{error, info};
|
||||
use ssd1306::{Ssd1306, prelude::*};
|
||||
use zedboard::PS_CLOCK_FREQUENCY;
|
||||
use zynq7000_hal::{
|
||||
BootMode, clocks, gic, gpio, gtc, spi,
|
||||
BootMode, clocks, generic_interrupt_handler, gpio, gtc, spi,
|
||||
time::Hertz,
|
||||
uart::{self, TxAsync},
|
||||
};
|
||||
@@ -216,7 +216,7 @@ pub async fn logger_task(
|
||||
reader: embassy_sync::pipe::Reader<'static, CriticalSectionRawMutex, 4096>,
|
||||
) -> ! {
|
||||
let (tx, _) = uart.split();
|
||||
let mut tx_async = TxAsync::new(tx);
|
||||
let mut tx_async = TxAsync::new(tx, true);
|
||||
let mut log_buf: [u8; 2048] = [0; 2048];
|
||||
loop {
|
||||
let read_bytes = reader.read(&mut log_buf).await;
|
||||
@@ -242,30 +242,12 @@ pub async fn blinky_task(mut mio_led: gpio::Output, mut emio_leds: [gpio::Output
|
||||
}
|
||||
|
||||
#[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) => match spi_interrupt {
|
||||
gic::SpiInterrupt::Uart1 => {
|
||||
zynq7000_hal::uart::tx_async::on_interrupt_tx(uart::UartId::Uart1);
|
||||
}
|
||||
_ => {
|
||||
log::warn!("Unhandled SPI interrupt: {:?}", 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)]
|
||||
|
||||
@@ -11,7 +11,9 @@ use embedded_io::Write;
|
||||
use log::{error, info};
|
||||
use zedboard::PS_CLOCK_FREQUENCY;
|
||||
use zedboard_bsp::qspi_spansion;
|
||||
use zynq7000_hal::{BootMode, clocks, gic, gpio, gtc, prelude::*, qspi, uart};
|
||||
use zynq7000_hal::{
|
||||
BootMode, clocks, generic_interrupt_handler, gpio, gtc, prelude::*, qspi, uart,
|
||||
};
|
||||
|
||||
use zynq7000_rt as _;
|
||||
|
||||
@@ -193,23 +195,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)]
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -41,8 +41,8 @@ use log::{error, info, warn};
|
||||
use zynq7000_hal::{
|
||||
BootMode,
|
||||
clocks::Clocks,
|
||||
configure_level_shifter,
|
||||
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
|
||||
configure_level_shifter, generic_interrupt_handler,
|
||||
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,
|
||||
@@ -210,6 +210,20 @@ async fn main(spawner: Spawner) -> ! {
|
||||
unsafe { HEAP.init(&raw mut HEAP_MEM as usize, HEAP_SIZE) }
|
||||
}
|
||||
|
||||
// Register the interrupts for the PL.
|
||||
zynq7000_hal::register_interrupt(
|
||||
Interrupt::Spi(zynq7000_hal::gic::SpiInterrupt::Pl0),
|
||||
on_interrupt_axi_uartlite,
|
||||
);
|
||||
zynq7000_hal::register_interrupt(
|
||||
Interrupt::Spi(zynq7000_hal::gic::SpiInterrupt::Pl1),
|
||||
on_interrupt_axi_16550,
|
||||
);
|
||||
zynq7000_hal::register_interrupt(
|
||||
Interrupt::Spi(zynq7000_hal::gic::SpiInterrupt::Uart0),
|
||||
on_interrupt_uart_0,
|
||||
);
|
||||
|
||||
// Safety: We are not multi-threaded yet.
|
||||
unsafe {
|
||||
zynq7000_hal::log::uart_blocking::init_unsafe_single_core(
|
||||
@@ -390,7 +404,8 @@ async fn uartlite_task(uartlite: axi_uartlite::Tx) {
|
||||
#[embassy_executor::task]
|
||||
async fn uart_0_task(uart_tx: zynq7000_hal::uart::Tx) {
|
||||
let mut ticker = Ticker::every(Duration::from_millis(1000));
|
||||
let mut tx_async = zynq7000_hal::uart::TxAsync::new(uart_tx);
|
||||
let mut tx_async = zynq7000_hal::uart::TxAsync::new(uart_tx, false);
|
||||
|
||||
let str0 = build_print_string("UART0:", "Hello World");
|
||||
let str1 = build_print_string(
|
||||
"UART0:",
|
||||
@@ -432,36 +447,12 @@ async fn uart_16550_task(uart_tx: axi_uart16550::Tx) {
|
||||
}
|
||||
|
||||
#[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) => match spi_interrupt {
|
||||
zynq7000_hal::gic::SpiInterrupt::Pl0 => {
|
||||
on_interrupt_axi_uartlite();
|
||||
}
|
||||
zynq7000_hal::gic::SpiInterrupt::Pl1 => {
|
||||
on_interrupt_axi_16550();
|
||||
}
|
||||
zynq7000_hal::gic::SpiInterrupt::Uart0 => {
|
||||
on_interrupt_uart_0();
|
||||
}
|
||||
|
||||
_ => (),
|
||||
},
|
||||
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);
|
||||
}
|
||||
|
||||
fn on_interrupt_axi_uartlite() {
|
||||
@@ -530,8 +521,9 @@ fn on_interrupt_uart_0() {
|
||||
.on_interrupt(&mut buf, true)
|
||||
.read_bytes();
|
||||
});
|
||||
// Safety: This function is only called once inside the interrupt handler.
|
||||
// Handle TX next: Handle pending asynchronous TX operations.
|
||||
zynq7000_hal::uart::on_interrupt_tx(zynq7000_hal::uart::UartId::Uart0);
|
||||
unsafe { zynq7000_hal::uart::on_interrupt_tx(zynq7000_hal::uart::UartId::Uart0) };
|
||||
// Send received RX data to main task.
|
||||
if read_bytes > 0 {
|
||||
critical_section::with(|cs| {
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -66,6 +66,16 @@ impl GtcTimerDriver {
|
||||
///
|
||||
/// This has to be called ONCE at system initialization.
|
||||
pub unsafe fn init(&'static self, arm_clock: &ArmClocks, mut gtc: GlobalTimerCounter) {
|
||||
fn safe_interrupt_handler() {
|
||||
// Safety: See safety notes of [zynq7000_hal::generic_interrupt_handler].
|
||||
unsafe {
|
||||
on_interrupt();
|
||||
}
|
||||
}
|
||||
zynq7000_hal::register_interrupt(
|
||||
zynq7000_hal::gic::Interrupt::Ppi(zynq7000_hal::gic::PpiInterrupt::GlobalTimer),
|
||||
safe_interrupt_handler,
|
||||
);
|
||||
CPU_3X2X_CLK.set(arm_clock.cpu_3x2x_clk()).unwrap();
|
||||
SCALE
|
||||
.set(arm_clock.cpu_3x2x_clk().to_raw() as u64 / TICK_HZ)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -85,8 +88,9 @@ bitflags::bitflags! {
|
||||
}
|
||||
|
||||
/// Private Peripheral Interrupt (PPI) which are private to the CPU.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Copy, num_enum::TryFromPrimitive)]
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash, num_enum::TryFromPrimitive)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
pub enum PpiInterrupt {
|
||||
/// Global timer.
|
||||
@@ -102,8 +106,9 @@ pub enum PpiInterrupt {
|
||||
}
|
||||
|
||||
/// Shared Peripheral Interrupt IDs.
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Copy, num_enum::TryFromPrimitive)]
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash, num_enum::TryFromPrimitive)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
pub enum SpiInterrupt {
|
||||
/// CPU 0.
|
||||
@@ -231,8 +236,9 @@ pub enum SpiInterrupt {
|
||||
}
|
||||
|
||||
/// Interrupt ID wrapper.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[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),
|
||||
@@ -247,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,
|
||||
@@ -334,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]
|
||||
@@ -351,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
|
||||
}
|
||||
@@ -365,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() },
|
||||
}
|
||||
@@ -648,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),
|
||||
@@ -678,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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
use crate::gic::{Interrupt, InterruptGuard};
|
||||
|
||||
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();
|
||||
map.insert(interrupt, handler).ok();
|
||||
});
|
||||
}
|
||||
|
||||
/// Generic interrupt handler which retrieves the interrupt handler for individual [Interrupt]s
|
||||
/// from a registry and calls it.
|
||||
///
|
||||
/// If no interrupt was registered or the number is [Interrupt::Invalid], returns the [Interrupt]
|
||||
/// ID as an error. In any case, the generic handler acknowledges the interrupt in the GIC.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// 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_guard = InterruptGuard::new();
|
||||
let irq_info = gic_guard.interrupt_info();
|
||||
let interrupt = irq_info.interrupt();
|
||||
if let Interrupt::Invalid(_) = interrupt {
|
||||
gic_guard.end_of_interrupt(irq_info);
|
||||
return Err(interrupt);
|
||||
}
|
||||
let opt_interrupt_handler = critical_section::with(|cs| {
|
||||
let map = INTERRUPT_MAP.borrow(cs).borrow_mut();
|
||||
map.get(&interrupt).copied()
|
||||
});
|
||||
if let Some(interrupt_handler) = opt_interrupt_handler {
|
||||
// Safety: The user made sure that this is only called once in the interrupt handler
|
||||
// function.
|
||||
unsafe {
|
||||
interrupt_handler();
|
||||
}
|
||||
}
|
||||
gic_guard.end_of_interrupt(irq_info);
|
||||
opt_interrupt_handler.ok_or(interrupt)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -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))]
|
||||
@@ -32,6 +32,7 @@ pub mod gic;
|
||||
pub mod gpio;
|
||||
pub mod gtc;
|
||||
pub mod i2c;
|
||||
pub mod interrupt;
|
||||
pub mod l2_cache;
|
||||
pub mod log;
|
||||
pub mod pl;
|
||||
@@ -45,6 +46,8 @@ pub mod time;
|
||||
pub mod ttc;
|
||||
pub mod uart;
|
||||
|
||||
pub use gic::{Interrupt, PpiInterrupt, SpiInterrupt};
|
||||
pub use interrupt::{generic_interrupt_handler, register_interrupt};
|
||||
pub use zynq7000 as pac;
|
||||
pub use zynq7000::slcr::LevelShifterConfig;
|
||||
|
||||
@@ -80,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();
|
||||
|
||||
@@ -29,9 +29,11 @@ impl embedded_hal_async::spi::Error for RxOverrunError {
|
||||
/// This is a generic interrupt handler to handle asynchronous SPI operations for a given
|
||||
/// SPI peripheral.
|
||||
///
|
||||
/// The user has to call this once in the interrupt handler responsible for the SPI interrupts on
|
||||
/// # Safety
|
||||
///
|
||||
/// This needs to be called once in the interrupt handler responsible for the SPI interrupts on
|
||||
/// the given SPI bank.
|
||||
pub fn on_interrupt(peripheral: SpiId) {
|
||||
pub unsafe fn on_interrupt(peripheral: SpiId) {
|
||||
let mut spi = unsafe { SpiLowLevel::steal(peripheral) };
|
||||
let index = peripheral as usize;
|
||||
let enabled_irqs = spi.read_enabled_interrupts();
|
||||
@@ -513,6 +515,30 @@ pub struct SpiAsync(pub Spi);
|
||||
|
||||
impl SpiAsync {
|
||||
pub fn new(spi: Spi) -> Self {
|
||||
match spi.inner.id {
|
||||
SpiId::Spi0 => {
|
||||
unsafe fn spi0_interrupt_handler() {
|
||||
unsafe {
|
||||
on_interrupt(SpiId::Spi0);
|
||||
}
|
||||
}
|
||||
crate::register_interrupt(
|
||||
crate::gic::Interrupt::Spi(crate::gic::SpiInterrupt::Spi0),
|
||||
spi0_interrupt_handler,
|
||||
)
|
||||
}
|
||||
SpiId::Spi1 => {
|
||||
unsafe fn spi1_interrupt_handler() {
|
||||
unsafe {
|
||||
on_interrupt(SpiId::Spi1);
|
||||
}
|
||||
}
|
||||
crate::register_interrupt(
|
||||
crate::gic::Interrupt::Spi(crate::gic::SpiInterrupt::Spi1),
|
||||
spi1_interrupt_handler,
|
||||
)
|
||||
}
|
||||
}
|
||||
Self(spi)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -631,7 +631,7 @@ impl Uart {
|
||||
},
|
||||
tx: Tx {
|
||||
regs: reg_block,
|
||||
idx: uart_id,
|
||||
id: uart_id,
|
||||
},
|
||||
cfg,
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@ use super::UartId;
|
||||
/// Transmitter (TX) driver.
|
||||
pub struct Tx {
|
||||
pub(crate) regs: MmioRegisters<'static>,
|
||||
pub(crate) idx: UartId,
|
||||
pub(crate) id: UartId,
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for Tx {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("Tx").field("idx", &self.idx).finish()
|
||||
f.debug_struct("Tx").field("idx", &self.id).finish()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,17 +24,17 @@ impl Tx {
|
||||
///
|
||||
/// Circumvents safety guarantees provided by the compiler.
|
||||
#[inline]
|
||||
pub const unsafe fn steal(idx: UartId) -> Self {
|
||||
pub const unsafe fn steal(id: UartId) -> Self {
|
||||
Tx {
|
||||
regs: unsafe { idx.regs() },
|
||||
idx,
|
||||
regs: unsafe { id.regs() },
|
||||
id,
|
||||
}
|
||||
}
|
||||
|
||||
/// UART index.
|
||||
/// UART ID.
|
||||
#[inline]
|
||||
pub const fn uart_idx(&self) -> UartId {
|
||||
self.idx
|
||||
pub const fn uart_id(&self) -> UartId {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Direct access to the UART MMIO registers.
|
||||
|
||||
@@ -19,9 +19,11 @@ static TX_DONE: [AtomicBool; 2] = [const { AtomicBool::new(false) }; 2];
|
||||
/// This is a generic interrupt handler to handle asynchronous UART TX operations for a given
|
||||
/// UART peripheral.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The user has to call this once in the interrupt handler responsible for the TX interrupts on
|
||||
/// the given UART bank.
|
||||
pub fn on_interrupt_tx(peripheral: UartId) {
|
||||
pub unsafe fn on_interrupt_tx(peripheral: UartId) {
|
||||
let mut tx_with_irq = unsafe { Tx::steal(peripheral) };
|
||||
let idx = peripheral as usize;
|
||||
let enabled_irqs = tx_with_irq.regs().read_enabled_interrupts();
|
||||
@@ -126,7 +128,7 @@ impl<'uart> TxFuture<'uart> {
|
||||
/// This function stores the raw pointer of the passed data slice. The user MUST ensure
|
||||
/// that the slice outlives the data structure.
|
||||
pub unsafe fn new(tx_with_irq: &'uart mut Tx, data: &[u8]) -> TxFuture<'uart> {
|
||||
let idx = tx_with_irq.uart_idx() as usize;
|
||||
let idx = tx_with_irq.uart_id() as usize;
|
||||
TX_DONE[idx].store(false, core::sync::atomic::Ordering::Relaxed);
|
||||
tx_with_irq.disable_interrupts();
|
||||
tx_with_irq.disable();
|
||||
@@ -156,7 +158,7 @@ impl<'uart> TxFuture<'uart> {
|
||||
tx_with_irq.enable_interrupts(data.len() > FIFO_DEPTH);
|
||||
|
||||
Self {
|
||||
id: tx_with_irq.uart_idx(),
|
||||
id: tx_with_irq.uart_id(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -196,7 +198,38 @@ pub struct TxAsync {
|
||||
|
||||
impl TxAsync {
|
||||
/// Constructor.
|
||||
pub fn new(tx: Tx) -> Self {
|
||||
///
|
||||
/// 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() {
|
||||
UartId::Uart0 => {
|
||||
unsafe fn uart0_interrupt_handler() {
|
||||
unsafe {
|
||||
on_interrupt_tx(UartId::Uart0);
|
||||
}
|
||||
}
|
||||
crate::register_interrupt(
|
||||
crate::gic::Interrupt::Spi(crate::gic::SpiInterrupt::Uart0),
|
||||
uart0_interrupt_handler,
|
||||
)
|
||||
}
|
||||
UartId::Uart1 => {
|
||||
unsafe fn uart1_interrupt_handler() {
|
||||
unsafe {
|
||||
on_interrupt_tx(UartId::Uart1);
|
||||
}
|
||||
}
|
||||
crate::register_interrupt(
|
||||
crate::gic::Interrupt::Spi(crate::gic::SpiInterrupt::Uart1),
|
||||
uart1_interrupt_handler,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Self { tx }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user