Implement SPI

This commit is contained in:
bjoernQ 2022-03-07 17:39:25 +01:00
parent e7eea75ef8
commit 3f7a675b1e
10 changed files with 875 additions and 3 deletions

View File

@ -39,6 +39,7 @@ pub mod prelude;
#[cfg(not(feature = "esp32c3"))]
pub mod rtc_cntl;
pub mod serial;
pub mod spi;
pub mod timer;
pub use delay::Delay;
@ -49,6 +50,7 @@ pub use procmacros::ram;
#[cfg(not(feature = "esp32c3"))]
pub use rtc_cntl::RtcCntl;
pub use serial::Serial;
pub use spi::Spi;
pub use timer::Timer;
/// Enumeration of CPU cores

605
esp-hal-common/src/spi.rs Normal file
View File

@ -0,0 +1,605 @@
//! # Serial Peripheral Interface
//! To construct the SPI instances, use the `Spi::new` functions.
//!
//! ## Initialisation example
//! ```rust
//! let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
//! let sclk = io.pins.gpio12;
//! let miso = io.pins.gpio11;
//! let mosi = io.pins.gpio13;
//! let cs = io.pins.gpio10;
//!
//! let mut spi = hal::spi::Spi::new(
//! peripherals.SPI2,
//! sclk,
//! mosi,
//! miso,
//! cs,
//! 100_000,
//! embedded_hal::spi::MODE_0,
//! &mut peripherals.SYSTEM,
//! );
//! ```
use core::convert::Infallible;
use embedded_hal::spi::{FullDuplex, Mode};
use crate::{
pac::spi2::RegisterBlock,
types::{InputSignal, OutputSignal},
InputPin,
OutputPin,
};
#[cfg(feature = "esp32")]
type System = crate::pac::DPORT;
#[cfg(not(feature = "esp32"))]
type System = crate::pac::SYSTEM;
pub struct Spi<T> {
spi: T,
}
impl<T> Spi<T>
where
T: Instance,
{
/// Constructs an SPI instance in 8bit dataframe mode.
pub fn new<
SCK: OutputPin<OutputSignal = OutputSignal>,
MOSI: OutputPin<OutputSignal = OutputSignal>,
MISO: InputPin<InputSignal = InputSignal>,
CS: OutputPin<OutputSignal = OutputSignal>,
>(
spi: T,
mut sck: SCK,
mut mosi: MOSI,
mut miso: MISO,
mut cs: CS,
frequency: u32,
mode: Mode,
system: &mut System,
) -> Self {
sck.set_to_push_pull_output()
.connect_peripheral_to_output(spi.sclk_signal());
mosi.set_to_push_pull_output()
.connect_peripheral_to_output(spi.mosi_signal());
miso.set_to_input()
.connect_input_to_peripheral(spi.miso_signal());
cs.set_to_push_pull_output()
.connect_peripheral_to_output(spi.cs_signal());
spi.enable_peripheral(system);
let mut spi = Self { spi: spi };
spi.spi.setup(frequency);
spi.spi.init();
spi.spi.set_data_mode(mode);
spi
}
/// Return the raw interface to the underlying peripheral instance
pub fn free(self) -> T {
self.spi
}
}
impl<T> FullDuplex<u8> for Spi<T>
where
T: Instance,
{
type Error = Infallible;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
self.spi.read()
}
fn send(&mut self, word: u8) -> nb::Result<(), Self::Error> {
self.spi.send(word)
}
}
impl<T> embedded_hal::blocking::spi::Transfer<u8> for Spi<T>
where
T: Instance,
{
type Error = Infallible;
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
self.spi.transfer(words)
}
}
impl<T> embedded_hal::blocking::spi::Write<u8> for Spi<T>
where
T: Instance,
{
type Error = Infallible;
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
let mut words_mut = [0u8; 256];
words_mut[0..words.len()].clone_from_slice(&words[0..words.len()]);
self.spi.transfer(&mut words_mut[0..words.len()])?;
Ok(())
}
}
pub trait Instance {
fn register_block(&self) -> &RegisterBlock;
fn sclk_signal(&self) -> OutputSignal;
fn mosi_signal(&self) -> OutputSignal;
fn miso_signal(&self) -> InputSignal;
fn cs_signal(&self) -> OutputSignal;
fn enable_peripheral(&self, system: &mut System);
fn init(&mut self) {
let reg_block = self.register_block();
reg_block.user.modify(|_, w| {
w.usr_miso_highpart()
.clear_bit()
.usr_miso_highpart()
.clear_bit()
.doutdin()
.set_bit()
.usr_miso()
.set_bit()
.usr_mosi()
.set_bit()
.cs_hold()
.set_bit()
.usr_dummy_idle()
.set_bit()
.usr_addr()
.clear_bit()
.usr_command()
.clear_bit()
});
#[cfg(not(any(feature = "esp32", feature = "esp32s2")))]
reg_block.clk_gate.modify(|_, w| {
w.clk_en()
.set_bit()
.mst_clk_active()
.set_bit()
.mst_clk_sel()
.set_bit()
});
reg_block.ctrl.write(|w| unsafe { w.bits(0) });
#[cfg(not(feature = "esp32"))]
reg_block.misc.write(|w| unsafe { w.bits(0) });
reg_block.slave.write(|w| unsafe { w.bits(0) });
}
// taken from https://github.com/apache/incubator-nuttx/blob/8267a7618629838231256edfa666e44b5313348e/arch/risc-v/src/esp32c3/esp32c3_spi.c#L496
fn setup(&mut self, frequency: u32) {
const APB_CLK_FREQ: u32 = 80_000_000; // TODO this might not be always true
let reg_val: u32;
let duty_cycle = 128;
// In HW, n, h and l fields range from 1 to 64, pre ranges from 1 to 8K.
// The value written to register is one lower than the used value.
if frequency > ((APB_CLK_FREQ / 4) * 3) {
// Using APB frequency directly will give us the best result here.
reg_val = 1 << 31;
} else {
/* For best duty cycle resolution, we want n to be as close to 32 as
* possible, but we also need a pre/n combo that gets us as close as
* possible to the intended frequency. To do this, we bruteforce n and
* calculate the best pre to go along with that. If there's a choice
* between pre/n combos that give the same result, use the one with the
* higher n.
*/
let mut pre: i32;
let n: i32;
let mut h: i32;
let l: i32;
let mut bestn: i32 = -1;
let mut bestpre: i32 = -1;
let mut besterr: i32 = 0;
let mut errval: i32;
/* Start at n = 2. We need to be able to set h/l so we have at least
* one high and one low pulse.
*/
for n in 2..64 {
/* Effectively, this does:
* pre = round((APB_CLK_FREQ / n) / frequency)
*/
pre = ((APB_CLK_FREQ as i32/ n) + (frequency as i32 / 2)) / frequency as i32;
if pre <= 0 {
pre = 1;
}
if pre > 16 {
pre = 16;
}
errval = (APB_CLK_FREQ as i32 / (pre as i32 * n as i32) - frequency as i32).abs();
if bestn == -1 || errval <= besterr {
besterr = errval;
bestn = n as i32;
bestpre = pre as i32;
}
}
n = bestn;
pre = bestpre as i32;
l = n;
/* Effectively, this does:
* h = round((duty_cycle * n) / 256)
*/
h = (duty_cycle * n + 127) / 256;
if h <= 0 {
h = 1;
}
reg_val = ((l as u32 - 1) << 0) |
((h as u32 - 1) << 6) |
((n as u32 - 1) << 12) |
((pre as u32 - 1) << 18);
}
self.register_block()
.clock
.write(|w| unsafe { w.bits(reg_val) });
}
#[cfg(not(feature = "esp32"))]
fn set_data_mode(&mut self, data_mode: embedded_hal::spi::Mode) -> &mut Self {
let reg_block = self.register_block();
match data_mode {
embedded_hal::spi::MODE_0 => {
reg_block.misc.modify(|_, w| w.ck_idle_edge().clear_bit());
reg_block.user.modify(|_, w| w.ck_out_edge().clear_bit());
}
embedded_hal::spi::MODE_1 => {
reg_block.misc.modify(|_, w| w.ck_idle_edge().clear_bit());
reg_block.user.modify(|_, w| w.ck_out_edge().set_bit());
}
embedded_hal::spi::MODE_2 => {
reg_block.misc.modify(|_, w| w.ck_idle_edge().set_bit());
reg_block.user.modify(|_, w| w.ck_out_edge().set_bit());
}
embedded_hal::spi::MODE_3 => {
reg_block.misc.modify(|_, w| w.ck_idle_edge().set_bit());
reg_block.user.modify(|_, w| w.ck_out_edge().clear_bit());
}
}
self
}
#[cfg(feature = "esp32")]
fn set_data_mode(&mut self, data_mode: embedded_hal::spi::Mode) -> &mut Self {
let reg_block = self.register_block();
match data_mode {
embedded_hal::spi::MODE_0 => {
reg_block.pin.modify(|_, w| w.ck_idle_edge().clear_bit());
reg_block.user.modify(|_, w| w.ck_out_edge().clear_bit());
}
embedded_hal::spi::MODE_1 => {
reg_block.pin.modify(|_, w| w.ck_idle_edge().clear_bit());
reg_block.user.modify(|_, w| w.ck_out_edge().set_bit());
}
embedded_hal::spi::MODE_2 => {
reg_block.pin.modify(|_, w| w.ck_idle_edge().set_bit());
reg_block.user.modify(|_, w| w.ck_out_edge().set_bit());
}
embedded_hal::spi::MODE_3 => {
reg_block.pin.modify(|_, w| w.ck_idle_edge().set_bit());
reg_block.user.modify(|_, w| w.ck_out_edge().clear_bit());
}
}
self
}
fn read(&mut self) -> nb::Result<u8, Infallible> {
let reg_block = self.register_block();
if reg_block.cmd.read().usr().bit_is_set() {
return Err(nb::Error::WouldBlock);
}
Ok(u32::try_into(reg_block.w0.read().bits()).unwrap_or_default())
}
fn send(&mut self, word: u8) -> nb::Result<(), Infallible> {
let reg_block = self.register_block();
if reg_block.cmd.read().usr().bit_is_set() {
return Err(nb::Error::WouldBlock);
}
self.configure_datalen(8);
reg_block.w0.write(|w| unsafe { w.bits(word.into()) });
self.update();
reg_block.cmd.modify(|_, w| w.usr().set_bit());
Ok(())
}
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Infallible> {
let reg_block = self.register_block();
for chunk in words.chunks_mut(64) {
self.configure_datalen(chunk.len() as u32 * 8);
let mut fifo_ptr = reg_block.w0.as_ptr();
for chunk in chunk.chunks(4) {
let mut u32_as_bytes = [0u8; 4];
u32_as_bytes[0..(chunk.len())].clone_from_slice(&chunk);
let reg_val: u32 = u32::from_le_bytes(u32_as_bytes);
unsafe {
*fifo_ptr = reg_val;
fifo_ptr = fifo_ptr.offset(1);
};
}
self.update();
reg_block.cmd.modify(|_, w| w.usr().set_bit());
while reg_block.cmd.read().usr().bit_is_set() {
// wait
}
let mut fifo_ptr = reg_block.w0.as_ptr();
for index in (0..chunk.len()).step_by(4) {
let reg_val = unsafe { *fifo_ptr };
let bytes = reg_val.to_le_bytes();
let len = usize::min(chunk.len(), index + 4) - index;
chunk[index..(index + len)].clone_from_slice(&bytes[0..len]);
unsafe {
fifo_ptr = fifo_ptr.offset(1);
};
}
}
Ok(words)
}
#[cfg(not(any(feature = "esp32", feature = "esp32s2")))]
fn update(&self) {
let reg_block = self.register_block();
reg_block.cmd.modify(|_, w| w.update().set_bit());
while reg_block.cmd.read().update().bit_is_set() {
// wait
}
}
#[cfg(any(feature = "esp32", feature = "esp32s2"))]
fn update(&self) {
// not need/available on ESP32/ESP32S2
}
fn configure_datalen(&self, len: u32) {
let reg_block = self.register_block();
#[cfg(any(feature = "esp32c3", feature = "esp32s3"))]
reg_block
.ms_dlen
.write(|w| unsafe { w.ms_data_bitlen().bits(len - 1) });
#[cfg(not(any(feature = "esp32c3", feature = "esp32s3")))]
{
reg_block
.mosi_dlen
.write(|w| unsafe { w.usr_mosi_dbitlen().bits(len - 1) });
reg_block
.miso_dlen
.write(|w| unsafe { w.usr_miso_dbitlen().bits(len - 1) });
}
}
}
#[cfg(any(feature = "esp32c3"))]
impl Instance for crate::pac::SPI2 {
#[inline(always)]
fn register_block(&self) -> &RegisterBlock {
self
}
#[inline(always)]
fn sclk_signal(&self) -> OutputSignal {
OutputSignal::FSPICLK_MUX
}
#[inline(always)]
fn mosi_signal(&self) -> OutputSignal {
OutputSignal::FSPID
}
#[inline(always)]
fn miso_signal(&self) -> InputSignal {
InputSignal::FSPIQ
}
#[inline(always)]
fn cs_signal(&self) -> OutputSignal {
OutputSignal::FSPICS0
}
#[inline(always)]
fn enable_peripheral(&self, system: &mut System) {
// enable peripheral
system
.perip_clk_en0
.modify(|_, w| w.spi2_clk_en().set_bit());
// Take the peripheral out of any pre-existing reset state
// (shouldn't be the case after a fresh startup, but better be safe)
system.perip_rst_en0.modify(|_, w| w.spi2_rst().clear_bit());
}
}
#[cfg(any(feature = "esp32"))]
impl Instance for crate::pac::SPI2 {
#[inline(always)]
fn register_block(&self) -> &RegisterBlock {
self
}
#[inline(always)]
fn sclk_signal(&self) -> OutputSignal {
OutputSignal::HSPICLK
}
#[inline(always)]
fn mosi_signal(&self) -> OutputSignal {
OutputSignal::HSPID
}
#[inline(always)]
fn miso_signal(&self) -> InputSignal {
InputSignal::HSPIQ
}
#[inline(always)]
fn cs_signal(&self) -> OutputSignal {
OutputSignal::HSPICS0
}
#[inline(always)]
fn enable_peripheral(&self, system: &mut System) {
system.perip_clk_en.modify(|_, w| w.spi2_clk_en().set_bit());
system.perip_rst_en.modify(|_, w| w.spi2_rst().clear_bit());
}
}
#[cfg(any(feature = "esp32"))]
impl Instance for crate::pac::SPI3 {
#[inline(always)]
fn register_block(&self) -> &RegisterBlock {
self
}
#[inline(always)]
fn sclk_signal(&self) -> OutputSignal {
OutputSignal::VSPICLK
}
#[inline(always)]
fn mosi_signal(&self) -> OutputSignal {
OutputSignal::VSPID
}
#[inline(always)]
fn miso_signal(&self) -> InputSignal {
InputSignal::VSPIQ
}
#[inline(always)]
fn cs_signal(&self) -> OutputSignal {
OutputSignal::VSPICS0
}
#[inline(always)]
fn enable_peripheral(&self, system: &mut System) {
system.perip_clk_en.modify(|_, w| w.spi3_clk_en().set_bit());
system.perip_rst_en.modify(|_, w| w.spi3_rst().clear_bit());
}
}
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
impl Instance for crate::pac::SPI2 {
#[inline(always)]
fn register_block(&self) -> &RegisterBlock {
self
}
#[inline(always)]
fn sclk_signal(&self) -> OutputSignal {
OutputSignal::FSPICLK
}
#[inline(always)]
fn mosi_signal(&self) -> OutputSignal {
OutputSignal::FSPID
}
#[inline(always)]
fn miso_signal(&self) -> InputSignal {
InputSignal::FSPIQ
}
#[inline(always)]
fn cs_signal(&self) -> OutputSignal {
OutputSignal::FSPICS0
}
#[inline(always)]
fn enable_peripheral(&self, system: &mut System) {
system
.perip_clk_en0
.modify(|_, w| w.spi2_clk_en().set_bit());
system.perip_rst_en0.modify(|_, w| w.spi2_rst().clear_bit());
}
}
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
impl Instance for crate::pac::SPI3 {
#[inline(always)]
fn register_block(&self) -> &RegisterBlock {
self
}
#[inline(always)]
fn sclk_signal(&self) -> OutputSignal {
OutputSignal::SPI3_CLK
}
#[inline(always)]
fn mosi_signal(&self) -> OutputSignal {
OutputSignal::SPI3_D
}
#[inline(always)]
fn miso_signal(&self) -> InputSignal {
InputSignal::SPI3_Q
}
#[inline(always)]
fn cs_signal(&self) -> OutputSignal {
OutputSignal::SPI3_CS0
}
#[inline(always)]
fn enable_peripheral(&self, system: &mut System) {
system
.perip_clk_en0
.modify(|_, w| w.spi3_clk_en().set_bit());
system.perip_rst_en0.modify(|_, w| w.spi3_rst().clear_bit());
}
}

