Skip to content

Commit

Permalink
Spi slave mode
Browse files Browse the repository at this point in the history
spi with interrupts
  • Loading branch information
apeng2012 committed Mar 7, 2022
1 parent c508256 commit c0c2c03
Show file tree
Hide file tree
Showing 3 changed files with 411 additions and 48 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added

- Spi Slave mode
- Reexport gpio pins to `gpio` mod
- Added the ability to specify the word size (8 or 9 bits) for `Serial` (USART). When using parity, the parity bit is included in the number of bits of the word.
- `blocking::serial::Write` for `Tx` and `Serial`. `core::fmt::Write` for `Serial`
Expand Down
154 changes: 154 additions & 0 deletions examples/spi-slave.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
//! SPI slave mode test
//!
//! spi1 master <-> spi2 slave
//! PA5 <-SCK-> PB13
//! PA6 <-MISO-> PB14
//! PA7 <-MOSI-> PB15

#![allow(clippy::empty_loop)]
#![no_std]
#![no_main]

use cortex_m_rt::entry;
use panic_halt as _;

use cortex_m::{asm, singleton};
use embedded_hal::spi::{Mode, Phase, Polarity};
pub const MODE: Mode = Mode {
phase: Phase::CaptureOnSecondTransition,
polarity: Polarity::IdleHigh,
};

use stm32f1xx_hal::{
gpio::{
gpiob::{PB13, PB14, PB15},
Alternate, Floating, Input, PushPull,
},
pac::{self, interrupt, Peripherals, SPI2},
prelude::*,
spi::{Event, Slave, Spi, Spi2NoRemap},
};

type SlaveSpi = Spi<
SPI2,
Spi2NoRemap,
(
PB13<Input<Floating>>,
PB14<Alternate<PushPull>>,
PB15<Input<Floating>>,
),
u8,
Slave,
>;

static mut SPI2SLAVE: Option<SlaveSpi> = None;

#[entry]
fn main() -> ! {
let dp = Peripherals::take().unwrap();

let mut flash = dp.FLASH.constrain();
let rcc = dp.RCC.constrain();

let clocks = rcc.cfgr.freeze(&mut flash.acr);

let mut afio = dp.AFIO.constrain();
let mut gpioa = dp.GPIOA.split();
let mut gpiob = dp.GPIOB.split();

// SPI1
let sck = gpioa.pa5.into_alternate_push_pull(&mut gpioa.crl);
let miso = gpioa.pa6;
let mosi = gpioa.pa7.into_alternate_push_pull(&mut gpioa.crl);

let spi1 = Spi::spi1(
dp.SPI1,
(sck, miso, mosi),
&mut afio.mapr,
MODE,
10.kHz(),
clocks,
);

// SPI2
let sck = gpiob.pb13;
let miso = gpiob.pb14.into_alternate_push_pull(&mut gpiob.crh);
let mosi = gpiob.pb15;

let spi2 = Spi::spi2_slave(dp.SPI2, (sck, miso, mosi), MODE);

// Set up the DMA device
let dma = dp.DMA1.split();

let master_spi_dma = spi1.with_rx_tx_dma(dma.2, dma.3);
let slave_spi_dma = spi2.with_rx_tx_dma(dma.4, dma.5);

let master_buf = singleton!(: [u8; 12] = [0; 12]).unwrap();
let slave_buf = singleton!(: [u8; 12] = [0; 12]).unwrap();

// Make sure the buffers are the same length
let slave_transfer = slave_spi_dma.read_write(slave_buf, b"hello,master");
let master_transfer = master_spi_dma.read_write(master_buf, b"hello, slave");

let (buffer, spi1_dma) = master_transfer.wait();
let (_buffer, spi2_dma) = slave_transfer.wait();

asm::bkpt();

// test SPI with interrupts
let (mut spi2, _, _) = spi2_dma.release();

spi2.listen(Event::Rxne);
spi2.listen(Event::Txe);
spi2.listen(Event::Error);

cortex_m::interrupt::free(|_| unsafe {
SPI2SLAVE.replace(spi2);
});

unsafe {
cortex_m::peripheral::NVIC::unmask(pac::Interrupt::SPI2);
}

let master_transfer = spi1_dma.read_write(buffer.0, buffer.1);
let (_buffer, _spi1_dma) = master_transfer.wait();

loop {}
}

const R_BUFFER_LEN: usize = 16;
static mut R_BUFFER: &mut [u8; R_BUFFER_LEN] = &mut [0; R_BUFFER_LEN];
static mut RIDX: usize = 0;

const W_BUFFER_LEN: usize = 3;
static W_BUFFER: &[u8; W_BUFFER_LEN] = &[1, 2, 3];
static mut WIDX: usize = 0;

#[interrupt]
unsafe fn SPI2() {
cortex_m::interrupt::free(|_| {
if let Some(spi2) = SPI2SLAVE.as_mut() {
if spi2.is_overrun() {
// mcu processing speed is not enough
asm::bkpt();
}
if spi2.is_rx_not_empty() {
if let Ok(w) = nb::block!(spi2.read()) {
R_BUFFER[RIDX] = w;
RIDX += 1;
if RIDX >= R_BUFFER_LEN - 1 {
RIDX = 0;
}
}
}
if spi2.is_tx_empty() {
if let Ok(()) = nb::block!(spi2.send(W_BUFFER[WIDX])) {
WIDX += 1;
if WIDX >= W_BUFFER_LEN {
WIDX = 0;
}
}
}
}
})
}
Loading

0 comments on commit c0c2c03

Please sign in to comment.