Examples and test cleanup (#1590)

* initial cull of examples

* Remove direct vector example, replace with interrupt latency test

* Remove clock monitor in favour of just a test
This commit is contained in:
Scott Mabin 2024-05-28 19:58:48 +01:00 committed by GitHub
parent 06bf505093
commit db39d0197a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 131 additions and 2371 deletions

View File

@ -1,82 +0,0 @@
//! Encrypt/Decrypt a message using AES
//% CHIPS: esp32 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
#![no_std]
#![no_main]
use aes::{
cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt, KeyInit},
Aes128 as Aes128SW,
};
use esp_backtrace as _;
use esp_hal::{
aes::{Aes, Mode},
peripherals::Peripherals,
prelude::*,
};
use esp_println::println;
use examples::cycles;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let mut aes = Aes::new(peripherals.AES);
let keytext = "SUp4SeCp@sSw0rd".as_bytes();
let plaintext = "message".as_bytes();
// create an array with aes128 key size
let mut keybuf = [0_u8; 16];
keybuf[..keytext.len()].copy_from_slice(keytext);
// create an array with aes block size
let mut block_buf = [0_u8; 16];
block_buf[..plaintext.len()].copy_from_slice(plaintext);
let mut block = block_buf.clone();
let pre_hw_encrypt = cycles();
aes.process(&mut block, Mode::Encryption128, keybuf);
let post_hw_encrypt = cycles();
println!(
"it took {} cycles for hw encrypt",
post_hw_encrypt - pre_hw_encrypt
);
let hw_encrypted = block.clone();
let pre_hw_decrypt = cycles();
aes.process(&mut block, Mode::Decryption128, keybuf);
let post_hw_decrypt = cycles();
println!(
"it took {} cycles for hw decrypt",
post_hw_decrypt - pre_hw_decrypt
);
let hw_decrypted = block;
let key = GenericArray::from(keybuf);
let mut block = GenericArray::from(block_buf);
let cipher = Aes128SW::new(&key);
let pre_sw_encrypt = cycles();
cipher.encrypt_block(&mut block);
let post_sw_encrypt = cycles();
println!(
"it took {} cycles for sw encrypt",
post_sw_encrypt - pre_sw_encrypt
);
let sw_encrypted = block.clone();
let pre_sw_decrypt = cycles();
cipher.decrypt_block(&mut block);
let post_sw_decrypt = cycles();
println!(
"it took {} cycles for sw decrypt",
post_sw_decrypt - pre_sw_decrypt
);
let sw_decrypted = block;
assert!(&sw_encrypted as &[u8] == &hw_encrypted);
assert!(&sw_decrypted as &[u8] == &hw_decrypted);
println!("done");
loop {}
}

View File

@ -1,117 +0,0 @@
//! Encrypt/Decrypt a message using AES
//% CHIPS: esp32c3 esp32c6 esp32h2 esp32s3
#![no_std]
#![no_main]
use aes::{
cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt, KeyInit},
Aes128 as Aes128SW,
};
use esp_backtrace as _;
use esp_hal::{
aes::{
dma::{CipherMode, WithDmaAes},
Aes,
Mode,
},
dma::{Dma, DmaPriority},
dma_buffers,
peripherals::Peripherals,
prelude::*,
};
use esp_println::println;
use examples::cycles;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let dma = Dma::new(peripherals.DMA);
let dma_channel = dma.channel0;
let (input, mut tx_descriptors, mut output, mut rx_descriptors) = dma_buffers!(16, 16);
let mut aes = Aes::new(peripherals.AES).with_dma(dma_channel.configure(
false,
&mut tx_descriptors,
&mut rx_descriptors,
DmaPriority::Priority0,
));
let keytext = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
input.copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let pre_hw_encrypt = cycles();
let transfer = aes
.process(
&input,
&mut output,
Mode::Encryption128,
CipherMode::Ecb,
keytext,
)
.unwrap();
transfer.wait().unwrap();
let post_hw_encrypt = cycles();
println!(
"it took {} cycles for hw encrypt",
post_hw_encrypt - pre_hw_encrypt
);
let mut hw_encrypted = [0u8; 16];
(&mut hw_encrypted[..]).copy_from_slice(output);
input.copy_from_slice(output);
let pre_hw_decrypt = cycles();
let transfer = aes
.process(
&input,
&mut output,
Mode::Decryption128,
CipherMode::Ecb,
keytext,
)
.unwrap();
transfer.wait().unwrap();
let post_hw_decrypt = cycles();
println!(
"it took {} cycles for hw decrypt",
post_hw_decrypt - pre_hw_decrypt
);
let mut hw_decrypted = [0u8; 16];
(&mut hw_decrypted[..]).copy_from_slice(output);
// create an array with aes block size
let mut block_buf = [0_u8; 16];
block_buf[..].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let key = GenericArray::from(keytext);
let mut block = GenericArray::from(block_buf);
let cipher = Aes128SW::new(&key);
let pre_sw_encrypt = cycles();
cipher.encrypt_block(&mut block);
let post_sw_encrypt = cycles();
println!(
"it took {} cycles for sw encrypt",
post_sw_encrypt - pre_sw_encrypt
);
let sw_encrypted = block.clone();
let pre_sw_decrypt = cycles();
cipher.decrypt_block(&mut block);
let post_sw_decrypt = cycles();
println!(
"it took {} cycles for sw decrypt",
post_sw_decrypt - pre_sw_decrypt
);
let sw_decrypted = block.clone();
assert!(&sw_encrypted as &[u8] == &hw_encrypted);
assert!(&sw_decrypted as &[u8] == &hw_decrypted);
println!("done");
loop {}
}