View File

@ -0,0 +1,64 @@
//! SPI loopback test
//!
//! Folowing pins are used:
//! SCLK GPIO19
//! MISO GPIO25
//! MOSI GPIO23
//! CS GPIO22
//!
//! 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.
#![no_std]
#![no_main]
use core::fmt::Write;
use esp32_hal::{gpio::IO, pac::Peripherals, prelude::*, Delay, RtcCntl, Serial, Timer};
use panic_halt as _;
use xtensa_lx_rt::entry;
#[entry]
fn main() -> ! {
let mut peripherals = Peripherals::take().unwrap();
// Disable the watchdog timers. For the ESP32-C3, this includes the Super WDT,
// the RTC WDT, and the TIMG WDTs.
let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
let mut timer0 = Timer::new(peripherals.TIMG0);
let mut serial0 = Serial::new(peripherals.UART0).unwrap();
timer0.disable();
rtc_cntl.set_wdt_global_enable(false);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let sclk = io.pins.gpio19;
let miso = io.pins.gpio25;
let mosi = io.pins.gpio23;
let cs = io.pins.gpio22;
let mut spi = esp32_hal::spi::Spi::new(
peripherals.SPI2,
sclk,
mosi,
miso,
cs,
100_000,
embedded_hal::spi::MODE_0,
&mut peripherals.DPORT,
);
let delay = Delay::new();
loop {
let mut data = [0xde, 0xca, 0xfb, 0xad];
spi.transfer(&mut data).unwrap();
writeln!(serial0, "{:x?}", data).ok();
delay.delay(250_000);
}
}

