mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-10-02 06:40:47 +00:00
Implement SPI
This commit is contained in:
parent
e7eea75ef8
commit
3f7a675b1e
@ -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
605
esp-hal-common/src/spi.rs
Normal 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());
|
||||
}
|
||||
}
|
64
esp32-hal/examples/spi_loopback.rs
Normal file
64
esp32-hal/examples/spi_loopback.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
72
esp32c3-hal/examples/spi_loopback.rs
Normal file
72
esp32c3-hal/examples/spi_loopback.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
64
esp32s2-hal/examples/spi_loopback.rs
Normal file
64
esp32s2-hal/examples/spi_loopback.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ pub use esp_hal_common::{
|
||||
pac,
|
||||
prelude,
|
||||
ram,
|
||||
spi,
|
||||
Delay,
|
||||
RtcCntl,
|
||||
Serial,
|
||||
|
64
esp32s3-hal/examples/spi_loopback.rs
Normal file
64
esp32s3-hal/examples/spi_loopback.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user