View File

@ -27,8 +27,6 @@ fn main() -> ! {
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let mut led = Output::new(io.pins.gpio0, Level::High); let mut led = Output::new(io.pins.gpio0, Level::High);
// Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop.
let delay = Delay::new(&clocks); let delay = Delay::new(&clocks);
loop { loop {

View File

@ -41,11 +41,8 @@ fn main() -> ! {
let button = AnyInput::new(button, Pull::Up); let button = AnyInput::new(button, Pull::Up);
// You can use `into` or `degrade`:
let mut pins = [led1, led2, led3]; let mut pins = [led1, led2, led3];
// Initialize the `Delay` peripheral, and use it to toggle the LED state
// in a loop:
let delay = Delay::new(&clocks); let delay = Delay::new(&clocks);
loop { loop {

View File

@ -1,60 +0,0 @@
//! This demos a simple monitor for the XTAL frequency, by relying on a special
//! feature of the TIMG0 (Timer Group 0). This feature counts the number of XTAL
//! clock cycles within a given number of RTC_SLOW_CLK cycles.
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
#![no_std]
#![no_main]
use core::cell::RefCell;
use critical_section::Mutex;
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
peripherals::Peripherals,
prelude::*,
rtc_cntl::Rtc,
system::SystemControl,
};
use esp_println::println;
static RTC: Mutex<RefCell<Option<Rtc>>> = Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = SystemControl::new(peripherals.SYSTEM);
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let mut rtc = Rtc::new(peripherals.LPWR, Some(interrupt_handler));
rtc.rwdt.set_timeout(2000.millis());
rtc.rwdt.listen();
println!(
"{: <10} XTAL frequency: {} MHz",
"[Expected]",
clocks.xtal_clock.to_MHz()
);
critical_section::with(|cs| RTC.borrow_ref_mut(cs).replace(rtc));
loop {}
}
#[handler(priority = esp_hal::interrupt::Priority::min())]
fn interrupt_handler() {
critical_section::with(|cs| {
let mut rtc = RTC.borrow_ref_mut(cs);
let rtc = rtc.as_mut().unwrap();
println!(
"{: <10} XTAL frequency: {} MHz",
"[Monitor]",
rtc.estimate_xtal_frequency()
);
rtc.rwdt.clear_interrupt();
});
}

View File

@ -1,96 +0,0 @@
//! This shows example usage of the CRC functions in ROM
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
#![no_std]
#![no_main]
use core::fmt::Write;
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
delay::Delay,
peripherals::Peripherals,
prelude::*,
rom::{crc, md5},
system::SystemControl,
uart::Uart,
};
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = SystemControl::new(peripherals.SYSTEM);
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let delay = Delay::new(&clocks);
let mut uart0 = Uart::new(peripherals.UART0, &clocks);
let data = "123456789";
let sentence = "The quick brown fox jumps over a lazy dog";
writeln!(
uart0,
"Performing CRC calculations on test string \"{data}\""
)
.unwrap();
loop {
let crc_hdlc = crc::crc32_le(!0xffffffff, data.as_ref());
let crc_bzip2 = crc::crc32_be(!0xffffffff, data.as_ref());
let crc_mpeg2 = !crc::crc32_be(!0xffffffff, data.as_ref());
let crc_cksum = crc::crc32_be(!0, data.as_ref());
let crc_kermit = !crc::crc16_le(!0, data.as_ref());
let crc_genibus = crc::crc16_be(!0xffff, data.as_ref());
let crc_rohc = !crc::crc8_le(!0xff, data.as_ref());
let crc_smbus = !crc::crc8_be(!0, data.as_ref());
assert_eq!(crc_hdlc, 0xcbf43926);
assert_eq!(crc_bzip2, 0xfc891918);
assert_eq!(crc_mpeg2, 0x0376e6e7);
assert_eq!(crc_cksum, 0x765e7680);
assert_eq!(crc_kermit, 0x2189);
assert_eq!(crc_genibus, 0xd64e);
assert_eq!(crc_rohc, 0xd0);
assert_eq!(crc_smbus, 0xf4);
// Hash the sentence one word at a time to *really* test the context
// Use Peekable while iter_intersperse is unstable
let mut md5_ctx = md5::Context::new();
let mut it = sentence.split_whitespace().peekable();
while let Some(word) = it.next() {
md5_ctx.consume(word);
if it.peek().is_some() {
md5_ctx.consume(" ");
}
}
let md5_digest = md5_ctx.compute();
assert_eq!(
md5_digest,
md5::Digest([
0x30, 0xde, 0xd8, 0x07, 0xd6, 0x5e, 0xe0, 0x37, 0x0f, 0xc6, 0xd7, 0x3d, 0x6a, 0xb5,
0x5a, 0x95
])
);
writeln!(
uart0,
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x} {}",
crc_hdlc,
crc_bzip2,
crc_mpeg2,
crc_cksum,
crc_kermit,
crc_genibus,
crc_rohc,
crc_smbus,
md5_digest
)
.unwrap();
delay.delay(1.secs());
}
}

View File

@ -1,91 +0,0 @@
#![no_main]
#![no_std]
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2
use core::{arch::asm, cell::RefCell};
use critical_section::Mutex;
use esp_backtrace as _;
use esp_hal::{
interrupt::{self, CpuInterrupt, Priority},
peripherals::{Interrupt, Peripherals},
prelude::*,
system::{SoftwareInterrupt, SystemControl},
};
static SWINT0: Mutex<RefCell<Option<SoftwareInterrupt<0>>>> = Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
cfg_if::cfg_if! {
if #[cfg(any(feature = "esp32c6", feature = "esp32h2"))] {
let cpu_intr = &peripherals.INTPRI;
} else {
let cpu_intr = &peripherals.SYSTEM;
}
}
let sw0_trigger_addr = cpu_intr.cpu_intr_from_cpu_0() as *const _ as u32;
let system = SystemControl::new(peripherals.SYSTEM);
let sw_int = system.software_interrupt_control;
critical_section::with(|cs| {
SWINT0
.borrow_ref_mut(cs)
.replace(sw_int.software_interrupt0)
});
interrupt::enable_direct(
Interrupt::FROM_CPU_INTR0,
Priority::Priority3,
CpuInterrupt::Interrupt20,
)
.unwrap();
unsafe {
asm!(
"
csrrwi x0, 0x7e0, 1 #what to count, for cycles write 1 for instructions write 2
csrrwi x0, 0x7e1, 0 #disable counter
csrrwi x0, 0x7e2, 0 #reset counter
"
);
}
// interrupt is raised from assembly for max timer granularity.
unsafe {
asm!(
"
li {bit}, 1 # Flip flag (bit 0)
csrrwi x0, 0x7e1, 1 # enable timer
sw {bit}, 0({addr}) # trigger FROM_CPU_INTR0
",
options(nostack),
addr = in(reg) sw0_trigger_addr,
bit = out(reg) _,
)
}
esp_println::println!("Returned");
loop {}
}
#[no_mangle]
fn interrupt20() {
unsafe { asm!("csrrwi x0, 0x7e1, 0 #disable timer") }
critical_section::with(|cs| {
SWINT0.borrow_ref(cs).as_ref().unwrap().reset();
});
let mut perf_counter: u32 = 0;
unsafe {
asm!(
"
csrr {x}, 0x7e2
",
options(nostack),
x = inout(reg) perf_counter,
)
};
esp_println::println!("Performance counter:{}", perf_counter);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,50 +0,0 @@
//! embassy hello world systimer
//!
//! This is an example of running the embassy executor with multiple tasks
//! concurrently using the systimer time driver.
//!
//! It's not supported on ESP32, on ESP32-S2 the frequency of the systimer is different (so it's left out here)
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 esp32s3
//% FEATURES: embassy embassy-time-systick-16mhz embassy-generic-timers
#![no_std]
#![no_main]
use embassy_executor::Spawner;
use embassy_time::{Duration, Timer};
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
embassy,
peripherals::Peripherals,
prelude::*,
system::SystemControl,
timer::systimer::SystemTimer,
};
#[embassy_executor::task]
async fn run() {
loop {
esp_println::println!("Hello world from embassy using esp-hal-async!");
Timer::after(Duration::from_millis(1_000)).await;
}
}
#[main]
async fn main(spawner: Spawner) {
esp_println::println!("Init!");
let peripherals = Peripherals::take();
let system = SystemControl::new(peripherals.SYSTEM);
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let systimer = SystemTimer::new_async(peripherals.SYSTIMER);
embassy::init(&clocks, systimer);
spawner.spawn(run()).ok();
loop {
esp_println::println!("Bing!");
Timer::after(Duration::from_millis(5_000)).await;
}
}