View File

@ -1,7 +1,7 @@
#![no_std]
pub use embedded_hal as ehal;
pub use esp_hal_common::{i2c, pac, prelude, Delay, RtcCntl, Serial, Timer};
pub use esp_hal_common::{i2c, pac, prelude, spi, Delay, RtcCntl, Serial, Timer};
pub use self::gpio::IO;

View File

@ -0,0 +1,72 @@
//! SPI loopback test
//!
//! Folowing pins are used:
//! SCLK GPIO6
//! MISO GPIO2
//! MOSI GPIO7
//! CS GPIO10
//!
//! 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.
#![no_std]
#![no_main]
use core::fmt::Write;
use esp32c3_hal::{gpio::IO, pac::Peripherals, prelude::*, Delay, RtcCntl, Serial, Timer};
use panic_halt as _;
use riscv_rt::entry;
#[entry]
fn main() -> ! {
let mut peripherals = Peripherals::take().unwrap();
// Disable the watchdog timers. For the ESP32-C3, this includes the Super WDT,
// the RTC WDT, and the TIMG WDTs.
let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
let mut timer0 = Timer::new(peripherals.TIMG0);
let mut timer1 = Timer::new(peripherals.TIMG1);
let mut serial0 = Serial::new(peripherals.UART0).unwrap();
rtc_cntl.set_super_wdt_enable(false);
rtc_cntl.set_wdt_enable(false);
timer0.disable();
timer1.disable();
peripherals
.SYSTEM
.sysclk_conf
.modify(|_, w| unsafe { w.soc_clk_sel().bits(1) });
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let sclk = io.pins.gpio6;
let miso = io.pins.gpio2;
let mosi = io.pins.gpio7;
let cs = io.pins.gpio10;
let mut spi = esp32c3_hal::spi::Spi::new(
peripherals.SPI2,
sclk,
mosi,
miso,
cs,
100_000,
embedded_hal::spi::MODE_0,
&mut peripherals.SYSTEM,
);
let delay = Delay::new(peripherals.SYSTIMER);
loop {
let mut data = [0xde, 0xca, 0xfb, 0xad];
spi.transfer(&mut data).unwrap();
writeln!(serial0, "{:x?}", data).ok();
delay.delay(250_000);
}
}