View File

@ -11,8 +11,7 @@
//! demonstrates that this task will continue to run even while the low //! demonstrates that this task will continue to run even while the low
//! priority blocking task is running. //! priority blocking task is running.
// HINT: At first it looks a bit suspicious that we need *two* executor features enabled here but that's because we are really using // The thread-executor is created by the `#[main]` macro and is used to spawn `low_prio_async` and `low_prio_blocking`.
// both together. The thread-executor is created by the `#[main]` macro and is used to spawn `low_prio_async` and `low_prio_blocking`.
// The interrupt-executor is created in `main` and is used to spawn `high_prio`. // The interrupt-executor is created in `main` and is used to spawn `high_prio`.
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3

View File

@ -1,41 +0,0 @@
//! embassy systimer delay
//!
//! This is an example of using the `DelayNs` trait implementation
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% FEATURES: embassy embassy-time-timg0 embassy-generic-timers async
#![no_std]
#![no_main]
use embassy_executor::Spawner;
use embedded_hal_async::delay::DelayNs;
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
embassy,
peripherals::Peripherals,
prelude::*,
system::SystemControl,
timer::{systimer::SystemTimer, timg::TimerGroup},
};
#[main]
async fn main(_spawner: Spawner) {
esp_println::println!("Init!");
let peripherals = Peripherals::take();
let system = SystemControl::new(peripherals.SYSTEM);
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0);
let mut alarm0 = SystemTimer::new_async(peripherals.SYSTIMER)
.alarm0
.into_periodic();
loop {
esp_println::println!("Bing!");
alarm0.delay_ms(1000).await;
}
}