View File

@ -1,7 +1,7 @@
#![no_std]
pub use embedded_hal as ehal;
pub use esp_hal_common::{i2c, pac, prelude, Delay, Serial, Timer};
pub use esp_hal_common::{i2c, pac, prelude, spi, Delay, Serial, Timer};
#[cfg(not(feature = "normalboot"))]
use riscv_rt::pre_init;

View File

@ -0,0 +1,64 @@
//! SPI loopback test
//!
//! Folowing pins are used:
//! SCLK GPIO36
//! MISO GPIO35
//! MOSI GPIO37
//! CS GPIO34
//!
//! 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.
#![no_std]
#![no_main]
use core::fmt::Write;
use esp32s2_hal::{gpio::IO, pac::Peripherals, prelude::*, Delay, RtcCntl, Serial, Timer};
use panic_halt as _;
use xtensa_lx_rt::entry;
#[entry]
fn main() -> ! {
let mut peripherals = Peripherals::take().unwrap();
// Disable the watchdog timers. For the ESP32-C3, this includes the Super WDT,
// the RTC WDT, and the TIMG WDTs.
let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
let mut timer0 = Timer::new(peripherals.TIMG0);
let mut serial0 = Serial::new(peripherals.UART0).unwrap();
timer0.disable();
rtc_cntl.set_wdt_global_enable(false);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let sclk = io.pins.gpio36;
let miso = io.pins.gpio37;
let mosi = io.pins.gpio35;
let cs = io.pins.gpio34;
let mut spi = esp32s2_hal::spi::Spi::new(
peripherals.SPI2,
sclk,
mosi,
miso,
cs,
100_000,
embedded_hal::spi::MODE_0,
&mut peripherals.SYSTEM,
);
let delay = Delay::new();
loop {
let mut data = [0xde, 0xca, 0xfb, 0xad];
spi.transfer(&mut data).unwrap();
writeln!(serial0, "{:x?}", data).ok();
delay.delay(250_000);
}
}