View File

@ -51,8 +51,6 @@ fn main() -> ! {
}); });
led.set_high(); led.set_high();
// Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop.
let delay = Delay::new(&clocks); let delay = Delay::new(&clocks);
loop { loop {

View File

@ -66,8 +66,6 @@ fn main() -> ! {
let rmt_buffer = smartLedBuffer!(1); let rmt_buffer = smartLedBuffer!(1);
let mut led = SmartLedsAdapter::new(rmt.channel0, led_pin, rmt_buffer, &clocks); let mut led = SmartLedsAdapter::new(rmt.channel0, led_pin, rmt_buffer, &clocks);
// Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop.
let delay = Delay::new(&clocks); let delay = Delay::new(&clocks);
let mut color = Hsv { let mut color = Hsv {

View File

@ -1,110 +0,0 @@
//! Interrupt Preemption
//!
//! An example of how an interrupt can be preempted by another with higher
//! priority. Should show higher-numbered software interrupts happening during
//! the handling of lower-numbered ones.
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
#![no_std]
#![no_main]
use core::cell::RefCell;
use critical_section::Mutex;
use esp_backtrace as _;
use esp_hal::{
peripherals::Peripherals,
prelude::*,
system::{SoftwareInterrupt, SystemControl},
};
static SWINT0: Mutex<RefCell<Option<SoftwareInterrupt<0>>>> = Mutex::new(RefCell::new(None));
static SWINT1: Mutex<RefCell<Option<SoftwareInterrupt<1>>>> = Mutex::new(RefCell::new(None));
static SWINT2: Mutex<RefCell<Option<SoftwareInterrupt<2>>>> = Mutex::new(RefCell::new(None));
static SWINT3: Mutex<RefCell<Option<SoftwareInterrupt<3>>>> = Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = SystemControl::new(peripherals.SYSTEM);
let mut sw_int = system.software_interrupt_control;
critical_section::with(|cs| {
sw_int
.software_interrupt0
.set_interrupt_handler(swint0_handler);
SWINT0
.borrow_ref_mut(cs)
.replace(sw_int.software_interrupt0);
sw_int
.software_interrupt1
.set_interrupt_handler(swint1_handler);
SWINT1
.borrow_ref_mut(cs)
.replace(sw_int.software_interrupt1);
sw_int
.software_interrupt2
.set_interrupt_handler(swint2_handler);
SWINT2
.borrow_ref_mut(cs)
.replace(sw_int.software_interrupt2);
sw_int
.software_interrupt3
.set_interrupt_handler(swint3_handler);
SWINT3
.borrow_ref_mut(cs)
.replace(sw_int.software_interrupt3);
});
// Raise mid priority interrupt.
//
// The handler raises one interrupt at lower priority, one at same and one at
// higher. We expect to see the higher priority served immeiately before
// exiting the handler Once the handler is exited we expect to see same
// priority and low priority interrupts served in that order.
critical_section::with(|cs| {
SWINT1.borrow_ref(cs).as_ref().unwrap().raise();
});
loop {}
}
#[handler(priority = esp_hal::interrupt::Priority::Priority1)]
fn swint0_handler() {
esp_println::println!("SW interrupt0");
critical_section::with(|cs| {
SWINT0.borrow_ref(cs).as_ref().unwrap().reset();
});
}
#[handler(priority = esp_hal::interrupt::Priority::Priority2)]
fn swint1_handler() {
esp_println::println!("SW interrupt1 entry");
critical_section::with(|cs| {
SWINT1.borrow_ref(cs).as_ref().unwrap().reset();
SWINT2.borrow_ref(cs).as_ref().unwrap().raise(); // raise interrupt at same priority
SWINT3.borrow_ref(cs).as_ref().unwrap().raise(); // raise interrupt at higher priority
SWINT0.borrow_ref(cs).as_ref().unwrap().raise(); // raise interrupt at lower priority
});
esp_println::println!("SW interrupt1 exit");
}
#[handler(priority = esp_hal::interrupt::Priority::Priority2)]
fn swint2_handler() {
esp_println::println!("SW interrupt2");
critical_section::with(|cs| {
SWINT2.borrow_ref(cs).as_ref().unwrap().reset();
});
}
#[handler(priority = esp_hal::interrupt::Priority::Priority3)]
fn swint3_handler() {
esp_println::println!("SW interrupt3");
critical_section::with(|cs| {
SWINT3.borrow_ref(cs).as_ref().unwrap().reset();
});
}

View File

@ -1,185 +0,0 @@
//! Demonstrates the use of the RSA peripheral and compares the speed of
//! multiple arithmetic operations.
//% CHIPS: esp32 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
#![no_std]
#![no_main]
use crypto_bigint::{
modular::runtime_mod::{DynResidue, DynResidueParams},
Uint,
U1024,
U512,
};
use esp_backtrace as _;
use esp_hal::{
peripherals::Peripherals,
prelude::*,
rsa::{
operand_sizes,
Rsa,
RsaModularExponentiation,
RsaModularMultiplication,
RsaMultiplication,
},
};
use esp_println::println;
use examples::cycles;
const BIGNUM_1: U512 = Uint::from_be_hex(
"c7f61058f96db3bd87dbab08ab03b4f7f2f864eac249144adea6a65f97803b719d8ca980b7b3c0389c1c7c6\
7dc353c5e0ec11f5fc8ce7f6073796cc8f73fa878",
);
const BIGNUM_2: U512 = Uint::from_be_hex(
"1763db3344e97be15d04de4868badb12a38046bb793f7630d87cf100aa1c759afac15a01f3c4c83ec2d2f66\
6bd22f71c3c1f075ec0e2cb0cb29994d091b73f51",
);
const BIGNUM_3: U512 = Uint::from_be_hex(
"6b6bb3d2b6cbeb45a769eaa0384e611e1b89b0c9b45a045aca1c5fd6e8785b38df7118cf5dd45b9b63d293b\
67aeafa9ba25feb8712f188cb139b7d9b9af1c361",
);
const fn compute_r(modulus: &U512) -> U512 {
let mut d = [0_u32; U512::LIMBS * 2 + 1];
d[d.len() - 1] = 1;
let d = Uint::from_words(d);
d.const_rem(&modulus.resize()).0.resize()
}
const fn compute_mprime(modulus: &U512) -> u32 {
let m_inv = modulus.inv_mod2k(32).to_words()[0];
(-1 * m_inv as i64 % 4294967296) as u32
}
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let mut rsa = Rsa::new(peripherals.RSA, None);
nb::block!(rsa.ready()).unwrap();
mod_exp_example(&mut rsa);
mod_multi_example(&mut rsa);
multiplication_example(&mut rsa);
loop {}
}
fn mod_multi_example(rsa: &mut Rsa<esp_hal::Blocking>) {
let mut outbuf = [0_u32; U512::LIMBS];
let mut mod_multi = RsaModularMultiplication::<operand_sizes::Op512, esp_hal::Blocking>::new(
rsa,
#[cfg(not(feature = "esp32"))]
BIGNUM_1.as_words(),
#[cfg(not(feature = "esp32"))]
BIGNUM_2.as_words(),
BIGNUM_3.as_words(),
compute_mprime(&BIGNUM_3),
);
let r = compute_r(&BIGNUM_3);
let pre_hw_modmul = cycles();
#[cfg(feature = "esp32")]
{
mod_multi.start_step1(BIGNUM_1.as_words(), r.as_words());
mod_multi.start_step2(BIGNUM_2.as_words());
}
#[cfg(not(feature = "esp32"))]
{
mod_multi.start_modular_multiplication(r.as_words());
}
mod_multi.read_results(&mut outbuf);
let post_hw_modmul = cycles();
println!(
"it took {} cycles for hw modular multiplication",
post_hw_modmul - pre_hw_modmul
);
let residue_params = DynResidueParams::new(&BIGNUM_3);
let residue_num1 = DynResidue::new(&BIGNUM_1, residue_params);
let residue_num2 = DynResidue::new(&BIGNUM_2, residue_params);
let pre_sw_exp = cycles();
let sw_out = residue_num1.mul(&residue_num2);
let post_sw_exp = cycles();
println!(
"it took {} cycles for sw modular multiplication",
post_sw_exp - pre_sw_exp
);
assert_eq!(U512::from_words(outbuf), sw_out.retrieve());
println!("modular multiplication done");
}
fn mod_exp_example(rsa: &mut Rsa<esp_hal::Blocking>) {
#[cfg(not(feature = "esp32"))]
{
rsa.enable_disable_constant_time_acceleration(true);
rsa.enable_disable_search_acceleration(true);
}
let mut outbuf = [0_u32; U512::LIMBS];
let mut mod_exp = RsaModularExponentiation::<operand_sizes::Op512, esp_hal::Blocking>::new(
rsa,
BIGNUM_2.as_words(),
BIGNUM_3.as_words(),
compute_mprime(&BIGNUM_3),
);
let r = compute_r(&BIGNUM_3);
let base = &BIGNUM_1.as_words();
let pre_hw_exp = cycles();
mod_exp.start_exponentiation(&base, r.as_words());
mod_exp.read_results(&mut outbuf);
let post_hw_exp = cycles();
println!(
"it took {} cycles for hw modular exponentiation",
post_hw_exp - pre_hw_exp
);
let residue_params = DynResidueParams::new(&BIGNUM_3);
let residue = DynResidue::new(&BIGNUM_1, residue_params);
let pre_sw_exp = cycles();
let sw_out = residue.pow(&BIGNUM_2);
let post_sw_exp = cycles();
println!(
"it took {} cycles for sw modular exponentiation",
post_sw_exp - pre_sw_exp
);
assert_eq!(U512::from_words(outbuf), sw_out.retrieve());
println!("modular exponentiation done");
}
fn multiplication_example(rsa: &mut Rsa<esp_hal::Blocking>) {
let mut outbuf = [0_u32; U1024::LIMBS];
let operand_a = BIGNUM_1.as_words();
let operand_b = BIGNUM_2.as_words();
let pre_hw_mul = cycles();
#[cfg(feature = "esp32")]
{
let mut rsamulti = RsaMultiplication::<operand_sizes::Op512, esp_hal::Blocking>::new(rsa);
rsamulti.start_multiplication(operand_a, operand_b);
rsamulti.read_results(&mut outbuf);
}
#[cfg(not(feature = "esp32"))]
{
let mut rsamulti =
RsaMultiplication::<operand_sizes::Op512, esp_hal::Blocking>::new(rsa, operand_a);
rsamulti.start_multiplication(operand_b);
rsamulti.read_results(&mut outbuf);
}
let post_hw_mul = cycles();
println!(
"it took {} cycles for hw multiplication",
post_hw_mul - pre_hw_mul
);
let pre_sw_mul = cycles();
let sw_out = BIGNUM_1.mul_wide(&BIGNUM_2);
let post_sw_mul = cycles();
println!(
"it took {} cycles for sw multiplication",
post_sw_mul - pre_sw_mul
);
assert_eq!(U1024::from_words(outbuf), sw_out.1.concat(&sw_out.0));
println!("multiplication done");
}

View File

@ -1,75 +0,0 @@
//! Demonstrates the use of the SHA peripheral and compares the speed of
//! hardware-accelerated and pure software hashing.
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
#![no_std]
#![no_main]
use esp_backtrace as _;
use esp_hal::{
peripherals::Peripherals,
prelude::*,
sha::{Sha, ShaMode},
};
use esp_println::println;
use examples::cycles;
use nb::block;
use sha2::{Digest, Sha256};
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let source_data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
let mut remaining = source_data;
#[cfg(not(feature = "esp32"))]
let mut hasher = Sha::new(peripherals.SHA, ShaMode::SHA256, None);
#[cfg(feature = "esp32")]
let mut hasher = Sha::new(peripherals.SHA, ShaMode::SHA256);
// Short hashes can be created by decreasing the output buffer to the desired
// length
let mut output = [0u8; 32];
let pre_calc = cycles();
// The hardware implementation takes a subslice of the input, and returns the
// unprocessed parts The unprocessed parts can be input in the next
// iteration, you can always add more data until finish() is called. After
// finish() is called update()'s will contribute to a new hash which
// can be extracted again with finish().
while remaining.len() > 0 {
// Can add println to view progress, however println takes a few orders of
// magnitude longer than the Sha function itself so not useful for
// comparing processing time println!("Remaining len: {}",
// remaining.len());
// All the HW Sha functions are infallible so unwrap is fine to use if you use
// block!
remaining = block!(hasher.update(remaining)).unwrap();
}
// Finish can be called as many times as desired to get mutliple copies of the
// output.
block!(hasher.finish(output.as_mut_slice())).unwrap();
let post_calc = cycles();
let hw_time = post_calc - pre_calc;
println!("Took {} cycles", hw_time);
println!("SHA256 Hash output {:02x?}", output);
let pre_calc = cycles();
let mut hasher = Sha256::new();
hasher.update(source_data);
let soft_result = hasher.finalize();
let post_calc = cycles();
let soft_time = post_calc - pre_calc;
println!("Took {} cycles", soft_time);
println!("SHA256 Hash output {:02x?}", soft_result);
assert_eq!(output, soft_result[..]);
println!("HW SHA is {}x faster", soft_time / hw_time);
loop {}
}

View File

@ -1,162 +0,0 @@
//! SPI loopback test
//!
//! Folowing pins are used:
//! SCLK GPIO0
//! MISO GPIO2
//! MOSI GPIO4
//! CS 1 GPIO5
//! CS 2 GPIO6
//! CS 3 GPIO7
//!
//! Folowing pins are used for ESP32:
//! SCLK GPIO0
//! MISO GPIO2
//! MOSI GPIO4
//! CS 1 GPIO5
//! CS 2 GPIO13
//! CS 3 GPIO14
//!
//! Depending on your target and the board you are using you have to change the
//! pins.
//!
//! This example transfers data via SPI.
//! Connect MISO and MOSI pins to see the outgoing data is read as incoming
//! data.
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% FEATURES: embedded-hal
#![no_std]
#![no_main]
use core::cell::RefCell;
use embedded_hal::spi::SpiDevice;
use embedded_hal_bus::spi::RefCellDevice;
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
delay::Delay,
gpio::{self, Io, Level, Output},
peripherals::Peripherals,
prelude::*,
spi::{master::Spi, SpiMode},
system::SystemControl,
};
use esp_println::{print, println};
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = SystemControl::new(peripherals.SYSTEM);
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let sclk = io.pins.gpio0;
let miso = io.pins.gpio2;
let mosi = io.pins.gpio4;
let spi_bus = Spi::new(peripherals.SPI2, 1000.kHz(), SpiMode::Mode0, &clocks).with_pins(
Some(sclk),
Some(mosi),
Some(miso),
gpio::NO_PIN,
);
let spi_bus = RefCell::new(spi_bus);
let mut spi_device_1 =
RefCellDevice::new_no_delay(&spi_bus, Output::new(io.pins.gpio5, Level::Low));
cfg_if::cfg_if! {
if #[cfg(feature = "esp32")] {
let mut spi_device_2 =
RefCellDevice::new_no_delay(&spi_bus, Output::new(io.pins.gpio13, Level::Low));
let mut spi_device_3 =
RefCellDevice::new_no_delay(&spi_bus, Output::new(io.pins.gpio14, Level::Low));
} else {
let mut spi_device_2 =
RefCellDevice::new_no_delay(&spi_bus, Output::new(io.pins.gpio6, Level::Low));
let mut spi_device_3 =
RefCellDevice::new_no_delay(&spi_bus, Output::new(io.pins.gpio7, Level::Low));
}
}
let delay = Delay::new(&clocks);
println!("=== SPI example with embedded-hal-1 traits ===");
loop {
// --- Symmetric transfer (Read as much as we write) ---
print!("Starting symmetric transfer...");
let write = [0xde, 0xad, 0xbe, 0xef];
let mut read: [u8; 4] = [0x00u8; 4];
spi_device_1.transfer(&mut read[..], &write[..]).unwrap();
assert_eq!(write, read);
spi_device_2.transfer(&mut read[..], &write[..]).unwrap();
spi_device_3.transfer(&mut read[..], &write[..]).unwrap();
println!(" SUCCESS");
delay.delay_millis(250);
// --- Asymmetric transfer (Read more than we write) ---
print!("Starting asymetric transfer (read > write)...");
let mut read: [u8; 4] = [0x00; 4];
spi_device_1
.transfer(&mut read[0..2], &write[..])
.expect("Asymmetric transfer failed");
assert_eq!(write[0], read[0]);
assert_eq!(read[2], 0x00u8);
spi_device_2
.transfer(&mut read[0..2], &write[..])
.expect("Asymmetric transfer failed");
spi_device_3
.transfer(&mut read[0..2], &write[..])
.expect("Asymmetric transfer failed");
println!(" SUCCESS");
delay.delay_millis(250);
// --- Symmetric transfer with huge buffer ---
// Only your RAM is the limit!
print!("Starting huge transfer...");
let mut write = [0x55u8; 4096];
for byte in 0..write.len() {
write[byte] = byte as u8;
}
let mut read = [0x00u8; 4096];
spi_device_1
.transfer(&mut read[..], &write[..])
.expect("Huge transfer failed");
assert_eq!(write, read);
spi_device_2
.transfer(&mut read[..], &write[..])
.expect("Huge transfer failed");
spi_device_3
.transfer(&mut read[..], &write[..])
.expect("Huge transfer failed");
println!(" SUCCESS");
delay.delay_millis(250);
// --- Symmetric transfer with huge buffer in-place (No additional allocation
// needed) ---
print!("Starting huge transfer (in-place)...");
let mut write = [0x55u8; 4096];
for byte in 0..write.len() {
write[byte] = byte as u8;
}
spi_device_1
.transfer_in_place(&mut write[..])
.expect("Huge transfer failed");
for byte in 0..write.len() {
assert_eq!(write[byte], byte as u8);
}
spi_device_2
.transfer_in_place(&mut write[..])
.expect("Huge transfer failed");
spi_device_3
.transfer_in_place(&mut write[..])
.expect("Huge transfer failed");
println!(" SUCCESS");
delay.delay_millis(250);
}
}