View File

@ -6,6 +6,7 @@ pub use esp_hal_common::{
pac,
prelude,
ram,
spi,
Delay,
RtcCntl,
Serial,

View File

@ -0,0 +1,64 @@
//! SPI loopback test
//!
//! Folowing pins are used:
//! SCLK GPIO12
//! MISO GPIO11
//! MOSI GPIO13
//! CS GPIO10
//!
//! 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.
#![no_std]
#![no_main]
use core::fmt::Write;
use esp32s3_hal::{gpio::IO, pac::Peripherals, prelude::*, Delay, RtcCntl, Serial, Timer};
use panic_halt as _;
use xtensa_lx_rt::entry;
#[entry]
fn main() -> ! {
let mut peripherals = Peripherals::take().unwrap();
// Disable the watchdog timers. For the ESP32-C3, this includes the Super WDT,
// the RTC WDT, and the TIMG WDTs.
let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
let mut timer0 = Timer::new(peripherals.TIMG0);
let mut serial0 = Serial::new(peripherals.UART0).unwrap();
timer0.disable();
rtc_cntl.set_wdt_global_enable(false);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let sclk = io.pins.gpio12;
let miso = io.pins.gpio11;
let mosi = io.pins.gpio13;
let cs = io.pins.gpio10;
let mut spi = esp32s3_hal::spi::Spi::new(
peripherals.SPI2,
sclk,
mosi,
miso,
cs,
100_000,
embedded_hal::spi::MODE_0,
&mut peripherals.SYSTEM,
);
let delay = Delay::new();
loop {
let mut data = [0xde, 0xca, 0xfb, 0xad];
spi.transfer(&mut data).unwrap();
writeln!(serial0, "{:x?}", data).ok();
delay.delay(250_000);
}
}

View File

@ -1,7 +1,7 @@
#![no_std]
pub use embedded_hal as ehal;
pub use esp_hal_common::{i2c, pac, prelude, ram, Delay, RtcCntl, Serial, Timer};
pub use esp_hal_common::{i2c, pac, prelude, ram, spi, Delay, RtcCntl, Serial, Timer};
pub use self::gpio::IO;