View File

@ -1,108 +0,0 @@
//! SPI loopback test
//!
//! Folowing pins are used:
//! SCLK GPIO0
//! MISO GPIO2
//! MOSI GPIO4
//! CS GPIO5
//!
//! Depending on your target and the board you are using you have to change the
//! pins.
//!
//! This example transfers data via SPI.
//! Connect MISO and MOSI pins to see the outgoing data is read as incoming
//! data.
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% FEATURES: embedded-hal
#![no_std]
#![no_main]
use embedded_hal::spi::SpiBus;
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
delay::Delay,
gpio::Io,
peripherals::Peripherals,
prelude::*,
spi::{master::Spi, SpiMode},
system::SystemControl,
};
use esp_println::{print, println};
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = SystemControl::new(peripherals.SYSTEM);
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let sclk = io.pins.gpio0;
let miso = io.pins.gpio2;
let mosi = io.pins.gpio4;
let cs = io.pins.gpio5;
let mut spi = Spi::new(peripherals.SPI2, 1000.kHz(), SpiMode::Mode0, &clocks).with_pins(
Some(sclk),
Some(mosi),
Some(miso),
Some(cs),
);
let delay = Delay::new(&clocks);
println!("=== SPI example with embedded-hal-1 traits ===");
loop {
// --- Symmetric transfer (Read as much as we write) ---
print!("Starting symmetric transfer...");
let write = [0xde, 0xad, 0xbe, 0xef];
let mut read: [u8; 4] = [0x00u8; 4];
SpiBus::transfer(&mut spi, &mut read[..], &write[..]).expect("Symmetric transfer failed");
assert_eq!(write, read);
println!(" SUCCESS");
delay.delay_millis(250);
// --- Asymmetric transfer (Read more than we write) ---
print!("Starting asymetric transfer (read > write)...");
let mut read: [u8; 4] = [0x00; 4];
SpiBus::transfer(&mut spi, &mut read[0..2], &write[..])
.expect("Asymmetric transfer failed");
assert_eq!(write[0], read[0]);
assert_eq!(read[2], 0x00u8);
println!(" SUCCESS");
delay.delay_millis(250);
// --- Symmetric transfer with huge buffer ---
// Only your RAM is the limit!
print!("Starting huge transfer...");
let mut write = [0x55u8; 4096];
for byte in 0..write.len() {
write[byte] = byte as u8;
}
let mut read = [0x00u8; 4096];
SpiBus::transfer(&mut spi, &mut read[..], &write[..]).expect("Huge transfer failed");
assert_eq!(write, read);
println!(" SUCCESS");
delay.delay_millis(250);
// --- Symmetric transfer with huge buffer in-place (No additional allocation
// needed) ---
print!("Starting huge transfer (in-place)...");
let mut write = [0x55u8; 4096];
for byte in 0..write.len() {
write[byte] = byte as u8;
}
SpiBus::transfer_in_place(&mut spi, &mut write[..]).expect("Huge transfer failed");
for byte in 0..write.len() {
assert_eq!(write[byte], byte as u8);
}
println!(" SUCCESS");
delay.delay_millis(250);
}
}

View File

@ -63,8 +63,6 @@ fn main() -> ! {
interrupt::enable(Interrupt::SYSTIMER_TARGET1, Priority::Priority3).unwrap(); interrupt::enable(Interrupt::SYSTIMER_TARGET1, Priority::Priority3).unwrap();
interrupt::enable(Interrupt::SYSTIMER_TARGET2, Priority::Priority3).unwrap(); interrupt::enable(Interrupt::SYSTIMER_TARGET2, Priority::Priority3).unwrap();
// Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop.
let delay = Delay::new(&clocks); let delay = Delay::new(&clocks);
loop { loop {

View File

@ -36,6 +36,10 @@ harness = false
name = "gpio" name = "gpio"
harness = false harness = false
[[test]]
name = "interrupt"
harness = false
[[test]] [[test]]
name = "spi_full_duplex" name = "spi_full_duplex"
harness = false harness = false

126
hil-test/tests/interrupt.rs Normal file
View File

@ -0,0 +1,126 @@
//! Interrupt Test
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2
#![no_std]
#![no_main]
use core::{arch::asm, cell::RefCell};
use critical_section::Mutex;
use defmt::info;
use defmt_rtt as _;
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
interrupt::{self, *},
peripherals::{Interrupt, Peripherals},
system::{SoftwareInterrupt, SystemControl},
};
static SWINT0: Mutex<RefCell<Option<SoftwareInterrupt<0>>>> = Mutex::new(RefCell::new(None));
struct Context {
sw0_trigger_addr: u32,
}
impl Context {
pub fn init() -> Self {
let peripherals = Peripherals::take();
cfg_if::cfg_if! {
if #[cfg(any(feature = "esp32c6", feature = "esp32h2"))] {
let cpu_intr = &peripherals.INTPRI;
} else {
let cpu_intr = &peripherals.SYSTEM;
}
}
let sw0_trigger_addr = cpu_intr.cpu_intr_from_cpu_0() as *const _ as u32;
let system = SystemControl::new(peripherals.SYSTEM);
let _clocks = ClockControl::max(system.clock_control).freeze();
let sw_int = system.software_interrupt_control;
critical_section::with(|cs| {
SWINT0
.borrow_ref_mut(cs)
.replace(sw_int.software_interrupt0)
});
interrupt::enable_direct(
Interrupt::FROM_CPU_INTR0,
Priority::Priority3,
CpuInterrupt::Interrupt20,
)
.unwrap();
Context { sw0_trigger_addr }
}
}
#[no_mangle]
fn interrupt20() {
unsafe { asm!("csrrwi x0, 0x7e1, 0 #disable timer") }
critical_section::with(|cs| {
SWINT0.borrow_ref(cs).as_ref().unwrap().reset();
});
let mut perf_counter: u32 = 0;
unsafe {
asm!(
"
csrr {x}, 0x7e2
",
options(nostack),
x = inout(reg) perf_counter,
)
};
info!("Performance counter:{}", perf_counter);
// TODO these values should be adjusted to catch smaller regressions
cfg_if::cfg_if! {
if #[cfg(any(feature = "esp32c3", feature = "esp32c2"))] {
assert!(perf_counter < 1100);
} else {
assert!(perf_counter < 750);
}
}
}
#[cfg(test)]
#[embedded_test::tests]
mod tests {
use super::*;
#[init]
fn init() -> Context {
Context::init()
}
#[test]
fn interrupt_latency(ctx: Context) {
unsafe {
asm!(
"
csrrwi x0, 0x7e0, 1 #what to count, for cycles write 1 for instructions write 2
csrrwi x0, 0x7e1, 0 #disable counter
csrrwi x0, 0x7e2, 0 #reset counter
"
);
}
// interrupt is raised from assembly for max timer granularity.
unsafe {
asm!(
"
li {bit}, 1 # Flip flag (bit 0)
csrrwi x0, 0x7e1, 1 # enable timer
sw {bit}, 0({addr}) # trigger FROM_CPU_INTR0
",
options(nostack),
addr = in(reg) ctx.sw0_trigger_addr,
bit = out(reg) _,
)
}
}
}