Merge branch 'main' of github.com:embassy-rs/embassy
This commit is contained in:
commit
320e2cf35b
@ -20,13 +20,13 @@ fn main() -> ! {
|
|||||||
let led = Output::new(p.PB14, Level::Low, Speed::Low);
|
let led = Output::new(p.PB14, Level::Low, Speed::Low);
|
||||||
let mut button = Input::new(p.PC13, Pull::Up);
|
let mut button = Input::new(p.PC13, Pull::Up);
|
||||||
|
|
||||||
cortex_m::interrupt::free(|cs| unsafe {
|
cortex_m::interrupt::free(|cs| {
|
||||||
enable_interrupt(&mut button);
|
enable_interrupt(&mut button);
|
||||||
|
|
||||||
LED.borrow(cs).borrow_mut().replace(led);
|
LED.borrow(cs).borrow_mut().replace(led);
|
||||||
BUTTON.borrow(cs).borrow_mut().replace(button);
|
BUTTON.borrow(cs).borrow_mut().replace(button);
|
||||||
|
|
||||||
NVIC::unmask(pac::Interrupt::EXTI15_10);
|
unsafe { NVIC::unmask(pac::Interrupt::EXTI15_10) };
|
||||||
});
|
});
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -64,25 +64,21 @@ const PORT: u8 = 2;
|
|||||||
const PIN: usize = 13;
|
const PIN: usize = 13;
|
||||||
fn check_interrupt<P: Pin>(_pin: &mut Input<'static, P>) -> bool {
|
fn check_interrupt<P: Pin>(_pin: &mut Input<'static, P>) -> bool {
|
||||||
let exti = pac::EXTI;
|
let exti = pac::EXTI;
|
||||||
unsafe {
|
|
||||||
let pin = PIN;
|
let pin = PIN;
|
||||||
let lines = exti.pr(0).read();
|
let lines = exti.pr(0).read();
|
||||||
lines.line(pin)
|
lines.line(pin)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_interrupt<P: Pin>(_pin: &mut Input<'static, P>) {
|
fn clear_interrupt<P: Pin>(_pin: &mut Input<'static, P>) {
|
||||||
let exti = pac::EXTI;
|
let exti = pac::EXTI;
|
||||||
unsafe {
|
|
||||||
let pin = PIN;
|
let pin = PIN;
|
||||||
let mut lines = exti.pr(0).read();
|
let mut lines = exti.pr(0).read();
|
||||||
lines.set_line(pin, true);
|
lines.set_line(pin, true);
|
||||||
exti.pr(0).write_value(lines);
|
exti.pr(0).write_value(lines);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn enable_interrupt<P: Pin>(_pin: &mut Input<'static, P>) {
|
fn enable_interrupt<P: Pin>(_pin: &mut Input<'static, P>) {
|
||||||
cortex_m::interrupt::free(|_| unsafe {
|
cortex_m::interrupt::free(|_| {
|
||||||
let rcc = pac::RCC;
|
let rcc = pac::RCC;
|
||||||
rcc.apb2enr().modify(|w| w.set_syscfgen(true));
|
rcc.apb2enr().modify(|w| w.set_syscfgen(true));
|
||||||
|
|
||||||
|
@ -31,3 +31,15 @@ pub fn block_on<F: Future>(mut fut: F) -> F::Output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Poll a future once.
|
||||||
|
pub fn poll_once<F: Future>(mut fut: F) -> Poll<F::Output> {
|
||||||
|
// safety: we don't move the future after this line.
|
||||||
|
let mut fut = unsafe { Pin::new_unchecked(&mut fut) };
|
||||||
|
|
||||||
|
let raw_waker = RawWaker::new(ptr::null(), &VTABLE);
|
||||||
|
let waker = unsafe { Waker::from_raw(raw_waker) };
|
||||||
|
let mut cx = Context::from_waker(&waker);
|
||||||
|
|
||||||
|
fut.as_mut().poll(&mut cx)
|
||||||
|
}
|
||||||
|
@ -68,29 +68,23 @@ where
|
|||||||
}
|
}
|
||||||
async fn set_nss_low(&mut self) -> Result<(), RadioError> {
|
async fn set_nss_low(&mut self) -> Result<(), RadioError> {
|
||||||
let pwr = pac::PWR;
|
let pwr = pac::PWR;
|
||||||
unsafe {
|
|
||||||
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW));
|
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW));
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn set_nss_high(&mut self) -> Result<(), RadioError> {
|
async fn set_nss_high(&mut self) -> Result<(), RadioError> {
|
||||||
let pwr = pac::PWR;
|
let pwr = pac::PWR;
|
||||||
unsafe {
|
|
||||||
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH));
|
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH));
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> {
|
async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> {
|
||||||
let rcc = pac::RCC;
|
let rcc = pac::RCC;
|
||||||
unsafe {
|
|
||||||
rcc.csr().modify(|w| w.set_rfrst(true));
|
rcc.csr().modify(|w| w.set_rfrst(true));
|
||||||
rcc.csr().modify(|w| w.set_rfrst(false));
|
rcc.csr().modify(|w| w.set_rfrst(false));
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn wait_on_busy(&mut self) -> Result<(), RadioError> {
|
async fn wait_on_busy(&mut self) -> Result<(), RadioError> {
|
||||||
let pwr = pac::PWR;
|
let pwr = pac::PWR;
|
||||||
while unsafe { pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY } {}
|
while pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY {}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use embassy_stm32::ipcc::Ipcc;
|
use embassy_stm32::ipcc::Ipcc;
|
||||||
|
|
||||||
use crate::cmd::{CmdPacket, CmdSerial};
|
use crate::cmd::CmdPacket;
|
||||||
use crate::consts::TlPacketType;
|
use crate::consts::TlPacketType;
|
||||||
use crate::evt::EvtBox;
|
use crate::evt::EvtBox;
|
||||||
use crate::tables::BleTable;
|
use crate::tables::BleTable;
|
||||||
use crate::unsafe_linked_list::LinkedListNode;
|
use crate::unsafe_linked_list::LinkedListNode;
|
||||||
use crate::{
|
use crate::{channels, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE};
|
||||||
channels, BLE_CMD_BUFFER, CS_BUFFER, EVT_CHANNEL, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE, TL_REF_TABLE,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Ble;
|
pub struct Ble {
|
||||||
|
phantom: PhantomData<Ble>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Ble {
|
impl Ble {
|
||||||
pub(super) fn enable() {
|
pub(crate) fn new() -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr());
|
LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr());
|
||||||
|
|
||||||
@ -24,54 +26,38 @@ impl Ble {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, true);
|
Self { phantom: PhantomData }
|
||||||
|
}
|
||||||
|
/// `HW_IPCC_BLE_EvtNot`
|
||||||
|
pub async fn read(&self) -> EvtBox {
|
||||||
|
Ipcc::receive(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, || unsafe {
|
||||||
|
if let Some(node_ptr) = LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr()) {
|
||||||
|
Some(EvtBox::new(node_ptr.cast()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn evt_handler() {
|
/// `TL_BLE_SendCmd`
|
||||||
unsafe {
|
pub async fn write(&self, opcode: u16, payload: &[u8]) {
|
||||||
while !LinkedListNode::is_empty(EVT_QUEUE.as_mut_ptr()) {
|
Ipcc::send(channels::cpu1::IPCC_BLE_CMD_CHANNEL, || unsafe {
|
||||||
let node_ptr = LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr());
|
CmdPacket::write_into(BLE_CMD_BUFFER.as_mut_ptr(), TlPacketType::BleCmd, opcode, payload);
|
||||||
|
})
|
||||||
let event = node_ptr.cast();
|
.await;
|
||||||
let event = EvtBox::new(event);
|
|
||||||
|
|
||||||
EVT_CHANNEL.try_send(event).unwrap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL);
|
/// `TL_BLE_SendAclData`
|
||||||
}
|
pub async fn acl_write(&self, handle: u16, payload: &[u8]) {
|
||||||
|
Ipcc::send(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL, || unsafe {
|
||||||
pub(super) fn acl_data_handler() {
|
CmdPacket::write_into(
|
||||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL, false);
|
HCI_ACL_DATA_BUFFER.as_mut_ptr() as *mut _,
|
||||||
|
TlPacketType::AclData,
|
||||||
// TODO: ACL data ack to the user
|
handle,
|
||||||
}
|
payload,
|
||||||
|
);
|
||||||
pub fn ble_send_cmd(buf: &[u8]) {
|
})
|
||||||
debug!("writing ble cmd");
|
.await;
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let pcmd_buffer: *mut CmdPacket = (*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer;
|
|
||||||
let pcmd_serial: *mut CmdSerial = &mut (*pcmd_buffer).cmdserial;
|
|
||||||
let pcmd_serial_buf: *mut u8 = pcmd_serial.cast();
|
|
||||||
|
|
||||||
core::ptr::copy(buf.as_ptr(), pcmd_serial_buf, buf.len());
|
|
||||||
|
|
||||||
let cmd_packet = &mut *(*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer;
|
|
||||||
cmd_packet.cmdserial.ty = TlPacketType::BleCmd as u8;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_BLE_CMD_CHANNEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
|
||||||
pub(super) fn ble_send_acl_data() {
|
|
||||||
let cmd_packet = unsafe { &mut *(*TL_REF_TABLE.assume_init().ble_table).phci_acl_data_buffer };
|
|
||||||
|
|
||||||
cmd_packet.acl_data_serial.ty = TlPacketType::AclData as u8;
|
|
||||||
|
|
||||||
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL);
|
|
||||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use crate::evt::{EvtPacket, EvtSerial};
|
use core::ptr;
|
||||||
use crate::{PacketHeader, TL_EVT_HEADER_SIZE};
|
|
||||||
|
use crate::consts::TlPacketType;
|
||||||
|
use crate::PacketHeader;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
@ -26,6 +28,14 @@ pub struct CmdSerial {
|
|||||||
pub cmd: Cmd,
|
pub cmd: Cmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct CmdSerialStub {
|
||||||
|
pub ty: u8,
|
||||||
|
pub cmd_code: u16,
|
||||||
|
pub payload_len: u8,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default)]
|
#[derive(Copy, Clone, Default)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct CmdPacket {
|
pub struct CmdPacket {
|
||||||
@ -34,29 +44,20 @@ pub struct CmdPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CmdPacket {
|
impl CmdPacket {
|
||||||
/// Writes an underlying CmdPacket into the provided buffer.
|
pub unsafe fn write_into(cmd_buf: *mut CmdPacket, packet_type: TlPacketType, cmd_code: u16, payload: &[u8]) {
|
||||||
/// Returns a number of bytes that were written.
|
let p_cmd_serial = &mut (*cmd_buf).cmdserial as *mut _ as *mut CmdSerialStub;
|
||||||
/// Returns an error if event kind is unknown or if provided buffer size is not enough.
|
let p_payload = &mut (*cmd_buf).cmdserial.cmd.payload as *mut _;
|
||||||
#[allow(clippy::result_unit_err)]
|
|
||||||
pub fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
|
|
||||||
unsafe {
|
|
||||||
let cmd_ptr: *const CmdPacket = self;
|
|
||||||
let self_as_evt_ptr: *const EvtPacket = cmd_ptr.cast();
|
|
||||||
let evt_serial: *const EvtSerial = &(*self_as_evt_ptr).evt_serial;
|
|
||||||
|
|
||||||
let acl_data: *const AclDataPacket = cmd_ptr.cast();
|
ptr::write_volatile(
|
||||||
let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
|
p_cmd_serial,
|
||||||
let acl_serial_buf: *const u8 = acl_serial.cast();
|
CmdSerialStub {
|
||||||
|
ty: packet_type as u8,
|
||||||
|
cmd_code: cmd_code,
|
||||||
|
payload_len: payload.len() as u8,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE;
|
ptr::copy_nonoverlapping(payload as *const _ as *const u8, p_payload, payload.len());
|
||||||
if len > buf.len() {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len);
|
|
||||||
|
|
||||||
Ok(len)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,9 +70,35 @@ pub struct AclDataSerial {
|
|||||||
pub acl_data: [u8; 1],
|
pub acl_data: [u8; 1],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct AclDataSerialStub {
|
||||||
|
pub ty: u8,
|
||||||
|
pub handle: u16,
|
||||||
|
pub length: u16,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct AclDataPacket {
|
pub struct AclDataPacket {
|
||||||
pub header: PacketHeader,
|
pub header: PacketHeader,
|
||||||
pub acl_data_serial: AclDataSerial,
|
pub acl_data_serial: AclDataSerial,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AclDataPacket {
|
||||||
|
pub unsafe fn write_into(cmd_buf: *mut AclDataPacket, packet_type: TlPacketType, handle: u16, payload: &[u8]) {
|
||||||
|
let p_cmd_serial = &mut (*cmd_buf).acl_data_serial as *mut _ as *mut AclDataSerialStub;
|
||||||
|
let p_payload = &mut (*cmd_buf).acl_data_serial.acl_data as *mut _;
|
||||||
|
|
||||||
|
ptr::write_volatile(
|
||||||
|
p_cmd_serial,
|
||||||
|
AclDataSerialStub {
|
||||||
|
ty: packet_type as u8,
|
||||||
|
handle: handle,
|
||||||
|
length: payload.len() as u16,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
ptr::copy_nonoverlapping(payload as *const _ as *const u8, p_payload, payload.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use core::mem::MaybeUninit;
|
use core::{ptr, slice};
|
||||||
|
|
||||||
use super::cmd::{AclDataPacket, AclDataSerial};
|
use super::PacketHeader;
|
||||||
use super::consts::TlPacketType;
|
|
||||||
use super::{PacketHeader, TL_EVT_HEADER_SIZE};
|
|
||||||
use crate::mm;
|
use crate::mm;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,6 +61,12 @@ pub struct EvtSerial {
|
|||||||
pub evt: Evt,
|
pub evt: Evt,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
pub struct EvtStub {
|
||||||
|
pub kind: u8,
|
||||||
|
pub evt_code: u8,
|
||||||
|
}
|
||||||
|
|
||||||
/// This format shall be used for all events (asynchronous and command response) reported
|
/// This format shall be used for all events (asynchronous and command response) reported
|
||||||
/// by the CPU2 except for the command response of a system command where the header is not there
|
/// by the CPU2 except for the command response of a system command where the header is not there
|
||||||
/// and the format to be used shall be `EvtSerial`.
|
/// and the format to be used shall be `EvtSerial`.
|
||||||
@ -101,76 +105,91 @@ impl EvtBox {
|
|||||||
Self { ptr }
|
Self { ptr }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// copies event data from inner pointer and returns an event structure
|
/// Returns information about the event
|
||||||
pub fn evt(&self) -> EvtPacket {
|
pub fn stub(&self) -> EvtStub {
|
||||||
let mut evt = MaybeUninit::uninit();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.ptr.copy_to(evt.as_mut_ptr(), 1);
|
let p_evt_stub = &(*self.ptr).evt_serial as *const _ as *const EvtStub;
|
||||||
evt.assume_init()
|
|
||||||
|
ptr::read_volatile(p_evt_stub)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// writes an underlying [`EvtPacket`] into the provided buffer.
|
pub fn payload<'a>(&self) -> &'a [u8] {
|
||||||
/// Returns the number of bytes that were written.
|
|
||||||
/// Returns an error if event kind is unknown or if provided buffer size is not enough.
|
|
||||||
#[allow(clippy::result_unit_err)]
|
|
||||||
pub fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
|
let p_payload_len = &(*self.ptr).evt_serial.evt.payload_len as *const u8;
|
||||||
|
let p_payload = &(*self.ptr).evt_serial.evt.payload as *const u8;
|
||||||
|
|
||||||
let evt_data: *const EvtPacket = self.ptr.cast();
|
let payload_len = ptr::read_volatile(p_payload_len);
|
||||||
let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
|
|
||||||
let evt_serial_buf: *const u8 = evt_serial.cast();
|
|
||||||
|
|
||||||
let acl_data: *const AclDataPacket = self.ptr.cast();
|
slice::from_raw_parts(p_payload, payload_len as usize)
|
||||||
let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
|
|
||||||
let acl_serial_buf: *const u8 = acl_serial.cast();
|
|
||||||
|
|
||||||
if let TlPacketType::AclData = evt_kind {
|
|
||||||
let len = (*acl_serial).length as usize + 5;
|
|
||||||
if len > buf.len() {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
core::ptr::copy(evt_serial_buf, buf.as_mut_ptr(), len);
|
|
||||||
|
|
||||||
Ok(len)
|
|
||||||
} else {
|
|
||||||
let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE;
|
|
||||||
if len > buf.len() {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len);
|
|
||||||
|
|
||||||
Ok(len)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns the size of a buffer required to hold this event
|
// TODO: bring back acl
|
||||||
#[allow(clippy::result_unit_err)]
|
|
||||||
pub fn size(&self) -> Result<usize, ()> {
|
|
||||||
unsafe {
|
|
||||||
let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
|
|
||||||
|
|
||||||
let evt_data: *const EvtPacket = self.ptr.cast();
|
// /// writes an underlying [`EvtPacket`] into the provided buffer.
|
||||||
let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
|
// /// Returns the number of bytes that were written.
|
||||||
|
// /// Returns an error if event kind is unknown or if provided buffer size is not enough.
|
||||||
let acl_data: *const AclDataPacket = self.ptr.cast();
|
// #[allow(clippy::result_unit_err)]
|
||||||
let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
|
// pub fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
|
||||||
|
// unsafe {
|
||||||
if let TlPacketType::AclData = evt_kind {
|
// let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
|
||||||
Ok((*acl_serial).length as usize + 5)
|
//
|
||||||
} else {
|
// let evt_data: *const EvtPacket = self.ptr.cast();
|
||||||
Ok((*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE)
|
// let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
|
||||||
}
|
// let evt_serial_buf: *const u8 = evt_serial.cast();
|
||||||
}
|
//
|
||||||
}
|
// let acl_data: *const AclDataPacket = self.ptr.cast();
|
||||||
|
// let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
|
||||||
|
// let acl_serial_buf: *const u8 = acl_serial.cast();
|
||||||
|
//
|
||||||
|
// if let TlPacketType::AclData = evt_kind {
|
||||||
|
// let len = (*acl_serial).length as usize + 5;
|
||||||
|
// if len > buf.len() {
|
||||||
|
// return Err(());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// core::ptr::copy(evt_serial_buf, buf.as_mut_ptr(), len);
|
||||||
|
//
|
||||||
|
// Ok(len)
|
||||||
|
// } else {
|
||||||
|
// let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE;
|
||||||
|
// if len > buf.len() {
|
||||||
|
// return Err(());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len);
|
||||||
|
//
|
||||||
|
// Ok(len)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /// returns the size of a buffer required to hold this event
|
||||||
|
// #[allow(clippy::result_unit_err)]
|
||||||
|
// pub fn size(&self) -> Result<usize, ()> {
|
||||||
|
// unsafe {
|
||||||
|
// let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
|
||||||
|
//
|
||||||
|
// let evt_data: *const EvtPacket = self.ptr.cast();
|
||||||
|
// let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
|
||||||
|
//
|
||||||
|
// let acl_data: *const AclDataPacket = self.ptr.cast();
|
||||||
|
// let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
|
||||||
|
//
|
||||||
|
// if let TlPacketType::AclData = evt_kind {
|
||||||
|
// Ok((*acl_serial).length as usize + 5)
|
||||||
|
// } else {
|
||||||
|
// Ok((*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for EvtBox {
|
impl Drop for EvtBox {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
mm::MemoryManager::evt_drop(self.ptr);
|
trace!("evt box drop packet");
|
||||||
|
|
||||||
|
unsafe { mm::MemoryManager::drop_event_packet(self.ptr) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,20 +6,21 @@ pub mod fmt;
|
|||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
|
|
||||||
|
use ble::Ble;
|
||||||
use cmd::CmdPacket;
|
use cmd::CmdPacket;
|
||||||
use embassy_futures::block_on;
|
|
||||||
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
||||||
use embassy_stm32::interrupt;
|
use embassy_stm32::interrupt;
|
||||||
use embassy_stm32::interrupt::typelevel::Interrupt;
|
use embassy_stm32::interrupt::typelevel::Interrupt;
|
||||||
use embassy_stm32::ipcc::{Config, Ipcc};
|
use embassy_stm32::ipcc::{Config, Ipcc, ReceiveInterruptHandler, TransmitInterruptHandler};
|
||||||
use embassy_stm32::peripherals::IPCC;
|
use embassy_stm32::peripherals::IPCC;
|
||||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
use embassy_sync::channel::Channel;
|
use embassy_sync::channel::Channel;
|
||||||
use embassy_sync::signal::Signal;
|
use embassy_sync::signal::Signal;
|
||||||
use evt::{CcEvt, EvtBox};
|
use evt::{CcEvt, EvtBox};
|
||||||
|
use mm::MemoryManager;
|
||||||
|
use sys::Sys;
|
||||||
use tables::{
|
use tables::{
|
||||||
BleTable, DeviceInfoTable, Mac802_15_4Table, MemManagerTable, RefTable, SysTable, ThreadTable, TracesTable,
|
BleTable, DeviceInfoTable, Mac802_15_4Table, MemManagerTable, RefTable, SysTable, ThreadTable, TracesTable,
|
||||||
WirelessFwInfoTable,
|
|
||||||
};
|
};
|
||||||
use unsafe_linked_list::LinkedListNode;
|
use unsafe_linked_list::LinkedListNode;
|
||||||
|
|
||||||
@ -29,50 +30,11 @@ pub mod cmd;
|
|||||||
pub mod consts;
|
pub mod consts;
|
||||||
pub mod evt;
|
pub mod evt;
|
||||||
pub mod mm;
|
pub mod mm;
|
||||||
pub mod rc;
|
|
||||||
pub mod shci;
|
pub mod shci;
|
||||||
pub mod sys;
|
pub mod sys;
|
||||||
pub mod tables;
|
pub mod tables;
|
||||||
pub mod unsafe_linked_list;
|
pub mod unsafe_linked_list;
|
||||||
|
|
||||||
/// Interrupt handler.
|
|
||||||
pub struct ReceiveInterruptHandler {}
|
|
||||||
|
|
||||||
impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for ReceiveInterruptHandler {
|
|
||||||
unsafe fn on_interrupt() {
|
|
||||||
if Ipcc::is_rx_pending(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL) {
|
|
||||||
debug!("RX SYS evt");
|
|
||||||
sys::Sys::evt_handler();
|
|
||||||
} else if Ipcc::is_rx_pending(channels::cpu2::IPCC_BLE_EVENT_CHANNEL) {
|
|
||||||
debug!("RX BLE evt");
|
|
||||||
ble::Ble::evt_handler();
|
|
||||||
}
|
|
||||||
|
|
||||||
STATE.signal(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TransmitInterruptHandler {}
|
|
||||||
|
|
||||||
impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler {
|
|
||||||
unsafe fn on_interrupt() {
|
|
||||||
if Ipcc::is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) {
|
|
||||||
debug!("TX SYS cmd rsp");
|
|
||||||
let cc = sys::Sys::cmd_evt_handler();
|
|
||||||
|
|
||||||
LAST_CC_EVT.signal(cc);
|
|
||||||
} else if Ipcc::is_tx_pending(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL) {
|
|
||||||
debug!("TX MM release");
|
|
||||||
mm::MemoryManager::free_buf_handler();
|
|
||||||
} else if Ipcc::is_tx_pending(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL) {
|
|
||||||
debug!("TX HCI acl");
|
|
||||||
ble::Ble::acl_data_handler();
|
|
||||||
}
|
|
||||||
|
|
||||||
STATE.signal(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[link_section = "TL_REF_TABLE"]
|
#[link_section = "TL_REF_TABLE"]
|
||||||
pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit();
|
pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit();
|
||||||
|
|
||||||
@ -167,10 +129,14 @@ static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
|
|||||||
// fuck these "magic" numbers from ST ---v---v
|
// fuck these "magic" numbers from ST ---v---v
|
||||||
static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit();
|
static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
// TODO: remove these items
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
/// current event that is produced during IPCC IRQ handler execution
|
/// current event that is produced during IPCC IRQ handler execution
|
||||||
/// on SYS channel
|
/// on SYS channel
|
||||||
static EVT_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 32> = Channel::new();
|
static EVT_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 32> = Channel::new();
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
/// last received Command Complete event
|
/// last received Command Complete event
|
||||||
static LAST_CC_EVT: Signal<CriticalSectionRawMutex, CcEvt> = Signal::new();
|
static LAST_CC_EVT: Signal<CriticalSectionRawMutex, CcEvt> = Signal::new();
|
||||||
|
|
||||||
@ -178,6 +144,10 @@ static STATE: Signal<CriticalSectionRawMutex, ()> = Signal::new();
|
|||||||
|
|
||||||
pub struct TlMbox<'d> {
|
pub struct TlMbox<'d> {
|
||||||
_ipcc: PeripheralRef<'d, IPCC>,
|
_ipcc: PeripheralRef<'d, IPCC>,
|
||||||
|
|
||||||
|
pub sys_subsystem: Sys,
|
||||||
|
pub mm_subsystem: MemoryManager,
|
||||||
|
pub ble_subsystem: Ble,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> TlMbox<'d> {
|
impl<'d> TlMbox<'d> {
|
||||||
@ -262,9 +232,9 @@ impl<'d> TlMbox<'d> {
|
|||||||
|
|
||||||
Ipcc::enable(config);
|
Ipcc::enable(config);
|
||||||
|
|
||||||
sys::Sys::enable();
|
let sys = sys::Sys::new();
|
||||||
ble::Ble::enable();
|
let ble = ble::Ble::new();
|
||||||
mm::MemoryManager::enable();
|
let mm = mm::MemoryManager::new();
|
||||||
|
|
||||||
// enable interrupts
|
// enable interrupts
|
||||||
interrupt::typelevel::IPCC_C1_RX::unpend();
|
interrupt::typelevel::IPCC_C1_RX::unpend();
|
||||||
@ -275,36 +245,11 @@ impl<'d> TlMbox<'d> {
|
|||||||
|
|
||||||
STATE.reset();
|
STATE.reset();
|
||||||
|
|
||||||
Self { _ipcc: ipcc }
|
Self {
|
||||||
}
|
_ipcc: ipcc,
|
||||||
|
sys_subsystem: sys,
|
||||||
/// Returns CPU2 wireless firmware information (if present).
|
ble_subsystem: ble,
|
||||||
pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> {
|
mm_subsystem: mm,
|
||||||
let info = unsafe { &(*(*TL_REF_TABLE.as_ptr()).device_info_table).wireless_fw_info_table };
|
|
||||||
|
|
||||||
// Zero version indicates that CPU2 wasn't active and didn't fill the information table
|
|
||||||
if info.version != 0 {
|
|
||||||
Some(*info)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// picks single [`EvtBox`] from internal event queue.
|
|
||||||
///
|
|
||||||
/// Internal event queu is populated in IPCC_RX_IRQ handler
|
|
||||||
pub fn dequeue_event(&mut self) -> Option<EvtBox> {
|
|
||||||
EVT_CHANNEL.try_recv().ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// retrieves last Command Complete event and removes it from mailbox
|
|
||||||
pub fn pop_last_cc_evt(&mut self) -> Option<CcEvt> {
|
|
||||||
if LAST_CC_EVT.signaled() {
|
|
||||||
let cc = block_on(LAST_CC_EVT.wait());
|
|
||||||
LAST_CC_EVT.reset();
|
|
||||||
Some(cc)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,29 @@
|
|||||||
//! Memory manager routines
|
//! Memory manager routines
|
||||||
|
|
||||||
|
use core::future::poll_fn;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use core::task::Poll;
|
||||||
|
|
||||||
|
use cortex_m::interrupt;
|
||||||
use embassy_stm32::ipcc::Ipcc;
|
use embassy_stm32::ipcc::Ipcc;
|
||||||
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
use crate::evt::EvtPacket;
|
use crate::evt::EvtPacket;
|
||||||
use crate::tables::MemManagerTable;
|
use crate::tables::MemManagerTable;
|
||||||
use crate::unsafe_linked_list::LinkedListNode;
|
use crate::unsafe_linked_list::LinkedListNode;
|
||||||
use crate::{
|
use crate::{
|
||||||
channels, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE, SYS_SPARE_EVT_BUF,
|
channels, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE, SYS_SPARE_EVT_BUF,
|
||||||
TL_MEM_MANAGER_TABLE, TL_REF_TABLE,
|
TL_MEM_MANAGER_TABLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(super) struct MemoryManager;
|
static MM_WAKER: AtomicWaker = AtomicWaker::new();
|
||||||
|
|
||||||
|
pub struct MemoryManager {
|
||||||
|
phantom: PhantomData<MemoryManager>,
|
||||||
|
}
|
||||||
|
|
||||||
impl MemoryManager {
|
impl MemoryManager {
|
||||||
pub fn enable() {
|
pub(crate) fn new() -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
LinkedListNode::init_head(FREE_BUF_QUEUE.as_mut_ptr());
|
LinkedListNode::init_head(FREE_BUF_QUEUE.as_mut_ptr());
|
||||||
LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
|
LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
|
||||||
@ -28,44 +38,40 @@ impl MemoryManager {
|
|||||||
tracespoolsize: 0,
|
tracespoolsize: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Self { phantom: PhantomData }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn evt_drop(evt: *mut EvtPacket) {
|
/// SAFETY: passing a pointer to something other than an event packet is UB
|
||||||
unsafe {
|
pub(crate) unsafe fn drop_event_packet(evt: *mut EvtPacket) {
|
||||||
let list_node = evt.cast();
|
interrupt::free(|_| unsafe {
|
||||||
|
LinkedListNode::insert_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _);
|
||||||
|
});
|
||||||
|
|
||||||
LinkedListNode::insert_tail(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), list_node);
|
MM_WAKER.wake();
|
||||||
|
}
|
||||||
|
|
||||||
let channel_is_busy = Ipcc::c1_is_active_flag(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
|
pub async fn run_queue(&self) {
|
||||||
|
loop {
|
||||||
// postpone event buffer freeing to IPCC interrupt handler
|
poll_fn(|cx| unsafe {
|
||||||
if channel_is_busy {
|
MM_WAKER.register(cx.waker());
|
||||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, true);
|
if LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
|
||||||
|
Poll::Pending
|
||||||
} else {
|
} else {
|
||||||
Self::send_free_buf();
|
Poll::Ready(())
|
||||||
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
/// gives free event buffers back to CPU2 from local buffer queue
|
Ipcc::send(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, || {
|
||||||
pub fn send_free_buf() {
|
interrupt::free(|_| unsafe {
|
||||||
unsafe {
|
// CS required while moving nodes
|
||||||
while !LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
|
while let Some(node_ptr) = LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
|
||||||
let node_ptr = LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
|
LinkedListNode::insert_head(FREE_BUF_QUEUE.as_mut_ptr(), node_ptr);
|
||||||
|
}
|
||||||
LinkedListNode::insert_tail(
|
})
|
||||||
(*(*TL_REF_TABLE.as_ptr()).mem_manager_table).pevt_free_buffer_queue,
|
})
|
||||||
node_ptr,
|
.await;
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// free buffer channel interrupt handler
|
|
||||||
pub fn free_buf_handler() {
|
|
||||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, false);
|
|
||||||
Self::send_free_buf();
|
|
||||||
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
use crate::ble::Ble;
|
|
||||||
use crate::consts::TlPacketType;
|
|
||||||
use crate::{shci, TlMbox, STATE};
|
|
||||||
|
|
||||||
pub struct RadioCoprocessor<'d> {
|
|
||||||
mbox: TlMbox<'d>,
|
|
||||||
rx_buf: [u8; 500],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d> RadioCoprocessor<'d> {
|
|
||||||
pub fn new(mbox: TlMbox<'d>) -> Self {
|
|
||||||
Self {
|
|
||||||
mbox,
|
|
||||||
rx_buf: [0u8; 500],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(&self, buf: &[u8]) {
|
|
||||||
let cmd_code = buf[0];
|
|
||||||
let cmd = TlPacketType::try_from(cmd_code).unwrap();
|
|
||||||
|
|
||||||
match &cmd {
|
|
||||||
TlPacketType::BleCmd => Ble::ble_send_cmd(buf),
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn read(&mut self) -> &[u8] {
|
|
||||||
loop {
|
|
||||||
STATE.wait().await;
|
|
||||||
|
|
||||||
while let Some(evt) = self.mbox.dequeue_event() {
|
|
||||||
let event = evt.evt();
|
|
||||||
|
|
||||||
evt.write(&mut self.rx_buf).unwrap();
|
|
||||||
|
|
||||||
if event.kind() == 18 {
|
|
||||||
shci::shci_ble_init(Default::default());
|
|
||||||
self.rx_buf[0] = 0x04;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.mbox.pop_last_cc_evt().is_some() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return &self.rx_buf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +1,8 @@
|
|||||||
use super::cmd::CmdPacket;
|
use core::{mem, slice};
|
||||||
use super::consts::TlPacketType;
|
|
||||||
use super::{sys, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE, TL_SYS_TABLE};
|
|
||||||
|
|
||||||
const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66;
|
use super::{TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE};
|
||||||
|
|
||||||
|
pub const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
@ -32,6 +32,12 @@ pub struct ShciBleInitCmdParam {
|
|||||||
pub hw_version: u8,
|
pub hw_version: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ShciBleInitCmdParam {
|
||||||
|
pub fn payload<'a>(&self) -> &'a [u8] {
|
||||||
|
unsafe { slice::from_raw_parts(self as *const _ as *const u8, mem::size_of::<Self>()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for ShciBleInitCmdParam {
|
impl Default for ShciBleInitCmdParam {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -66,35 +72,10 @@ pub struct ShciHeader {
|
|||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct ShciBleInitCmdPacket {
|
pub struct ShciBleInitCmdPacket {
|
||||||
header: ShciHeader,
|
pub header: ShciHeader,
|
||||||
param: ShciBleInitCmdParam,
|
pub param: ShciBleInitCmdParam,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
|
pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE;
|
const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE;
|
||||||
|
|
||||||
pub fn shci_ble_init(param: ShciBleInitCmdParam) {
|
|
||||||
debug!("sending SHCI");
|
|
||||||
|
|
||||||
let mut packet = ShciBleInitCmdPacket {
|
|
||||||
header: ShciHeader::default(),
|
|
||||||
param,
|
|
||||||
};
|
|
||||||
|
|
||||||
let packet_ptr: *mut _ = &mut packet;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let cmd_ptr: *mut CmdPacket = packet_ptr.cast();
|
|
||||||
|
|
||||||
(*cmd_ptr).cmdserial.cmd.cmd_code = SCHI_OPCODE_BLE_INIT;
|
|
||||||
(*cmd_ptr).cmdserial.cmd.payload_len = core::mem::size_of::<ShciBleInitCmdParam>() as u8;
|
|
||||||
|
|
||||||
let p_cmd_buffer = &mut *(*TL_SYS_TABLE.as_mut_ptr()).pcmd_buffer;
|
|
||||||
core::ptr::write(p_cmd_buffer, *cmd_ptr);
|
|
||||||
|
|
||||||
p_cmd_buffer.cmdserial.ty = TlPacketType::SysCmd as u8;
|
|
||||||
|
|
||||||
sys::Sys::send_cmd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,65 +1,70 @@
|
|||||||
use embassy_stm32::ipcc::Ipcc;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::cmd::{CmdPacket, CmdSerial};
|
use crate::cmd::CmdPacket;
|
||||||
use crate::evt::{CcEvt, EvtBox, EvtSerial};
|
use crate::consts::TlPacketType;
|
||||||
use crate::tables::SysTable;
|
use crate::evt::EvtBox;
|
||||||
|
use crate::shci::{ShciBleInitCmdParam, SCHI_OPCODE_BLE_INIT};
|
||||||
|
use crate::tables::{SysTable, WirelessFwInfoTable};
|
||||||
use crate::unsafe_linked_list::LinkedListNode;
|
use crate::unsafe_linked_list::LinkedListNode;
|
||||||
use crate::{channels, EVT_CHANNEL, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_SYS_TABLE};
|
use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE};
|
||||||
|
|
||||||
pub struct Sys;
|
pub struct Sys {
|
||||||
|
phantom: PhantomData<Sys>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Sys {
|
impl Sys {
|
||||||
pub fn enable() {
|
/// TL_Sys_Init
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
|
LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
|
||||||
|
|
||||||
TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable {
|
TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable {
|
||||||
pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(),
|
pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(),
|
||||||
sys_queue: SYSTEM_EVT_QUEUE.as_ptr(),
|
sys_queue: SYSTEM_EVT_QUEUE.as_ptr(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { phantom: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns CPU2 wireless firmware information (if present).
|
||||||
|
pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> {
|
||||||
|
let info = unsafe { TL_DEVICE_INFO_TABLE.as_mut_ptr().read_volatile().wireless_fw_info_table };
|
||||||
|
|
||||||
|
// Zero version indicates that CPU2 wasn't active and didn't fill the information table
|
||||||
|
if info.version != 0 {
|
||||||
|
Some(info)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&self, opcode: u16, payload: &[u8]) {
|
||||||
|
unsafe {
|
||||||
|
CmdPacket::write_into(SYS_CMD_BUF.as_mut_ptr(), TlPacketType::SysCmd, opcode, payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) {
|
||||||
|
debug!("sending SHCI");
|
||||||
|
|
||||||
|
Ipcc::send(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, || {
|
||||||
|
self.write(SCHI_OPCODE_BLE_INIT, param.payload());
|
||||||
})
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, true);
|
/// `HW_IPCC_SYS_EvtNot`
|
||||||
|
pub async fn read(&self) -> EvtBox {
|
||||||
|
Ipcc::receive(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, || unsafe {
|
||||||
|
if let Some(node_ptr) = LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
|
||||||
|
Some(EvtBox::new(node_ptr.cast()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
})
|
||||||
pub fn cmd_evt_handler() -> CcEvt {
|
.await
|
||||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, false);
|
|
||||||
|
|
||||||
// ST's command response data structure is really convoluted.
|
|
||||||
//
|
|
||||||
// for command response events on SYS channel, the header is missing
|
|
||||||
// and one should:
|
|
||||||
// 1. interpret the content of CMD_BUFFER as CmdPacket
|
|
||||||
// 2. Access CmdPacket's cmdserial field and interpret its content as EvtSerial
|
|
||||||
// 3. Access EvtSerial's evt field (as Evt) and interpret its payload as CcEvt
|
|
||||||
// 4. CcEvt type is the actual SHCI response
|
|
||||||
// 5. profit
|
|
||||||
unsafe {
|
|
||||||
let pcmd: *const CmdPacket = (*TL_SYS_TABLE.as_ptr()).pcmd_buffer;
|
|
||||||
let cmd_serial: *const CmdSerial = &(*pcmd).cmdserial;
|
|
||||||
let evt_serial: *const EvtSerial = cmd_serial.cast();
|
|
||||||
let cc: *const CcEvt = (*evt_serial).evt.payload.as_ptr().cast();
|
|
||||||
*cc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn evt_handler() {
|
|
||||||
unsafe {
|
|
||||||
while !LinkedListNode::is_empty(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
|
|
||||||
let node_ptr = LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
|
|
||||||
|
|
||||||
let event = node_ptr.cast();
|
|
||||||
let event = EvtBox::new(event);
|
|
||||||
|
|
||||||
EVT_CHANNEL.try_send(event).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_cmd() {
|
|
||||||
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL);
|
|
||||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,12 @@ impl LinkedListNode {
|
|||||||
/// Remove `node` from the linked list
|
/// Remove `node` from the linked list
|
||||||
pub unsafe fn remove_node(mut p_node: *mut LinkedListNode) {
|
pub unsafe fn remove_node(mut p_node: *mut LinkedListNode) {
|
||||||
interrupt::free(|_| {
|
interrupt::free(|_| {
|
||||||
let node = ptr::read_volatile(p_node);
|
// trace!("remove node: {:x}", p_node);
|
||||||
|
// apparently linked list nodes are not always aligned.
|
||||||
|
// if more hardfaults occur, more of these may need to be converted to unaligned.
|
||||||
|
let node = ptr::read_unaligned(p_node);
|
||||||
|
// trace!("remove node: prev/next {:x}/{:x}", node.prev, node.next);
|
||||||
|
|
||||||
if node.next != node.prev {
|
if node.next != node.prev {
|
||||||
let mut node_next = ptr::read_volatile(node.next);
|
let mut node_next = ptr::read_volatile(node.next);
|
||||||
let mut node_prev = ptr::read_volatile(node.prev);
|
let mut node_prev = ptr::read_volatile(node.prev);
|
||||||
@ -139,28 +144,36 @@ impl LinkedListNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Remove `list_head` and return a pointer to the `node`.
|
/// Remove `list_head` and return a pointer to the `node`.
|
||||||
pub unsafe fn remove_head(mut p_list_head: *mut LinkedListNode) -> *mut LinkedListNode {
|
pub unsafe fn remove_head(mut p_list_head: *mut LinkedListNode) -> Option<*mut LinkedListNode> {
|
||||||
interrupt::free(|_| {
|
interrupt::free(|_| {
|
||||||
let list_head = ptr::read_volatile(p_list_head);
|
let list_head = ptr::read_volatile(p_list_head);
|
||||||
|
|
||||||
|
if list_head.next == p_list_head {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
// Allowed because a removed node is not seen by another core
|
// Allowed because a removed node is not seen by another core
|
||||||
let p_node = list_head.next;
|
let p_node = list_head.next;
|
||||||
Self::remove_node(p_node);
|
Self::remove_node(p_node);
|
||||||
|
|
||||||
p_node
|
Some(p_node)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove `list_tail` and return a pointer to the `node`.
|
/// Remove `list_tail` and return a pointer to the `node`.
|
||||||
pub unsafe fn remove_tail(mut p_list_tail: *mut LinkedListNode) -> *mut LinkedListNode {
|
pub unsafe fn remove_tail(mut p_list_tail: *mut LinkedListNode) -> Option<*mut LinkedListNode> {
|
||||||
interrupt::free(|_| {
|
interrupt::free(|_| {
|
||||||
let list_tail = ptr::read_volatile(p_list_tail);
|
let list_tail = ptr::read_volatile(p_list_tail);
|
||||||
|
|
||||||
|
if list_tail.prev == p_list_tail {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
// Allowed because a removed node is not seen by another core
|
// Allowed because a removed node is not seen by another core
|
||||||
let p_node = list_tail.prev;
|
let p_node = list_tail.prev;
|
||||||
Self::remove_node(p_node);
|
Self::remove_node(p_node);
|
||||||
|
|
||||||
p_node
|
Some(p_node)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ sdio-host = "0.5.0"
|
|||||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
atomic-polyfill = "1.0.1"
|
atomic-polyfill = "1.0.1"
|
||||||
stm32-metapac = "9"
|
stm32-metapac = "10"
|
||||||
vcell = "0.1.3"
|
vcell = "0.1.3"
|
||||||
bxcan = "0.7.0"
|
bxcan = "0.7.0"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] }
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
proc-macro2 = "1.0.36"
|
proc-macro2 = "1.0.36"
|
||||||
quote = "1.0.15"
|
quote = "1.0.15"
|
||||||
stm32-metapac = { version = "9", default-features = false, features = ["metadata"]}
|
stm32-metapac = { version = "10", default-features = false, features = ["metadata"]}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["rt"]
|
default = ["rt"]
|
||||||
|
@ -322,7 +322,7 @@ fn main() {
|
|||||||
let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase());
|
let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase());
|
||||||
let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase());
|
let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase());
|
||||||
quote! {
|
quote! {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true));
|
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true));
|
||||||
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false));
|
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false));
|
||||||
});
|
});
|
||||||
@ -353,13 +353,13 @@ fn main() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn enable() {
|
fn enable() {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
|
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
|
||||||
#after_enable
|
#after_enable
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn disable() {
|
fn disable() {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
|
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -32,15 +32,12 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
into_ref!(adc);
|
into_ref!(adc);
|
||||||
T::enable();
|
T::enable();
|
||||||
T::reset();
|
T::reset();
|
||||||
unsafe {
|
|
||||||
T::regs().cr2().modify(|reg| reg.set_adon(true));
|
T::regs().cr2().modify(|reg| reg.set_adon(true));
|
||||||
}
|
|
||||||
|
|
||||||
// 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’)
|
// 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’)
|
||||||
// for at least two ADC clock cycles
|
// for at least two ADC clock cycles
|
||||||
delay.delay_us((1_000_000 * 2) / Self::freq().0 + 1);
|
delay.delay_us((1_000_000 * 2) / Self::freq().0 + 1);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// Reset calibration
|
// Reset calibration
|
||||||
T::regs().cr2().modify(|reg| reg.set_rstcal(true));
|
T::regs().cr2().modify(|reg| reg.set_rstcal(true));
|
||||||
while T::regs().cr2().read().rstcal() {
|
while T::regs().cr2().read().rstcal() {
|
||||||
@ -52,7 +49,6 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
while T::regs().cr2().read().cal() {
|
while T::regs().cr2().read().cal() {
|
||||||
// spin
|
// spin
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// One cycle after calibration
|
// One cycle after calibration
|
||||||
delay.delay_us((1_000_000) / Self::freq().0 + 1);
|
delay.delay_us((1_000_000) / Self::freq().0 + 1);
|
||||||
@ -81,20 +77,16 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref {
|
pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref {
|
||||||
unsafe {
|
|
||||||
T::regs().cr2().modify(|reg| {
|
T::regs().cr2().modify(|reg| {
|
||||||
reg.set_tsvrefe(true);
|
reg.set_tsvrefe(true);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
Vref {}
|
Vref {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_temperature(&self) -> Temperature {
|
pub fn enable_temperature(&self) -> Temperature {
|
||||||
unsafe {
|
|
||||||
T::regs().cr2().modify(|reg| {
|
T::regs().cr2().modify(|reg| {
|
||||||
reg.set_tsvrefe(true);
|
reg.set_tsvrefe(true);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
Temperature {}
|
Temperature {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +96,6 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
|
|
||||||
/// Perform a single conversion.
|
/// Perform a single conversion.
|
||||||
fn convert(&mut self) -> u16 {
|
fn convert(&mut self) -> u16 {
|
||||||
unsafe {
|
|
||||||
T::regs().cr2().modify(|reg| {
|
T::regs().cr2().modify(|reg| {
|
||||||
reg.set_adon(true);
|
reg.set_adon(true);
|
||||||
reg.set_swstart(true);
|
reg.set_swstart(true);
|
||||||
@ -114,10 +105,8 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
|
|
||||||
T::regs().dr().read().0 as u16
|
T::regs().dr().read().0 as u16
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
||||||
unsafe {
|
|
||||||
Self::set_channel_sample_time(pin.channel(), self.sample_time);
|
Self::set_channel_sample_time(pin.channel(), self.sample_time);
|
||||||
T::regs().cr1().modify(|reg| {
|
T::regs().cr1().modify(|reg| {
|
||||||
reg.set_scan(false);
|
reg.set_scan(false);
|
||||||
@ -131,14 +120,13 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
reg.set_swstart(false);
|
reg.set_swstart(false);
|
||||||
reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART);
|
reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the channel to sample
|
// Configure the channel to sample
|
||||||
unsafe { T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())) }
|
T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel()));
|
||||||
self.convert()
|
self.convert()
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||||
let sample_time = sample_time.into();
|
let sample_time = sample_time.into();
|
||||||
if ch <= 9 {
|
if ch <= 9 {
|
||||||
T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
|
T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
|
||||||
|
@ -57,18 +57,14 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
//
|
//
|
||||||
// 6.3.20 Vbat monitoring characteristics
|
// 6.3.20 Vbat monitoring characteristics
|
||||||
// ts_vbat ≥ 4μs
|
// ts_vbat ≥ 4μs
|
||||||
unsafe {
|
|
||||||
T::regs().ccr().modify(|reg| reg.set_vbaten(true));
|
T::regs().ccr().modify(|reg| reg.set_vbaten(true));
|
||||||
}
|
|
||||||
Vbat
|
Vbat
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_vref(&self, delay: &mut impl DelayUs<u32>) -> Vref {
|
pub fn enable_vref(&self, delay: &mut impl DelayUs<u32>) -> Vref {
|
||||||
// Table 28. Embedded internal reference voltage
|
// Table 28. Embedded internal reference voltage
|
||||||
// tstart = 10μs
|
// tstart = 10μs
|
||||||
unsafe {
|
|
||||||
T::regs().ccr().modify(|reg| reg.set_vrefen(true));
|
T::regs().ccr().modify(|reg| reg.set_vrefen(true));
|
||||||
}
|
|
||||||
delay.delay_us(10);
|
delay.delay_us(10);
|
||||||
Vref
|
Vref
|
||||||
}
|
}
|
||||||
@ -79,15 +75,12 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
// 6.3.19 Temperature sensor characteristics
|
// 6.3.19 Temperature sensor characteristics
|
||||||
// tstart ≤ 10μs
|
// tstart ≤ 10μs
|
||||||
// ts_temp ≥ 4μs
|
// ts_temp ≥ 4μs
|
||||||
unsafe {
|
|
||||||
T::regs().ccr().modify(|reg| reg.set_tsen(true));
|
T::regs().ccr().modify(|reg| reg.set_tsen(true));
|
||||||
}
|
|
||||||
delay.delay_us(10);
|
delay.delay_us(10);
|
||||||
Temperature
|
Temperature
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calibrate(&self) {
|
fn calibrate(&self) {
|
||||||
unsafe {
|
|
||||||
// A.7.1 ADC calibration code example
|
// A.7.1 ADC calibration code example
|
||||||
if T::regs().cr().read().aden() {
|
if T::regs().cr().read().aden() {
|
||||||
T::regs().cr().modify(|reg| reg.set_addis(true));
|
T::regs().cr().modify(|reg| reg.set_addis(true));
|
||||||
@ -101,35 +94,30 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
// spin
|
// spin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_sample_time(&mut self, sample_time: SampleTime) {
|
pub fn set_sample_time(&mut self, sample_time: SampleTime) {
|
||||||
self.sample_time = sample_time;
|
self.sample_time = sample_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_resolution(&mut self, resolution: Resolution) {
|
pub fn set_resolution(&mut self, resolution: Resolution) {
|
||||||
unsafe {
|
|
||||||
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
|
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read<P>(&mut self, pin: &mut P) -> u16
|
pub fn read<P>(&mut self, pin: &mut P) -> u16
|
||||||
where
|
where
|
||||||
P: AdcPin<T> + crate::gpio::sealed::Pin,
|
P: AdcPin<T> + crate::gpio::sealed::Pin,
|
||||||
{
|
{
|
||||||
let channel = pin.channel();
|
let channel = pin.channel();
|
||||||
unsafe {
|
|
||||||
pin.set_as_analog();
|
pin.set_as_analog();
|
||||||
self.read_channel(channel)
|
self.read_channel(channel)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
|
pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
|
||||||
let channel = channel.channel();
|
let channel = channel.channel();
|
||||||
unsafe { self.read_channel(channel) }
|
self.read_channel(channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn read_channel(&mut self, channel: u8) -> u16 {
|
fn read_channel(&mut self, channel: u8) -> u16 {
|
||||||
// A.7.2 ADC enable sequence code example
|
// A.7.2 ADC enable sequence code example
|
||||||
if T::regs().isr().read().adrdy() {
|
if T::regs().isr().read().adrdy() {
|
||||||
T::regs().isr().modify(|reg| reg.set_adrdy(true));
|
T::regs().isr().modify(|reg| reg.set_adrdy(true));
|
||||||
|
@ -100,13 +100,10 @@ where
|
|||||||
T::reset();
|
T::reset();
|
||||||
|
|
||||||
let presc = Prescaler::from_pclk2(T::frequency());
|
let presc = Prescaler::from_pclk2(T::frequency());
|
||||||
unsafe {
|
|
||||||
T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
|
T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
|
||||||
|
|
||||||
T::regs().cr2().modify(|reg| {
|
T::regs().cr2().modify(|reg| {
|
||||||
reg.set_adon(crate::pac::adc::vals::Adon::ENABLED);
|
reg.set_adon(crate::pac::adc::vals::Adon::ENABLED);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
delay.delay_us(ADC_POWERUP_TIME_US);
|
delay.delay_us(ADC_POWERUP_TIME_US);
|
||||||
|
|
||||||
@ -121,19 +118,15 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_resolution(&mut self, resolution: Resolution) {
|
pub fn set_resolution(&mut self, resolution: Resolution) {
|
||||||
unsafe {
|
|
||||||
T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
|
T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Enables internal voltage reference and returns [VrefInt], which can be used in
|
/// Enables internal voltage reference and returns [VrefInt], which can be used in
|
||||||
/// [Adc::read_internal()] to perform conversion.
|
/// [Adc::read_internal()] to perform conversion.
|
||||||
pub fn enable_vrefint(&self) -> VrefInt {
|
pub fn enable_vrefint(&self) -> VrefInt {
|
||||||
unsafe {
|
|
||||||
T::common_regs().ccr().modify(|reg| {
|
T::common_regs().ccr().modify(|reg| {
|
||||||
reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
|
reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
VrefInt {}
|
VrefInt {}
|
||||||
}
|
}
|
||||||
@ -144,11 +137,9 @@ where
|
|||||||
/// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled,
|
/// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled,
|
||||||
/// temperature sensor will return vbat value.
|
/// temperature sensor will return vbat value.
|
||||||
pub fn enable_temperature(&self) -> Temperature {
|
pub fn enable_temperature(&self) -> Temperature {
|
||||||
unsafe {
|
|
||||||
T::common_regs().ccr().modify(|reg| {
|
T::common_regs().ccr().modify(|reg| {
|
||||||
reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
|
reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Temperature {}
|
Temperature {}
|
||||||
}
|
}
|
||||||
@ -156,18 +147,15 @@ where
|
|||||||
/// Enables vbat input and returns [Vbat], which can be used in
|
/// Enables vbat input and returns [Vbat], which can be used in
|
||||||
/// [Adc::read_internal()] to perform conversion.
|
/// [Adc::read_internal()] to perform conversion.
|
||||||
pub fn enable_vbat(&self) -> Vbat {
|
pub fn enable_vbat(&self) -> Vbat {
|
||||||
unsafe {
|
|
||||||
T::common_regs().ccr().modify(|reg| {
|
T::common_regs().ccr().modify(|reg| {
|
||||||
reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED);
|
reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Vbat {}
|
Vbat {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform a single conversion.
|
/// Perform a single conversion.
|
||||||
fn convert(&mut self) -> u16 {
|
fn convert(&mut self) -> u16 {
|
||||||
unsafe {
|
|
||||||
// clear end of conversion flag
|
// clear end of conversion flag
|
||||||
T::regs().sr().modify(|reg| {
|
T::regs().sr().modify(|reg| {
|
||||||
reg.set_eoc(crate::pac::adc::vals::Eoc::NOTCOMPLETE);
|
reg.set_eoc(crate::pac::adc::vals::Eoc::NOTCOMPLETE);
|
||||||
@ -187,25 +175,22 @@ where
|
|||||||
|
|
||||||
T::regs().dr().read().0 as u16
|
T::regs().dr().read().0 as u16
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read<P>(&mut self, pin: &mut P) -> u16
|
pub fn read<P>(&mut self, pin: &mut P) -> u16
|
||||||
where
|
where
|
||||||
P: AdcPin<T>,
|
P: AdcPin<T>,
|
||||||
P: crate::gpio::sealed::Pin,
|
P: crate::gpio::sealed::Pin,
|
||||||
{
|
{
|
||||||
unsafe {
|
|
||||||
pin.set_as_analog();
|
pin.set_as_analog();
|
||||||
|
|
||||||
self.read_channel(pin.channel())
|
self.read_channel(pin.channel())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
|
pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
|
||||||
unsafe { self.read_channel(channel.channel()) }
|
self.read_channel(channel.channel())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn read_channel(&mut self, channel: u8) -> u16 {
|
fn read_channel(&mut self, channel: u8) -> u16 {
|
||||||
// Configure ADC
|
// Configure ADC
|
||||||
|
|
||||||
// Select channel
|
// Select channel
|
||||||
@ -219,7 +204,7 @@ where
|
|||||||
val
|
val
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||||
let sample_time = sample_time.into();
|
let sample_time = sample_time.into();
|
||||||
if ch <= 9 {
|
if ch <= 9 {
|
||||||
T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
|
T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
|
||||||
|
@ -12,7 +12,7 @@ pub const VREF_CALIB_MV: u32 = 3000;
|
|||||||
/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock
|
/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock
|
||||||
/// configuration.
|
/// configuration.
|
||||||
fn enable() {
|
fn enable() {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
#[cfg(stm32h7)]
|
#[cfg(stm32h7)]
|
||||||
crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true));
|
crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true));
|
||||||
#[cfg(stm32g0)]
|
#[cfg(stm32g0)]
|
||||||
@ -62,7 +62,6 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||||
into_ref!(adc);
|
into_ref!(adc);
|
||||||
enable();
|
enable();
|
||||||
unsafe {
|
|
||||||
T::regs().cr().modify(|reg| {
|
T::regs().cr().modify(|reg| {
|
||||||
#[cfg(not(adc_g0))]
|
#[cfg(not(adc_g0))]
|
||||||
reg.set_deeppwd(false);
|
reg.set_deeppwd(false);
|
||||||
@ -73,11 +72,9 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
T::regs().cfgr1().modify(|reg| {
|
T::regs().cfgr1().modify(|reg| {
|
||||||
reg.set_chselrmod(false);
|
reg.set_chselrmod(false);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
delay.delay_us(20);
|
delay.delay_us(20);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
T::regs().cr().modify(|reg| {
|
T::regs().cr().modify(|reg| {
|
||||||
reg.set_adcal(true);
|
reg.set_adcal(true);
|
||||||
});
|
});
|
||||||
@ -85,7 +82,6 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
while T::regs().cr().read().adcal() {
|
while T::regs().cr().read().adcal() {
|
||||||
// spin
|
// spin
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
delay.delay_us(1);
|
delay.delay_us(1);
|
||||||
|
|
||||||
@ -96,11 +92,9 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt {
|
pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt {
|
||||||
unsafe {
|
|
||||||
T::common_regs().ccr().modify(|reg| {
|
T::common_regs().ccr().modify(|reg| {
|
||||||
reg.set_vrefen(true);
|
reg.set_vrefen(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
|
// "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
|
||||||
// to stabilize the internal voltage reference, we wait a little more.
|
// to stabilize the internal voltage reference, we wait a little more.
|
||||||
@ -112,21 +106,17 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_temperature(&self) -> Temperature {
|
pub fn enable_temperature(&self) -> Temperature {
|
||||||
unsafe {
|
|
||||||
T::common_regs().ccr().modify(|reg| {
|
T::common_regs().ccr().modify(|reg| {
|
||||||
reg.set_ch17sel(true);
|
reg.set_ch17sel(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Temperature {}
|
Temperature {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_vbat(&self) -> Vbat {
|
pub fn enable_vbat(&self) -> Vbat {
|
||||||
unsafe {
|
|
||||||
T::common_regs().ccr().modify(|reg| {
|
T::common_regs().ccr().modify(|reg| {
|
||||||
reg.set_ch18sel(true);
|
reg.set_ch18sel(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Vbat {}
|
Vbat {}
|
||||||
}
|
}
|
||||||
@ -136,13 +126,11 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_resolution(&mut self, resolution: Resolution) {
|
pub fn set_resolution(&mut self, resolution: Resolution) {
|
||||||
unsafe {
|
|
||||||
#[cfg(not(stm32g0))]
|
#[cfg(not(stm32g0))]
|
||||||
T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
|
T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
|
||||||
#[cfg(stm32g0)]
|
#[cfg(stm32g0)]
|
||||||
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
|
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
/// Convert a raw sample from the `Temperature` to deg C
|
/// Convert a raw sample from the `Temperature` to deg C
|
||||||
@ -155,7 +143,6 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
|
|
||||||
/// Perform a single conversion.
|
/// Perform a single conversion.
|
||||||
fn convert(&mut self) -> u16 {
|
fn convert(&mut self) -> u16 {
|
||||||
unsafe {
|
|
||||||
T::regs().isr().modify(|reg| {
|
T::regs().isr().modify(|reg| {
|
||||||
reg.set_eos(true);
|
reg.set_eos(true);
|
||||||
reg.set_eoc(true);
|
reg.set_eoc(true);
|
||||||
@ -172,10 +159,8 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
|
|
||||||
T::regs().dr().read().0 as u16
|
T::regs().dr().read().0 as u16
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
||||||
unsafe {
|
|
||||||
// Make sure bits are off
|
// Make sure bits are off
|
||||||
while T::regs().cr().read().addis() {
|
while T::regs().cr().read().addis() {
|
||||||
// spin
|
// spin
|
||||||
@ -217,15 +202,14 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
|
|
||||||
val
|
val
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(stm32g0)]
|
#[cfg(stm32g0)]
|
||||||
unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
|
fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
|
||||||
T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
|
T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(stm32g0))]
|
#[cfg(not(stm32g0))]
|
||||||
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||||
let sample_time = sample_time.into();
|
let sample_time = sample_time.into();
|
||||||
if ch <= 9 {
|
if ch <= 9 {
|
||||||
T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time));
|
T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time));
|
||||||
|
@ -46,8 +46,8 @@ foreach_peripheral!(
|
|||||||
(adc, ADC1) => {
|
(adc, ADC1) => {
|
||||||
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 {
|
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 {
|
||||||
fn frequency() -> crate::time::Hertz {
|
fn frequency() -> crate::time::Hertz {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
match crate::rcc::get_freqs().adc {
|
match unsafe { crate::rcc::get_freqs() }.adc {
|
||||||
Some(ck) => ck,
|
Some(ck) => ck,
|
||||||
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
|
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
|
||||||
}
|
}
|
||||||
@ -55,7 +55,7 @@ foreach_peripheral!(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn enable() {
|
fn enable() {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
|
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
|
||||||
});
|
});
|
||||||
ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
|
ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
|
||||||
@ -63,7 +63,7 @@ foreach_peripheral!(
|
|||||||
|
|
||||||
fn disable() {
|
fn disable() {
|
||||||
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
|
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
|
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ foreach_peripheral!(
|
|||||||
|
|
||||||
fn reset() {
|
fn reset() {
|
||||||
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
|
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
|
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
|
||||||
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
|
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
|
||||||
});
|
});
|
||||||
@ -85,8 +85,8 @@ foreach_peripheral!(
|
|||||||
(adc, ADC2) => {
|
(adc, ADC2) => {
|
||||||
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 {
|
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 {
|
||||||
fn frequency() -> crate::time::Hertz {
|
fn frequency() -> crate::time::Hertz {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
match crate::rcc::get_freqs().adc {
|
match unsafe { crate::rcc::get_freqs() }.adc {
|
||||||
Some(ck) => ck,
|
Some(ck) => ck,
|
||||||
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
|
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
|
||||||
}
|
}
|
||||||
@ -94,7 +94,7 @@ foreach_peripheral!(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn enable() {
|
fn enable() {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
|
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
|
||||||
});
|
});
|
||||||
ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
|
ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
|
||||||
@ -102,7 +102,7 @@ foreach_peripheral!(
|
|||||||
|
|
||||||
fn disable() {
|
fn disable() {
|
||||||
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
|
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
|
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -111,7 +111,7 @@ foreach_peripheral!(
|
|||||||
|
|
||||||
fn reset() {
|
fn reset() {
|
||||||
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
|
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
|
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
|
||||||
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
|
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
|
||||||
});
|
});
|
||||||
@ -124,8 +124,8 @@ foreach_peripheral!(
|
|||||||
(adc, ADC3) => {
|
(adc, ADC3) => {
|
||||||
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 {
|
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 {
|
||||||
fn frequency() -> crate::time::Hertz {
|
fn frequency() -> crate::time::Hertz {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
match crate::rcc::get_freqs().adc {
|
match unsafe { crate::rcc::get_freqs() }.adc {
|
||||||
Some(ck) => ck,
|
Some(ck) => ck,
|
||||||
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
|
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
|
||||||
}
|
}
|
||||||
@ -133,19 +133,19 @@ foreach_peripheral!(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn enable() {
|
fn enable() {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true))
|
crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disable() {
|
fn disable() {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false));
|
crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset() {
|
fn reset() {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true));
|
crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true));
|
||||||
crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false));
|
crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false));
|
||||||
});
|
});
|
||||||
@ -232,9 +232,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
|
|
||||||
let prescaler = Prescaler::from_ker_ck(T::frequency());
|
let prescaler = Prescaler::from_ker_ck(T::frequency());
|
||||||
|
|
||||||
unsafe {
|
|
||||||
T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
|
T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
|
||||||
}
|
|
||||||
|
|
||||||
let frequency = Hertz(T::frequency().0 / prescaler.divisor());
|
let frequency = Hertz(T::frequency().0 / prescaler.divisor());
|
||||||
info!("ADC frequency set to {} Hz", frequency.0);
|
info!("ADC frequency set to {} Hz", frequency.0);
|
||||||
@ -251,9 +249,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
} else {
|
} else {
|
||||||
Boost::LT50
|
Boost::LT50
|
||||||
};
|
};
|
||||||
unsafe {
|
|
||||||
T::regs().cr().modify(|w| w.set_boost(boost));
|
T::regs().cr().modify(|w| w.set_boost(boost));
|
||||||
}
|
|
||||||
|
|
||||||
let mut s = Self {
|
let mut s = Self {
|
||||||
adc,
|
adc,
|
||||||
@ -272,28 +268,23 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn power_up(&mut self, delay: &mut impl DelayUs<u16>) {
|
fn power_up(&mut self, delay: &mut impl DelayUs<u16>) {
|
||||||
unsafe {
|
|
||||||
T::regs().cr().modify(|reg| {
|
T::regs().cr().modify(|reg| {
|
||||||
reg.set_deeppwd(false);
|
reg.set_deeppwd(false);
|
||||||
reg.set_advregen(true);
|
reg.set_advregen(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
delay.delay_us(10);
|
delay.delay_us(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure_differential_inputs(&mut self) {
|
fn configure_differential_inputs(&mut self) {
|
||||||
unsafe {
|
|
||||||
T::regs().difsel().modify(|w| {
|
T::regs().difsel().modify(|w| {
|
||||||
for n in 0..20 {
|
for n in 0..20 {
|
||||||
w.set_difsel(n, Difsel::SINGLEENDED);
|
w.set_difsel(n, Difsel::SINGLEENDED);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calibrate(&mut self) {
|
fn calibrate(&mut self) {
|
||||||
unsafe {
|
|
||||||
T::regs().cr().modify(|w| {
|
T::regs().cr().modify(|w| {
|
||||||
w.set_adcaldif(Adcaldif::SINGLEENDED);
|
w.set_adcaldif(Adcaldif::SINGLEENDED);
|
||||||
w.set_adcallin(true);
|
w.set_adcallin(true);
|
||||||
@ -303,53 +294,42 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
|
|
||||||
while T::regs().cr().read().adcal() {}
|
while T::regs().cr().read().adcal() {}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn enable(&mut self) {
|
fn enable(&mut self) {
|
||||||
unsafe {
|
|
||||||
T::regs().isr().write(|w| w.set_adrdy(true));
|
T::regs().isr().write(|w| w.set_adrdy(true));
|
||||||
T::regs().cr().modify(|w| w.set_aden(true));
|
T::regs().cr().modify(|w| w.set_aden(true));
|
||||||
while !T::regs().isr().read().adrdy() {}
|
while !T::regs().isr().read().adrdy() {}
|
||||||
T::regs().isr().write(|w| w.set_adrdy(true));
|
T::regs().isr().write(|w| w.set_adrdy(true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn configure(&mut self) {
|
fn configure(&mut self) {
|
||||||
// single conversion mode, software trigger
|
// single conversion mode, software trigger
|
||||||
unsafe {
|
|
||||||
T::regs().cfgr().modify(|w| {
|
T::regs().cfgr().modify(|w| {
|
||||||
w.set_cont(false);
|
w.set_cont(false);
|
||||||
w.set_exten(Exten::DISABLED);
|
w.set_exten(Exten::DISABLED);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_vrefint(&self) -> VrefInt {
|
pub fn enable_vrefint(&self) -> VrefInt {
|
||||||
unsafe {
|
|
||||||
T::common_regs().ccr().modify(|reg| {
|
T::common_regs().ccr().modify(|reg| {
|
||||||
reg.set_vrefen(true);
|
reg.set_vrefen(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
VrefInt {}
|
VrefInt {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_temperature(&self) -> Temperature {
|
pub fn enable_temperature(&self) -> Temperature {
|
||||||
unsafe {
|
|
||||||
T::common_regs().ccr().modify(|reg| {
|
T::common_regs().ccr().modify(|reg| {
|
||||||
reg.set_vsenseen(true);
|
reg.set_vsenseen(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Temperature {}
|
Temperature {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_vbat(&self) -> Vbat {
|
pub fn enable_vbat(&self) -> Vbat {
|
||||||
unsafe {
|
|
||||||
T::common_regs().ccr().modify(|reg| {
|
T::common_regs().ccr().modify(|reg| {
|
||||||
reg.set_vbaten(true);
|
reg.set_vbaten(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Vbat {}
|
Vbat {}
|
||||||
}
|
}
|
||||||
@ -359,14 +339,11 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_resolution(&mut self, resolution: Resolution) {
|
pub fn set_resolution(&mut self, resolution: Resolution) {
|
||||||
unsafe {
|
|
||||||
T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
|
T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Perform a single conversion.
|
/// Perform a single conversion.
|
||||||
fn convert(&mut self) -> u16 {
|
fn convert(&mut self) -> u16 {
|
||||||
unsafe {
|
|
||||||
T::regs().isr().modify(|reg| {
|
T::regs().isr().modify(|reg| {
|
||||||
reg.set_eos(true);
|
reg.set_eos(true);
|
||||||
reg.set_eoc(true);
|
reg.set_eoc(true);
|
||||||
@ -383,25 +360,22 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
|
|
||||||
T::regs().dr().read().0 as u16
|
T::regs().dr().read().0 as u16
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read<P>(&mut self, pin: &mut P) -> u16
|
pub fn read<P>(&mut self, pin: &mut P) -> u16
|
||||||
where
|
where
|
||||||
P: AdcPin<T>,
|
P: AdcPin<T>,
|
||||||
P: crate::gpio::sealed::Pin,
|
P: crate::gpio::sealed::Pin,
|
||||||
{
|
{
|
||||||
unsafe {
|
|
||||||
pin.set_as_analog();
|
pin.set_as_analog();
|
||||||
|
|
||||||
self.read_channel(pin.channel())
|
self.read_channel(pin.channel())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
|
pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
|
||||||
unsafe { self.read_channel(channel.channel()) }
|
self.read_channel(channel.channel())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn read_channel(&mut self, channel: u8) -> u16 {
|
fn read_channel(&mut self, channel: u8) -> u16 {
|
||||||
// Configure channel
|
// Configure channel
|
||||||
Self::set_channel_sample_time(channel, self.sample_time);
|
Self::set_channel_sample_time(channel, self.sample_time);
|
||||||
|
|
||||||
@ -417,7 +391,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
self.convert()
|
self.convert()
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||||
let sample_time = sample_time.into();
|
let sample_time = sample_time.into();
|
||||||
if ch <= 9 {
|
if ch <= 9 {
|
||||||
T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time));
|
T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time));
|
||||||
|
@ -20,10 +20,8 @@ impl<'d, T: Instance> Can<'d, T> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(peri, rx, tx);
|
into_ref!(peri, rx, tx);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||||
}
|
|
||||||
|
|
||||||
T::enable();
|
T::enable();
|
||||||
T::reset();
|
T::reset();
|
||||||
@ -42,10 +40,8 @@ impl<'d, T: Instance> Can<'d, T> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(peri, rx, tx);
|
into_ref!(peri, rx, tx);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||||
}
|
|
||||||
|
|
||||||
T::enable();
|
T::enable();
|
||||||
T::reset();
|
T::reset();
|
||||||
@ -60,7 +56,7 @@ impl<'d, T: Instance> Drop for Can<'d, T> {
|
|||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Cannot call `free()` because it moves the instance.
|
// Cannot call `free()` because it moves the instance.
|
||||||
// Manually reset the peripheral.
|
// Manually reset the peripheral.
|
||||||
unsafe { T::regs().mcr().write(|w| w.set_reset(true)) }
|
T::regs().mcr().write(|w| w.set_reset(true));
|
||||||
T::disable();
|
T::disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,7 +94,7 @@ unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> {
|
|||||||
foreach_peripheral!(
|
foreach_peripheral!(
|
||||||
(can, $inst:ident) => {
|
(can, $inst:ident) => {
|
||||||
impl sealed::Instance for peripherals::$inst {
|
impl sealed::Instance for peripherals::$inst {
|
||||||
const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.0 as *mut _;
|
const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
|
||||||
|
|
||||||
fn regs() -> &'static crate::pac::can::Can {
|
fn regs() -> &'static crate::pac::can::Can {
|
||||||
&crate::pac::$inst
|
&crate::pac::$inst
|
||||||
|
@ -27,26 +27,24 @@ impl<'d> Crc<'d> {
|
|||||||
|
|
||||||
/// Resets the CRC unit to default value (0xFFFF_FFFF)
|
/// Resets the CRC unit to default value (0xFFFF_FFFF)
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
unsafe { PAC_CRC.cr().write(|w| w.set_reset(true)) };
|
PAC_CRC.cr().write(|w| w.set_reset(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Feeds a word to the peripheral and returns the current CRC value
|
/// Feeds a word to the peripheral and returns the current CRC value
|
||||||
pub fn feed_word(&mut self, word: u32) -> u32 {
|
pub fn feed_word(&mut self, word: u32) -> u32 {
|
||||||
// write a single byte to the device, and return the result
|
// write a single byte to the device, and return the result
|
||||||
unsafe {
|
|
||||||
PAC_CRC.dr().write_value(word);
|
PAC_CRC.dr().write_value(word);
|
||||||
}
|
|
||||||
self.read()
|
self.read()
|
||||||
}
|
}
|
||||||
/// Feed a slice of words to the peripheral and return the result.
|
/// Feed a slice of words to the peripheral and return the result.
|
||||||
pub fn feed_words(&mut self, words: &[u32]) -> u32 {
|
pub fn feed_words(&mut self, words: &[u32]) -> u32 {
|
||||||
for word in words {
|
for word in words {
|
||||||
unsafe { PAC_CRC.dr().write_value(*word) }
|
PAC_CRC.dr().write_value(*word);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.read()
|
self.read()
|
||||||
}
|
}
|
||||||
pub fn read(&self) -> u32 {
|
pub fn read(&self) -> u32 {
|
||||||
unsafe { PAC_CRC.dr().read() }
|
PAC_CRC.dr().read()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,14 +85,11 @@ impl<'d> Crc<'d> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
unsafe {
|
|
||||||
PAC_CRC.cr().modify(|w| w.set_reset(true));
|
PAC_CRC.cr().modify(|w| w.set_reset(true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Reconfigures the CRC peripheral. Doesn't reset.
|
/// Reconfigures the CRC peripheral. Doesn't reset.
|
||||||
fn reconfigure(&mut self) {
|
fn reconfigure(&mut self) {
|
||||||
unsafe {
|
|
||||||
// Init CRC value
|
// Init CRC value
|
||||||
PAC_CRC.init().write_value(self._config.crc_init_value);
|
PAC_CRC.init().write_value(self._config.crc_init_value);
|
||||||
#[cfg(crc_v3)]
|
#[cfg(crc_v3)]
|
||||||
@ -121,59 +118,46 @@ impl<'d> Crc<'d> {
|
|||||||
PolySize::Width16 => vals::Polysize::POLYSIZE16,
|
PolySize::Width16 => vals::Polysize::POLYSIZE16,
|
||||||
PolySize::Width32 => vals::Polysize::POLYSIZE32,
|
PolySize::Width32 => vals::Polysize::POLYSIZE32,
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
}
|
|
||||||
|
|
||||||
self.reset();
|
self.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Feeds a byte into the CRC peripheral. Returns the computed checksum.
|
/// Feeds a byte into the CRC peripheral. Returns the computed checksum.
|
||||||
pub fn feed_byte(&mut self, byte: u8) -> u32 {
|
pub fn feed_byte(&mut self, byte: u8) -> u32 {
|
||||||
unsafe {
|
|
||||||
PAC_CRC.dr8().write_value(byte);
|
PAC_CRC.dr8().write_value(byte);
|
||||||
PAC_CRC.dr().read()
|
PAC_CRC.dr().read()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum.
|
/// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum.
|
||||||
pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 {
|
pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 {
|
||||||
for byte in bytes {
|
for byte in bytes {
|
||||||
unsafe {
|
|
||||||
PAC_CRC.dr8().write_value(*byte);
|
PAC_CRC.dr8().write_value(*byte);
|
||||||
}
|
}
|
||||||
}
|
PAC_CRC.dr().read()
|
||||||
unsafe { PAC_CRC.dr().read() }
|
|
||||||
}
|
}
|
||||||
/// Feeds a halfword into the CRC peripheral. Returns the computed checksum.
|
/// Feeds a halfword into the CRC peripheral. Returns the computed checksum.
|
||||||
pub fn feed_halfword(&mut self, halfword: u16) -> u32 {
|
pub fn feed_halfword(&mut self, halfword: u16) -> u32 {
|
||||||
unsafe {
|
|
||||||
PAC_CRC.dr16().write_value(halfword);
|
PAC_CRC.dr16().write_value(halfword);
|
||||||
PAC_CRC.dr().read()
|
PAC_CRC.dr().read()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum.
|
/// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum.
|
||||||
pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 {
|
pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 {
|
||||||
for halfword in halfwords {
|
for halfword in halfwords {
|
||||||
unsafe {
|
|
||||||
PAC_CRC.dr16().write_value(*halfword);
|
PAC_CRC.dr16().write_value(*halfword);
|
||||||
}
|
}
|
||||||
}
|
PAC_CRC.dr().read()
|
||||||
unsafe { PAC_CRC.dr().read() }
|
|
||||||
}
|
}
|
||||||
/// Feeds a words into the CRC peripheral. Returns the computed checksum.
|
/// Feeds a words into the CRC peripheral. Returns the computed checksum.
|
||||||
pub fn feed_word(&mut self, word: u32) -> u32 {
|
pub fn feed_word(&mut self, word: u32) -> u32 {
|
||||||
unsafe {
|
|
||||||
PAC_CRC.dr().write_value(word as u32);
|
PAC_CRC.dr().write_value(word as u32);
|
||||||
PAC_CRC.dr().read()
|
PAC_CRC.dr().read()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/// Feeds an slice of words into the CRC peripheral. Returns the computed checksum.
|
/// Feeds an slice of words into the CRC peripheral. Returns the computed checksum.
|
||||||
pub fn feed_words(&mut self, words: &[u32]) -> u32 {
|
pub fn feed_words(&mut self, words: &[u32]) -> u32 {
|
||||||
for word in words {
|
for word in words {
|
||||||
unsafe {
|
|
||||||
PAC_CRC.dr().write_value(*word as u32);
|
PAC_CRC.dr().write_value(*word as u32);
|
||||||
}
|
}
|
||||||
}
|
PAC_CRC.dr().read()
|
||||||
unsafe { PAC_CRC.dr().read() }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,8 +96,7 @@ impl Default for Config {
|
|||||||
macro_rules! config_pins {
|
macro_rules! config_pins {
|
||||||
($($pin:ident),*) => {
|
($($pin:ident),*) => {
|
||||||
into_ref!($($pin),*);
|
into_ref!($($pin),*);
|
||||||
// NOTE(unsafe) Exclusive access to the registers
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
$(
|
$(
|
||||||
$pin.set_as_af($pin.af_num(), AFType::Input);
|
$pin.set_as_af($pin.af_num(), AFType::Input);
|
||||||
$pin.set_speed(Speed::VeryHigh);
|
$pin.set_speed(Speed::VeryHigh);
|
||||||
@ -334,7 +333,6 @@ where
|
|||||||
T::reset();
|
T::reset();
|
||||||
T::enable();
|
T::enable();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
peri.regs().cr().modify(|r| {
|
peri.regs().cr().modify(|r| {
|
||||||
r.set_cm(true); // disable continuous mode (snapshot mode)
|
r.set_cm(true); // disable continuous mode (snapshot mode)
|
||||||
r.set_ess(use_embedded_synchronization);
|
r.set_ess(use_embedded_synchronization);
|
||||||
@ -344,7 +342,6 @@ where
|
|||||||
r.set_fcrc(0x00); // capture every frame
|
r.set_fcrc(0x00); // capture every frame
|
||||||
r.set_edm(edm); // extended data mode
|
r.set_edm(edm); // extended data mode
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
T::Interrupt::unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::enable() };
|
unsafe { T::Interrupt::enable() };
|
||||||
@ -352,7 +349,7 @@ where
|
|||||||
Self { inner: peri, dma }
|
Self { inner: peri, dma }
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn toggle(enable: bool) {
|
fn toggle(enable: bool) {
|
||||||
crate::pac::DCMI.cr().modify(|r| {
|
crate::pac::DCMI.cr().modify(|r| {
|
||||||
r.set_enable(enable);
|
r.set_enable(enable);
|
||||||
r.set_capture(enable);
|
r.set_capture(enable);
|
||||||
@ -360,24 +357,20 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn enable_irqs() {
|
fn enable_irqs() {
|
||||||
unsafe {
|
|
||||||
crate::pac::DCMI.ier().modify(|r| {
|
crate::pac::DCMI.ier().modify(|r| {
|
||||||
r.set_err_ie(true);
|
r.set_err_ie(true);
|
||||||
r.set_ovr_ie(true);
|
r.set_ovr_ie(true);
|
||||||
r.set_frame_ie(true);
|
r.set_frame_ie(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_interrupt_flags() {
|
fn clear_interrupt_flags() {
|
||||||
unsafe {
|
|
||||||
crate::pac::DCMI.icr().write(|r| {
|
crate::pac::DCMI.icr().write(|r| {
|
||||||
r.set_ovr_isc(true);
|
r.set_ovr_isc(true);
|
||||||
r.set_err_isc(true);
|
r.set_err_isc(true);
|
||||||
r.set_frame_isc(true);
|
r.set_frame_isc(true);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// This method starts the capture and finishes when both the dma transfer and DCMI finish the frame transfer.
|
/// This method starts the capture and finishes when both the dma transfer and DCMI finish the frame transfer.
|
||||||
/// The implication is that the input buffer size must be exactly the size of the captured frame.
|
/// The implication is that the input buffer size must be exactly the size of the captured frame.
|
||||||
@ -392,41 +385,30 @@ where
|
|||||||
return self.capture_giant(buffer).await;
|
return self.capture_giant(buffer).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn capture_small(&mut self, buffer: &mut [u32]) -> Result<(), Error> {
|
async fn capture_small(&mut self, buffer: &mut [u32]) -> Result<(), Error> {
|
||||||
let r = self.inner.regs();
|
let r = self.inner.regs();
|
||||||
let src = r.dr().ptr() as *mut u32;
|
let src = r.dr().as_ptr() as *mut u32;
|
||||||
let request = self.dma.request();
|
let request = self.dma.request();
|
||||||
let dma_read = unsafe { Transfer::new_read(&mut self.dma, request, src, buffer, Default::default()) };
|
let dma_read = unsafe { Transfer::new_read(&mut self.dma, request, src, buffer, Default::default()) };
|
||||||
|
|
||||||
Self::clear_interrupt_flags();
|
Self::clear_interrupt_flags();
|
||||||
Self::enable_irqs();
|
Self::enable_irqs();
|
||||||
|
|
||||||
unsafe { Self::toggle(true) };
|
Self::toggle(true);
|
||||||
|
|
||||||
let result = poll_fn(|cx| {
|
let result = poll_fn(|cx| {
|
||||||
STATE.waker.register(cx.waker());
|
STATE.waker.register(cx.waker());
|
||||||
|
|
||||||
let ris = unsafe { crate::pac::DCMI.ris().read() };
|
let ris = crate::pac::DCMI.ris().read();
|
||||||
if ris.err_ris() {
|
if ris.err_ris() {
|
||||||
unsafe {
|
crate::pac::DCMI.icr().write(|r| r.set_err_isc(true));
|
||||||
crate::pac::DCMI.icr().write(|r| {
|
|
||||||
r.set_err_isc(true);
|
|
||||||
})
|
|
||||||
};
|
|
||||||
Poll::Ready(Err(Error::PeripheralError))
|
Poll::Ready(Err(Error::PeripheralError))
|
||||||
} else if ris.ovr_ris() {
|
} else if ris.ovr_ris() {
|
||||||
unsafe {
|
crate::pac::DCMI.icr().write(|r| r.set_ovr_isc(true));
|
||||||
crate::pac::DCMI.icr().write(|r| {
|
|
||||||
r.set_ovr_isc(true);
|
|
||||||
})
|
|
||||||
};
|
|
||||||
Poll::Ready(Err(Error::Overrun))
|
Poll::Ready(Err(Error::Overrun))
|
||||||
} else if ris.frame_ris() {
|
} else if ris.frame_ris() {
|
||||||
unsafe {
|
crate::pac::DCMI.icr().write(|r| r.set_frame_isc(true));
|
||||||
crate::pac::DCMI.icr().write(|r| {
|
|
||||||
r.set_frame_isc(true);
|
|
||||||
})
|
|
||||||
};
|
|
||||||
Poll::Ready(Ok(()))
|
Poll::Ready(Ok(()))
|
||||||
} else {
|
} else {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
@ -435,7 +417,7 @@ where
|
|||||||
|
|
||||||
let (_, result) = embassy_futures::join::join(dma_read, result).await;
|
let (_, result) = embassy_futures::join::join(dma_read, result).await;
|
||||||
|
|
||||||
unsafe { Self::toggle(false) };
|
Self::toggle(false);
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -468,7 +450,7 @@ where
|
|||||||
let request = channel.request();
|
let request = channel.request();
|
||||||
|
|
||||||
let r = self.inner.regs();
|
let r = self.inner.regs();
|
||||||
let src = r.dr().ptr() as *mut u32;
|
let src = r.dr().as_ptr() as *mut u32;
|
||||||
|
|
||||||
let mut transfer = unsafe {
|
let mut transfer = unsafe {
|
||||||
crate::dma::DoubleBuffered::new_read(
|
crate::dma::DoubleBuffered::new_read(
|
||||||
@ -526,38 +508,26 @@ where
|
|||||||
let result = poll_fn(|cx| {
|
let result = poll_fn(|cx| {
|
||||||
STATE.waker.register(cx.waker());
|
STATE.waker.register(cx.waker());
|
||||||
|
|
||||||
let ris = unsafe { crate::pac::DCMI.ris().read() };
|
let ris = crate::pac::DCMI.ris().read();
|
||||||
if ris.err_ris() {
|
if ris.err_ris() {
|
||||||
unsafe {
|
crate::pac::DCMI.icr().write(|r| r.set_err_isc(true));
|
||||||
crate::pac::DCMI.icr().write(|r| {
|
|
||||||
r.set_err_isc(true);
|
|
||||||
})
|
|
||||||
};
|
|
||||||
Poll::Ready(Err(Error::PeripheralError))
|
Poll::Ready(Err(Error::PeripheralError))
|
||||||
} else if ris.ovr_ris() {
|
} else if ris.ovr_ris() {
|
||||||
unsafe {
|
crate::pac::DCMI.icr().write(|r| r.set_ovr_isc(true));
|
||||||
crate::pac::DCMI.icr().write(|r| {
|
|
||||||
r.set_ovr_isc(true);
|
|
||||||
})
|
|
||||||
};
|
|
||||||
Poll::Ready(Err(Error::Overrun))
|
Poll::Ready(Err(Error::Overrun))
|
||||||
} else if ris.frame_ris() {
|
} else if ris.frame_ris() {
|
||||||
unsafe {
|
crate::pac::DCMI.icr().write(|r| r.set_frame_isc(true));
|
||||||
crate::pac::DCMI.icr().write(|r| {
|
|
||||||
r.set_frame_isc(true);
|
|
||||||
})
|
|
||||||
};
|
|
||||||
Poll::Ready(Ok(()))
|
Poll::Ready(Ok(()))
|
||||||
} else {
|
} else {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
unsafe { Self::toggle(true) };
|
Self::toggle(true);
|
||||||
|
|
||||||
let (_, result) = embassy_futures::join::join(dma_result, result).await;
|
let (_, result) = embassy_futures::join::join(dma_result, result).await;
|
||||||
|
|
||||||
unsafe { Self::toggle(false) };
|
Self::toggle(false);
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index
|
|||||||
let cr = dma.ch(channel_num).cr();
|
let cr = dma.ch(channel_num).cr();
|
||||||
|
|
||||||
if isr.teif(channel_num) {
|
if isr.teif(channel_num) {
|
||||||
panic!("DMA: error on BDMA@{:08x} channel {}", dma.0 as u32, channel_num);
|
panic!("DMA: error on BDMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
if isr.htif(channel_num) && cr.read().htie() {
|
if isr.htif(channel_num) && cr.read().htie() {
|
||||||
@ -306,29 +306,25 @@ impl<'a, C: Channel> Transfer<'a, C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn clear_irqs(&mut self) {
|
fn clear_irqs(&mut self) {
|
||||||
unsafe {
|
|
||||||
self.channel.regs().ifcr().write(|w| {
|
self.channel.regs().ifcr().write(|w| {
|
||||||
w.set_tcif(self.channel.num(), true);
|
w.set_tcif(self.channel.num(), true);
|
||||||
w.set_teif(self.channel.num(), true);
|
w.set_teif(self.channel.num(), true);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_stop(&mut self) {
|
pub fn request_stop(&mut self) {
|
||||||
let ch = self.channel.regs().ch(self.channel.num());
|
let ch = self.channel.regs().ch(self.channel.num());
|
||||||
|
|
||||||
// Disable the channel. Keep the IEs enabled so the irqs still fire.
|
// Disable the channel. Keep the IEs enabled so the irqs still fire.
|
||||||
unsafe {
|
|
||||||
ch.cr().write(|w| {
|
ch.cr().write(|w| {
|
||||||
w.set_teie(true);
|
w.set_teie(true);
|
||||||
w.set_tcie(true);
|
w.set_tcie(true);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_running(&mut self) -> bool {
|
pub fn is_running(&mut self) -> bool {
|
||||||
let ch = self.channel.regs().ch(self.channel.num());
|
let ch = self.channel.regs().ch(self.channel.num());
|
||||||
let en = unsafe { ch.cr().read() }.en();
|
let en = ch.cr().read().en();
|
||||||
let circular = unsafe { ch.cr().read() }.circ() == vals::Circ::ENABLED;
|
let circular = unsafe { ch.cr().read() }.circ() == vals::Circ::ENABLED;
|
||||||
let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
|
let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
|
||||||
en && (circular || !tcif)
|
en && (circular || !tcif)
|
||||||
@ -338,7 +334,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
|
|||||||
/// Note: this will be zero for transfers that completed without cancellation.
|
/// Note: this will be zero for transfers that completed without cancellation.
|
||||||
pub fn get_remaining_transfers(&self) -> u16 {
|
pub fn get_remaining_transfers(&self) -> u16 {
|
||||||
let ch = self.channel.regs().ch(self.channel.num());
|
let ch = self.channel.regs().ch(self.channel.num());
|
||||||
unsafe { ch.ndtr().read() }.ndt()
|
ch.ndtr().read().ndt()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_wait(mut self) {
|
pub fn blocking_wait(mut self) {
|
||||||
@ -382,7 +378,7 @@ struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>);
|
|||||||
impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
|
impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
|
||||||
fn get_remaining_transfers(&self) -> usize {
|
fn get_remaining_transfers(&self) -> usize {
|
||||||
let ch = self.0.regs().ch(self.0.num());
|
let ch = self.0.regs().ch(self.0.num());
|
||||||
unsafe { ch.ndtr().read() }.ndt() as usize
|
ch.ndtr().read().ndt() as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_complete_count(&self) -> usize {
|
fn get_complete_count(&self) -> usize {
|
||||||
@ -458,7 +454,7 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
|
|||||||
|
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
let ch = self.channel.regs().ch(self.channel.num());
|
let ch = self.channel.regs().ch(self.channel.num());
|
||||||
unsafe { ch.cr().write_value(self.cr) }
|
ch.cr().write_value(self.cr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
@ -485,13 +481,11 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
|
|||||||
|
|
||||||
fn clear_irqs(&mut self) {
|
fn clear_irqs(&mut self) {
|
||||||
let dma = self.channel.regs();
|
let dma = self.channel.regs();
|
||||||
unsafe {
|
|
||||||
dma.ifcr().write(|w| {
|
dma.ifcr().write(|w| {
|
||||||
w.set_htif(self.channel.num(), true);
|
w.set_htif(self.channel.num(), true);
|
||||||
w.set_tcif(self.channel.num(), true);
|
w.set_tcif(self.channel.num(), true);
|
||||||
w.set_teif(self.channel.num(), true);
|
w.set_teif(self.channel.num(), true);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_stop(&mut self) {
|
pub fn request_stop(&mut self) {
|
||||||
@ -500,18 +494,16 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
|
|||||||
// Disable the channel. Keep the IEs enabled so the irqs still fire.
|
// Disable the channel. Keep the IEs enabled so the irqs still fire.
|
||||||
// If the channel is enabled and transfer is not completed, we need to perform
|
// If the channel is enabled and transfer is not completed, we need to perform
|
||||||
// two separate write access to the CR register to disable the channel.
|
// two separate write access to the CR register to disable the channel.
|
||||||
unsafe {
|
|
||||||
ch.cr().write(|w| {
|
ch.cr().write(|w| {
|
||||||
w.set_teie(true);
|
w.set_teie(true);
|
||||||
w.set_htie(true);
|
w.set_htie(true);
|
||||||
w.set_tcie(true);
|
w.set_tcie(true);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_running(&mut self) -> bool {
|
pub fn is_running(&mut self) -> bool {
|
||||||
let ch = self.channel.regs().ch(self.channel.num());
|
let ch = self.channel.regs().ch(self.channel.num());
|
||||||
unsafe { ch.cr().read() }.en()
|
ch.cr().read().en()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index:
|
|||||||
let isr = dma.isr(channel_num / 4).read();
|
let isr = dma.isr(channel_num / 4).read();
|
||||||
|
|
||||||
if isr.teif(channel_num % 4) {
|
if isr.teif(channel_num % 4) {
|
||||||
panic!("DMA: error on DMA@{:08x} channel {}", dma.0 as u32, channel_num);
|
panic!("DMA: error on DMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
if isr.htif(channel_num % 4) && cr.read().htie() {
|
if isr.htif(channel_num % 4) && cr.read().htie() {
|
||||||
@ -387,36 +387,32 @@ impl<'a, C: Channel> Transfer<'a, C> {
|
|||||||
let isrn = self.channel.num() / 4;
|
let isrn = self.channel.num() / 4;
|
||||||
let isrbit = self.channel.num() % 4;
|
let isrbit = self.channel.num() % 4;
|
||||||
|
|
||||||
unsafe {
|
|
||||||
self.channel.regs().ifcr(isrn).write(|w| {
|
self.channel.regs().ifcr(isrn).write(|w| {
|
||||||
w.set_tcif(isrbit, true);
|
w.set_tcif(isrbit, true);
|
||||||
w.set_teif(isrbit, true);
|
w.set_teif(isrbit, true);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_stop(&mut self) {
|
pub fn request_stop(&mut self) {
|
||||||
let ch = self.channel.regs().st(self.channel.num());
|
let ch = self.channel.regs().st(self.channel.num());
|
||||||
|
|
||||||
// Disable the channel. Keep the IEs enabled so the irqs still fire.
|
// Disable the channel. Keep the IEs enabled so the irqs still fire.
|
||||||
unsafe {
|
|
||||||
ch.cr().write(|w| {
|
ch.cr().write(|w| {
|
||||||
w.set_teie(true);
|
w.set_teie(true);
|
||||||
w.set_tcie(true);
|
w.set_tcie(true);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_running(&mut self) -> bool {
|
pub fn is_running(&mut self) -> bool {
|
||||||
let ch = self.channel.regs().st(self.channel.num());
|
let ch = self.channel.regs().st(self.channel.num());
|
||||||
unsafe { ch.cr().read() }.en()
|
ch.cr().read().en()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the total remaining transfers for the channel
|
/// Gets the total remaining transfers for the channel
|
||||||
/// Note: this will be zero for transfers that completed without cancellation.
|
/// Note: this will be zero for transfers that completed without cancellation.
|
||||||
pub fn get_remaining_transfers(&self) -> u16 {
|
pub fn get_remaining_transfers(&self) -> u16 {
|
||||||
let ch = self.channel.regs().st(self.channel.num());
|
let ch = self.channel.regs().st(self.channel.num());
|
||||||
unsafe { ch.ndtr().read() }.ndt()
|
ch.ndtr().read().ndt()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_wait(mut self) {
|
pub fn blocking_wait(mut self) {
|
||||||
@ -537,13 +533,11 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
|
|||||||
let isrn = channel_number / 4;
|
let isrn = channel_number / 4;
|
||||||
let isrbit = channel_number % 4;
|
let isrbit = channel_number % 4;
|
||||||
|
|
||||||
unsafe {
|
|
||||||
dma.ifcr(isrn).write(|w| {
|
dma.ifcr(isrn).write(|w| {
|
||||||
w.set_htif(isrbit, true);
|
w.set_htif(isrbit, true);
|
||||||
w.set_tcif(isrbit, true);
|
w.set_tcif(isrbit, true);
|
||||||
w.set_teif(isrbit, true);
|
w.set_teif(isrbit, true);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn set_buffer0(&mut self, buffer: *mut W) {
|
pub unsafe fn set_buffer0(&mut self, buffer: *mut W) {
|
||||||
@ -558,7 +552,7 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
|
|||||||
|
|
||||||
pub fn is_buffer0_accessible(&mut self) -> bool {
|
pub fn is_buffer0_accessible(&mut self) -> bool {
|
||||||
let ch = self.channel.regs().st(self.channel.num());
|
let ch = self.channel.regs().st(self.channel.num());
|
||||||
unsafe { ch.cr().read() }.ct() == vals::Ct::MEMORY1
|
ch.cr().read().ct() == vals::Ct::MEMORY1
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_waker(&mut self, waker: &Waker) {
|
pub fn set_waker(&mut self, waker: &Waker) {
|
||||||
@ -569,24 +563,22 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
|
|||||||
let ch = self.channel.regs().st(self.channel.num());
|
let ch = self.channel.regs().st(self.channel.num());
|
||||||
|
|
||||||
// Disable the channel. Keep the IEs enabled so the irqs still fire.
|
// Disable the channel. Keep the IEs enabled so the irqs still fire.
|
||||||
unsafe {
|
|
||||||
ch.cr().write(|w| {
|
ch.cr().write(|w| {
|
||||||
w.set_teie(true);
|
w.set_teie(true);
|
||||||
w.set_tcie(true);
|
w.set_tcie(true);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_running(&mut self) -> bool {
|
pub fn is_running(&mut self) -> bool {
|
||||||
let ch = self.channel.regs().st(self.channel.num());
|
let ch = self.channel.regs().st(self.channel.num());
|
||||||
unsafe { ch.cr().read() }.en()
|
ch.cr().read().en()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the total remaining transfers for the channel
|
/// Gets the total remaining transfers for the channel
|
||||||
/// Note: this will be zero for transfers that completed without cancellation.
|
/// Note: this will be zero for transfers that completed without cancellation.
|
||||||
pub fn get_remaining_transfers(&self) -> u16 {
|
pub fn get_remaining_transfers(&self) -> u16 {
|
||||||
let ch = self.channel.regs().st(self.channel.num());
|
let ch = self.channel.regs().st(self.channel.num());
|
||||||
unsafe { ch.ndtr().read() }.ndt()
|
ch.ndtr().read().ndt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -607,7 +599,7 @@ struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>);
|
|||||||
impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
|
impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
|
||||||
fn get_remaining_transfers(&self) -> usize {
|
fn get_remaining_transfers(&self) -> usize {
|
||||||
let ch = self.0.regs().st(self.0.num());
|
let ch = self.0.regs().st(self.0.num());
|
||||||
unsafe { ch.ndtr().read() }.ndt() as usize
|
ch.ndtr().read().ndt() as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_complete_count(&self) -> usize {
|
fn get_complete_count(&self) -> usize {
|
||||||
@ -698,7 +690,7 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
|
|||||||
|
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
let ch = self.channel.regs().st(self.channel.num());
|
let ch = self.channel.regs().st(self.channel.num());
|
||||||
unsafe { ch.cr().write_value(self.cr) }
|
ch.cr().write_value(self.cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
@ -729,31 +721,27 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
|
|||||||
let isrn = channel_number / 4;
|
let isrn = channel_number / 4;
|
||||||
let isrbit = channel_number % 4;
|
let isrbit = channel_number % 4;
|
||||||
|
|
||||||
unsafe {
|
|
||||||
dma.ifcr(isrn).write(|w| {
|
dma.ifcr(isrn).write(|w| {
|
||||||
w.set_htif(isrbit, true);
|
w.set_htif(isrbit, true);
|
||||||
w.set_tcif(isrbit, true);
|
w.set_tcif(isrbit, true);
|
||||||
w.set_teif(isrbit, true);
|
w.set_teif(isrbit, true);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_stop(&mut self) {
|
pub fn request_stop(&mut self) {
|
||||||
let ch = self.channel.regs().st(self.channel.num());
|
let ch = self.channel.regs().st(self.channel.num());
|
||||||
|
|
||||||
// Disable the channel. Keep the IEs enabled so the irqs still fire.
|
// Disable the channel. Keep the IEs enabled so the irqs still fire.
|
||||||
unsafe {
|
|
||||||
ch.cr().write(|w| {
|
ch.cr().write(|w| {
|
||||||
w.set_teie(true);
|
w.set_teie(true);
|
||||||
w.set_htie(true);
|
w.set_htie(true);
|
||||||
w.set_tcie(true);
|
w.set_tcie(true);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_running(&mut self) -> bool {
|
pub fn is_running(&mut self) -> bool {
|
||||||
let ch = self.channel.regs().st(self.channel.num());
|
let ch = self.channel.regs().st(self.channel.num());
|
||||||
unsafe { ch.cr().read() }.en()
|
ch.cr().read().en()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::{pac, peripherals};
|
use crate::{pac, peripherals};
|
||||||
|
|
||||||
pub(crate) unsafe fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) {
|
pub(crate) fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) {
|
||||||
let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num());
|
let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num());
|
||||||
ch_mux_regs.write(|reg| {
|
ch_mux_regs.write(|reg| {
|
||||||
reg.set_nbreq(0);
|
reg.set_nbreq(0);
|
||||||
|
@ -92,13 +92,15 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, in
|
|||||||
if sr.dtef() {
|
if sr.dtef() {
|
||||||
panic!(
|
panic!(
|
||||||
"DMA: data transfer error on DMA@{:08x} channel {}",
|
"DMA: data transfer error on DMA@{:08x} channel {}",
|
||||||
dma.0 as u32, channel_num
|
dma.as_ptr() as u32,
|
||||||
|
channel_num
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if sr.usef() {
|
if sr.usef() {
|
||||||
panic!(
|
panic!(
|
||||||
"DMA: user settings error on DMA@{:08x} channel {}",
|
"DMA: user settings error on DMA@{:08x} channel {}",
|
||||||
dma.0 as u32, channel_num
|
dma.as_ptr() as u32,
|
||||||
|
channel_num
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +300,6 @@ impl<'a, C: Channel> Transfer<'a, C> {
|
|||||||
let ch = self.channel.regs().ch(self.channel.num());
|
let ch = self.channel.regs().ch(self.channel.num());
|
||||||
|
|
||||||
// Disable the channel. Keep the IEs enabled so the irqs still fire.
|
// Disable the channel. Keep the IEs enabled so the irqs still fire.
|
||||||
unsafe {
|
|
||||||
ch.cr().write(|w| {
|
ch.cr().write(|w| {
|
||||||
w.set_tcie(true);
|
w.set_tcie(true);
|
||||||
w.set_useie(true);
|
w.set_useie(true);
|
||||||
@ -306,18 +307,17 @@ impl<'a, C: Channel> Transfer<'a, C> {
|
|||||||
w.set_suspie(true);
|
w.set_suspie(true);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_running(&mut self) -> bool {
|
pub fn is_running(&mut self) -> bool {
|
||||||
let ch = self.channel.regs().ch(self.channel.num());
|
let ch = self.channel.regs().ch(self.channel.num());
|
||||||
!unsafe { ch.sr().read() }.tcf()
|
!ch.sr().read().tcf()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the total remaining transfers for the channel
|
/// Gets the total remaining transfers for the channel
|
||||||
/// Note: this will be zero for transfers that completed without cancellation.
|
/// Note: this will be zero for transfers that completed without cancellation.
|
||||||
pub fn get_remaining_transfers(&self) -> u16 {
|
pub fn get_remaining_transfers(&self) -> u16 {
|
||||||
let ch = self.channel.regs().ch(self.channel.num());
|
let ch = self.channel.regs().ch(self.channel.num());
|
||||||
unsafe { ch.br1().read() }.bndt()
|
ch.br1().read().bndt()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_wait(mut self) {
|
pub fn blocking_wait(mut self) {
|
||||||
|
@ -29,7 +29,6 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl
|
|||||||
WAKER.wake();
|
WAKER.wake();
|
||||||
|
|
||||||
// TODO: Check and clear more flags
|
// TODO: Check and clear more flags
|
||||||
unsafe {
|
|
||||||
let dma = ETH.ethernet_dma();
|
let dma = ETH.ethernet_dma();
|
||||||
|
|
||||||
dma.dmasr().modify(|w| {
|
dma.dmasr().modify(|w| {
|
||||||
@ -42,7 +41,6 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl
|
|||||||
dma.dmasr().read();
|
dma.dmasr().read();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Ethernet<'d, T: Instance, P: PHY> {
|
pub struct Ethernet<'d, T: Instance, P: PHY> {
|
||||||
_peri: PeripheralRef<'d, T>,
|
_peri: PeripheralRef<'d, T>,
|
||||||
@ -59,7 +57,6 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
|
|||||||
#[cfg(eth_v1a)]
|
#[cfg(eth_v1a)]
|
||||||
macro_rules! config_in_pins {
|
macro_rules! config_in_pins {
|
||||||
($($pin:ident),*) => {
|
($($pin:ident),*) => {
|
||||||
// NOTE(unsafe) Exclusive access to the registers
|
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
$(
|
$(
|
||||||
// TODO properly create a set_as_input function
|
// TODO properly create a set_as_input function
|
||||||
@ -72,7 +69,6 @@ macro_rules! config_in_pins {
|
|||||||
#[cfg(eth_v1a)]
|
#[cfg(eth_v1a)]
|
||||||
macro_rules! config_af_pins {
|
macro_rules! config_af_pins {
|
||||||
($($pin:ident),*) => {
|
($($pin:ident),*) => {
|
||||||
// NOTE(unsafe) Exclusive access to the registers
|
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
$(
|
$(
|
||||||
// We are lucky here, this configures to max speed (50MHz)
|
// We are lucky here, this configures to max speed (50MHz)
|
||||||
@ -85,7 +81,6 @@ macro_rules! config_af_pins {
|
|||||||
#[cfg(any(eth_v1b, eth_v1c))]
|
#[cfg(any(eth_v1b, eth_v1c))]
|
||||||
macro_rules! config_pins {
|
macro_rules! config_pins {
|
||||||
($($pin:ident),*) => {
|
($($pin:ident),*) => {
|
||||||
// NOTE(unsafe) Exclusive access to the registers
|
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
$(
|
$(
|
||||||
$pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
|
$pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
|
||||||
@ -116,9 +111,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// Enable the necessary Clocks
|
// Enable the necessary Clocks
|
||||||
// NOTE(unsafe) We have exclusive access to the registers
|
|
||||||
#[cfg(eth_v1a)]
|
#[cfg(eth_v1a)]
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
RCC.apb2enr().modify(|w| w.set_afioen(true));
|
RCC.apb2enr().modify(|w| w.set_afioen(true));
|
||||||
@ -156,7 +149,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
#[cfg(any(eth_v1b, eth_v1c))]
|
#[cfg(any(eth_v1b, eth_v1c))]
|
||||||
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
||||||
|
|
||||||
// NOTE(unsafe) We have exclusive access to the registers
|
|
||||||
let dma = ETH.ethernet_dma();
|
let dma = ETH.ethernet_dma();
|
||||||
let mac = ETH.ethernet_mac();
|
let mac = ETH.ethernet_mac();
|
||||||
|
|
||||||
@ -201,7 +193,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
// TODO MTU size setting not found for v1 ethernet, check if correct
|
// TODO MTU size setting not found for v1 ethernet, check if correct
|
||||||
|
|
||||||
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
|
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
|
||||||
let hclk = crate::rcc::get_freqs().ahb1;
|
let hclk = unsafe { crate::rcc::get_freqs() }.ahb1;
|
||||||
let hclk_mhz = hclk.0 / 1_000_000;
|
let hclk_mhz = hclk.0 / 1_000_000;
|
||||||
|
|
||||||
// Set the MDC clock frequency in the range 1MHz - 2.5MHz
|
// Set the MDC clock frequency in the range 1MHz - 2.5MHz
|
||||||
@ -268,17 +260,14 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
P::phy_init(&mut this);
|
P::phy_init(&mut this);
|
||||||
|
|
||||||
interrupt::ETH.unpend();
|
interrupt::ETH.unpend();
|
||||||
interrupt::ETH.enable();
|
unsafe { interrupt::ETH.enable() };
|
||||||
|
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
|
unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
|
||||||
fn smi_read(&mut self, reg: u8) -> u16 {
|
fn smi_read(&mut self, reg: u8) -> u16 {
|
||||||
// NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self`
|
|
||||||
unsafe {
|
|
||||||
let mac = ETH.ethernet_mac();
|
let mac = ETH.ethernet_mac();
|
||||||
|
|
||||||
mac.macmiiar().modify(|w| {
|
mac.macmiiar().modify(|w| {
|
||||||
@ -291,11 +280,8 @@ unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
|
|||||||
while mac.macmiiar().read().mb() == MbProgress::BUSY {}
|
while mac.macmiiar().read().mb() == MbProgress::BUSY {}
|
||||||
mac.macmiidr().read().md()
|
mac.macmiidr().read().md()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn smi_write(&mut self, reg: u8, val: u16) {
|
fn smi_write(&mut self, reg: u8, val: u16) {
|
||||||
// NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self`
|
|
||||||
unsafe {
|
|
||||||
let mac = ETH.ethernet_mac();
|
let mac = ETH.ethernet_mac();
|
||||||
|
|
||||||
mac.macmiidr().write(|w| w.set_md(val));
|
mac.macmiidr().write(|w| w.set_md(val));
|
||||||
@ -309,12 +295,9 @@ unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
|
|||||||
while mac.macmiiar().read().mb() == MbProgress::BUSY {}
|
while mac.macmiiar().read().mb() == MbProgress::BUSY {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
|
impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers
|
|
||||||
unsafe {
|
|
||||||
let dma = ETH.ethernet_dma();
|
let dma = ETH.ethernet_dma();
|
||||||
let mac = ETH.ethernet_mac();
|
let mac = ETH.ethernet_mac();
|
||||||
|
|
||||||
@ -328,10 +311,8 @@ impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED));
|
dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED));
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE(unsafe) Exclusive access to the regs
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
for pin in self.pins.iter_mut() {
|
for pin in self.pins.iter_mut() {
|
||||||
pin.set_as_disconnected();
|
pin.set_as_disconnected();
|
||||||
}
|
}
|
||||||
|
@ -146,12 +146,9 @@ impl<'a> RDesRing<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register rx descriptor start
|
// Register rx descriptor start
|
||||||
// NOTE (unsafe) Used for atomic writes
|
|
||||||
unsafe {
|
|
||||||
ETH.ethernet_dma()
|
ETH.ethernet_dma()
|
||||||
.dmardlar()
|
.dmardlar()
|
||||||
.write(|w| w.0 = descriptors.as_ptr() as u32);
|
.write(|w| w.0 = descriptors.as_ptr() as u32);
|
||||||
};
|
|
||||||
// We already have fences in `set_owned`, which is called in `setup`
|
// We already have fences in `set_owned`, which is called in `setup`
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -162,12 +159,12 @@ impl<'a> RDesRing<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn demand_poll(&self) {
|
pub(crate) fn demand_poll(&self) {
|
||||||
unsafe { ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL)) };
|
ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get current `RunningState`
|
/// Get current `RunningState`
|
||||||
fn running_state(&self) -> RunningState {
|
fn running_state(&self) -> RunningState {
|
||||||
match unsafe { ETH.ethernet_dma().dmasr().read().rps() } {
|
match ETH.ethernet_dma().dmasr().read().rps() {
|
||||||
// Reset or Stop Receive Command issued
|
// Reset or Stop Receive Command issued
|
||||||
Rps::STOPPED => RunningState::Stopped,
|
Rps::STOPPED => RunningState::Stopped,
|
||||||
// Fetching receive transfer descriptor
|
// Fetching receive transfer descriptor
|
||||||
|
@ -120,12 +120,9 @@ impl<'a> TDesRing<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register txdescriptor start
|
// Register txdescriptor start
|
||||||
// NOTE (unsafe) Used for atomic writes
|
|
||||||
unsafe {
|
|
||||||
ETH.ethernet_dma()
|
ETH.ethernet_dma()
|
||||||
.dmatdlar()
|
.dmatdlar()
|
||||||
.write(|w| w.0 = descriptors.as_ptr() as u32);
|
.write(|w| w.0 = descriptors.as_ptr() as u32);
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
descriptors,
|
descriptors,
|
||||||
@ -169,6 +166,6 @@ impl<'a> TDesRing<'a> {
|
|||||||
self.index = 0
|
self.index = 0
|
||||||
}
|
}
|
||||||
// Request the DMA engine to poll the latest tx descriptor
|
// Request the DMA engine to poll the latest tx descriptor
|
||||||
unsafe { ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1) }
|
ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,14 +73,10 @@ impl<'a> TDesRing<'a> {
|
|||||||
|
|
||||||
// Initialize the pointers in the DMA engine. (There will be a memory barrier later
|
// Initialize the pointers in the DMA engine. (There will be a memory barrier later
|
||||||
// before the DMA engine is enabled.)
|
// before the DMA engine is enabled.)
|
||||||
// NOTE (unsafe) Used for atomic writes
|
|
||||||
unsafe {
|
|
||||||
let dma = ETH.ethernet_dma();
|
let dma = ETH.ethernet_dma();
|
||||||
|
|
||||||
dma.dmactx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32);
|
dma.dmactx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32);
|
||||||
dma.dmactx_rlr().write(|w| w.set_tdrl((descriptors.len() as u16) - 1));
|
dma.dmactx_rlr().write(|w| w.set_tdrl((descriptors.len() as u16) - 1));
|
||||||
dma.dmactx_dtpr().write(|w| w.0 = 0);
|
dma.dmactx_dtpr().write(|w| w.0 = 0);
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
descriptors,
|
descriptors,
|
||||||
@ -129,8 +125,7 @@ impl<'a> TDesRing<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// signal DMA it can try again.
|
// signal DMA it can try again.
|
||||||
// NOTE(unsafe) Atomic write
|
ETH.ethernet_dma().dmactx_dtpr().write(|w| w.0 = 0)
|
||||||
unsafe { ETH.ethernet_dma().dmactx_dtpr().write(|w| w.0 = 0) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,13 +194,10 @@ impl<'a> RDesRing<'a> {
|
|||||||
desc.set_ready(buffers[i].0.as_mut_ptr());
|
desc.set_ready(buffers[i].0.as_mut_ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let dma = ETH.ethernet_dma();
|
let dma = ETH.ethernet_dma();
|
||||||
|
|
||||||
dma.dmacrx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32);
|
dma.dmacrx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32);
|
||||||
dma.dmacrx_rlr().write(|w| w.set_rdrl((descriptors.len() as u16) - 1));
|
dma.dmacrx_rlr().write(|w| w.set_rdrl((descriptors.len() as u16) - 1));
|
||||||
dma.dmacrx_dtpr().write(|w| w.0 = 0);
|
dma.dmacrx_dtpr().write(|w| w.0 = 0);
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
descriptors,
|
descriptors,
|
||||||
@ -254,8 +246,7 @@ impl<'a> RDesRing<'a> {
|
|||||||
fence(Ordering::Release);
|
fence(Ordering::Release);
|
||||||
|
|
||||||
// signal DMA it can try again.
|
// signal DMA it can try again.
|
||||||
// NOTE(unsafe) Atomic write
|
ETH.ethernet_dma().dmacrx_dtpr().write(|w| w.0 = 0);
|
||||||
unsafe { ETH.ethernet_dma().dmacrx_dtpr().write(|w| w.0 = 0) }
|
|
||||||
|
|
||||||
// Increment index.
|
// Increment index.
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
|
@ -20,7 +20,6 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl
|
|||||||
WAKER.wake();
|
WAKER.wake();
|
||||||
|
|
||||||
// TODO: Check and clear more flags
|
// TODO: Check and clear more flags
|
||||||
unsafe {
|
|
||||||
let dma = ETH.ethernet_dma();
|
let dma = ETH.ethernet_dma();
|
||||||
|
|
||||||
dma.dmacsr().modify(|w| {
|
dma.dmacsr().modify(|w| {
|
||||||
@ -33,7 +32,6 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl
|
|||||||
dma.dmacsr().read();
|
dma.dmacsr().read();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet
|
const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet
|
||||||
|
|
||||||
@ -50,7 +48,6 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
|
|||||||
|
|
||||||
macro_rules! config_pins {
|
macro_rules! config_pins {
|
||||||
($($pin:ident),*) => {
|
($($pin:ident),*) => {
|
||||||
// NOTE(unsafe) Exclusive access to the registers
|
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
$(
|
$(
|
||||||
$pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
|
$pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
|
||||||
@ -80,9 +77,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// Enable the necessary Clocks
|
// Enable the necessary Clocks
|
||||||
// NOTE(unsafe) We have exclusive access to the registers
|
|
||||||
#[cfg(not(rcc_h5))]
|
#[cfg(not(rcc_h5))]
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true));
|
crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true));
|
||||||
@ -114,7 +109,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
|
|
||||||
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
||||||
|
|
||||||
// NOTE(unsafe) We have exclusive access to the registers
|
|
||||||
let dma = ETH.ethernet_dma();
|
let dma = ETH.ethernet_dma();
|
||||||
let mac = ETH.ethernet_mac();
|
let mac = ETH.ethernet_mac();
|
||||||
let mtl = ETH.ethernet_mtl();
|
let mtl = ETH.ethernet_mtl();
|
||||||
@ -174,7 +168,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
|
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
|
||||||
let hclk = crate::rcc::get_freqs().ahb1;
|
let hclk = unsafe { crate::rcc::get_freqs() }.ahb1;
|
||||||
let hclk_mhz = hclk.0 / 1_000_000;
|
let hclk_mhz = hclk.0 / 1_000_000;
|
||||||
|
|
||||||
// Set the MDC clock frequency in the range 1MHz - 2.5MHz
|
// Set the MDC clock frequency in the range 1MHz - 2.5MHz
|
||||||
@ -239,17 +233,14 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
P::phy_init(&mut this);
|
P::phy_init(&mut this);
|
||||||
|
|
||||||
interrupt::ETH.unpend();
|
interrupt::ETH.unpend();
|
||||||
interrupt::ETH.enable();
|
unsafe { interrupt::ETH.enable() };
|
||||||
|
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
|
unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
|
||||||
fn smi_read(&mut self, reg: u8) -> u16 {
|
fn smi_read(&mut self, reg: u8) -> u16 {
|
||||||
// NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self`
|
|
||||||
unsafe {
|
|
||||||
let mac = ETH.ethernet_mac();
|
let mac = ETH.ethernet_mac();
|
||||||
|
|
||||||
mac.macmdioar().modify(|w| {
|
mac.macmdioar().modify(|w| {
|
||||||
@ -262,11 +253,8 @@ unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
|
|||||||
while mac.macmdioar().read().mb() {}
|
while mac.macmdioar().read().mb() {}
|
||||||
mac.macmdiodr().read().md()
|
mac.macmdiodr().read().md()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn smi_write(&mut self, reg: u8, val: u16) {
|
fn smi_write(&mut self, reg: u8, val: u16) {
|
||||||
// NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self`
|
|
||||||
unsafe {
|
|
||||||
let mac = ETH.ethernet_mac();
|
let mac = ETH.ethernet_mac();
|
||||||
|
|
||||||
mac.macmdiodr().write(|w| w.set_md(val));
|
mac.macmdiodr().write(|w| w.set_md(val));
|
||||||
@ -280,12 +268,9 @@ unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
|
|||||||
while mac.macmdioar().read().mb() {}
|
while mac.macmdioar().read().mb() {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
|
impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers
|
|
||||||
unsafe {
|
|
||||||
let dma = ETH.ethernet_dma();
|
let dma = ETH.ethernet_dma();
|
||||||
let mac = ETH.ethernet_mac();
|
let mac = ETH.ethernet_mac();
|
||||||
let mtl = ETH.ethernet_mtl();
|
let mtl = ETH.ethernet_mtl();
|
||||||
@ -309,10 +294,8 @@ impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
|
|||||||
rxqueue.rxqsts() != 0b00 || rxqueue.prxq() != 0
|
rxqueue.rxqsts() != 0b00 || rxqueue.prxq() != 0
|
||||||
} {}
|
} {}
|
||||||
dma.dmacrx_cr().modify(|w| w.set_sr(false));
|
dma.dmacrx_cr().modify(|w| w.set_sr(false));
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE(unsafe) Exclusive access to the regs
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
for pin in self.pins.iter_mut() {
|
for pin in self.pins.iter_mut() {
|
||||||
pin.set_as_disconnected();
|
pin.set_as_disconnected();
|
||||||
}
|
}
|
||||||
|
@ -206,7 +206,7 @@ struct ExtiInputFuture<'a> {
|
|||||||
|
|
||||||
impl<'a> ExtiInputFuture<'a> {
|
impl<'a> ExtiInputFuture<'a> {
|
||||||
fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self {
|
fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
let pin = pin as usize;
|
let pin = pin as usize;
|
||||||
exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port));
|
exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port));
|
||||||
EXTI.rtsr(0).modify(|w| w.set_line(pin, rising));
|
EXTI.rtsr(0).modify(|w| w.set_line(pin, rising));
|
||||||
@ -233,7 +233,7 @@ impl<'a> ExtiInputFuture<'a> {
|
|||||||
|
|
||||||
impl<'a> Drop for ExtiInputFuture<'a> {
|
impl<'a> Drop for ExtiInputFuture<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
let pin = self.pin as _;
|
let pin = self.pin as _;
|
||||||
cpu_regs().imr(0).modify(|w| w.set_line(pin, false));
|
cpu_regs().imr(0).modify(|w| w.set_line(pin, false));
|
||||||
});
|
});
|
||||||
@ -246,7 +246,7 @@ impl<'a> Future for ExtiInputFuture<'a> {
|
|||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
EXTI_WAKERS[self.pin as usize].register(cx.waker());
|
EXTI_WAKERS[self.pin as usize].register(cx.waker());
|
||||||
|
|
||||||
let imr = unsafe { cpu_regs().imr(0).read() };
|
let imr = cpu_regs().imr(0).read();
|
||||||
if !imr.line(self.pin as _) {
|
if !imr.line(self.pin as _) {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
} else {
|
} else {
|
||||||
|
@ -192,7 +192,7 @@ impl FlashSector {
|
|||||||
|
|
||||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
|
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
|
||||||
pub(crate) fn is_default_layout() -> bool {
|
pub(crate) fn is_default_layout() -> bool {
|
||||||
unsafe { !pac::FLASH.optcr().read().db1m() }
|
!pac::FLASH.optcr().read().db1m()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))]
|
#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))]
|
||||||
@ -336,7 +336,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
|
|||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn clear_all_err() {
|
pub(crate) fn clear_all_err() {
|
||||||
pac::FLASH.sr().write(|w| {
|
pac::FLASH.sr().write(|w| {
|
||||||
w.set_pgserr(true);
|
w.set_pgserr(true);
|
||||||
w.set_pgperr(true);
|
w.set_pgperr(true);
|
||||||
@ -345,7 +345,7 @@ pub(crate) unsafe fn clear_all_err() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async unsafe fn wait_ready() -> Result<(), Error> {
|
pub(crate) async fn wait_ready() -> Result<(), Error> {
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use futures::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
@ -391,10 +391,10 @@ fn save_data_cache_state() {
|
|||||||
let dual_bank = get_flash_regions().last().unwrap().bank == FlashBank::Bank2;
|
let dual_bank = get_flash_regions().last().unwrap().bank == FlashBank::Bank2;
|
||||||
if dual_bank {
|
if dual_bank {
|
||||||
// Disable data cache during write/erase if there are two banks, see errata 2.2.12
|
// Disable data cache during write/erase if there are two banks, see errata 2.2.12
|
||||||
let dcen = unsafe { pac::FLASH.acr().read().dcen() };
|
let dcen = pac::FLASH.acr().read().dcen();
|
||||||
DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed);
|
DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed);
|
||||||
if dcen {
|
if dcen {
|
||||||
unsafe { pac::FLASH.acr().modify(|w| w.set_dcen(false)) };
|
pac::FLASH.acr().modify(|w| w.set_dcen(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -405,12 +405,10 @@ fn restore_data_cache_state() {
|
|||||||
// Restore data cache if it was enabled
|
// Restore data cache if it was enabled
|
||||||
let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed);
|
let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed);
|
||||||
if dcen {
|
if dcen {
|
||||||
unsafe {
|
|
||||||
// Reset data cache before we enable it again
|
// Reset data cache before we enable it again
|
||||||
pac::FLASH.acr().modify(|w| w.set_dcrst(true));
|
pac::FLASH.acr().modify(|w| w.set_dcrst(true));
|
||||||
pac::FLASH.acr().modify(|w| w.set_dcrst(false));
|
pac::FLASH.acr().modify(|w| w.set_dcrst(false));
|
||||||
pac::FLASH.acr().modify(|w| w.set_dcen(true))
|
pac::FLASH.acr().modify(|w| w.set_dcen(true))
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -445,7 +443,7 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) {
|
|||||||
feature = "stm32f439vi",
|
feature = "stm32f439vi",
|
||||||
feature = "stm32f439zi",
|
feature = "stm32f439zi",
|
||||||
))]
|
))]
|
||||||
if second_bank_read && unsafe { pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() } {
|
if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() {
|
||||||
panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11");
|
panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,12 +477,10 @@ fn pa12_is_output_pull_low() -> bool {
|
|||||||
use pac::gpio::vals;
|
use pac::gpio::vals;
|
||||||
use pac::GPIOA;
|
use pac::GPIOA;
|
||||||
const PIN: usize = 12;
|
const PIN: usize = 12;
|
||||||
unsafe {
|
|
||||||
GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT
|
GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT
|
||||||
&& GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN
|
&& GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN
|
||||||
&& GPIOA.odr().read().odr(PIN) == vals::Odr::LOW
|
&& GPIOA.odr().read().odr(PIN) == vals::Odr::LOW
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -16,7 +16,7 @@ unsafe impl<'d, T> stm32_fmc::FmcPeripheral for Fmc<'d, T>
|
|||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
const REGISTERS: *const () = T::REGS.0 as *const _;
|
const REGISTERS: *const () = T::REGS.as_ptr() as *const _;
|
||||||
|
|
||||||
fn enable(&mut self) {
|
fn enable(&mut self) {
|
||||||
<T as crate::rcc::sealed::RccPeripheral>::enable();
|
<T as crate::rcc::sealed::RccPeripheral>::enable();
|
||||||
@ -28,9 +28,7 @@ where
|
|||||||
// fsmc v1, v2 and v3 does not have the fmcen bit
|
// fsmc v1, v2 and v3 does not have the fmcen bit
|
||||||
// This is a "not" because it is expected that all future versions have this bit
|
// This is a "not" because it is expected that all future versions have this bit
|
||||||
#[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))]
|
#[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))]
|
||||||
unsafe {
|
T::REGS.bcr1().modify(|r| r.set_fmcen(true));
|
||||||
T::REGS.bcr1().modify(|r| r.set_fmcen(true))
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn source_clock_hz(&self) -> u32 {
|
fn source_clock_hz(&self) -> u32 {
|
||||||
@ -67,7 +65,7 @@ macro_rules! fmc_sdram_constructor {
|
|||||||
chip: CHIP
|
chip: CHIP
|
||||||
) -> stm32_fmc::Sdram<Fmc<'d, T>, CHIP> {
|
) -> stm32_fmc::Sdram<Fmc<'d, T>, CHIP> {
|
||||||
|
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
config_pins!(
|
config_pins!(
|
||||||
$($addr_pin_name),*,
|
$($addr_pin_name),*,
|
||||||
$($ba_pin_name),*,
|
$($ba_pin_name),*,
|
||||||
|
@ -46,7 +46,7 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
/// Put the pin into input mode.
|
/// Put the pin into input mode.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_as_input(&mut self, pull: Pull) {
|
pub fn set_as_input(&mut self, pull: Pull) {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
let r = self.pin.block();
|
let r = self.pin.block();
|
||||||
let n = self.pin.pin() as usize;
|
let n = self.pin.pin() as usize;
|
||||||
#[cfg(gpio_v1)]
|
#[cfg(gpio_v1)]
|
||||||
@ -84,7 +84,7 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
/// at a specific level, call `set_high`/`set_low` on the pin first.
|
/// at a specific level, call `set_high`/`set_low` on the pin first.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_as_output(&mut self, speed: Speed) {
|
pub fn set_as_output(&mut self, speed: Speed) {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
let r = self.pin.block();
|
let r = self.pin.block();
|
||||||
let n = self.pin.pin() as usize;
|
let n = self.pin.pin() as usize;
|
||||||
#[cfg(gpio_v1)]
|
#[cfg(gpio_v1)]
|
||||||
@ -116,7 +116,7 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
/// at a specific level, call `set_high`/`set_low` on the pin first.
|
/// at a specific level, call `set_high`/`set_low` on the pin first.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_as_input_output(&mut self, speed: Speed, pull: Pull) {
|
pub fn set_as_input_output(&mut self, speed: Speed, pull: Pull) {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
let r = self.pin.block();
|
let r = self.pin.block();
|
||||||
let n = self.pin.pin() as usize;
|
let n = self.pin.pin() as usize;
|
||||||
#[cfg(gpio_v1)]
|
#[cfg(gpio_v1)]
|
||||||
@ -147,7 +147,7 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_low(&self) -> bool {
|
pub fn is_low(&self) -> bool {
|
||||||
let state = unsafe { self.pin.block().idr().read().idr(self.pin.pin() as _) };
|
let state = self.pin.block().idr().read().idr(self.pin.pin() as _);
|
||||||
state == vals::Idr::LOW
|
state == vals::Idr::LOW
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
/// Is the output pin set as low?
|
/// Is the output pin set as low?
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_set_low(&self) -> bool {
|
pub fn is_set_low(&self) -> bool {
|
||||||
let state = unsafe { self.pin.block().odr().read().odr(self.pin.pin() as _) };
|
let state = self.pin.block().odr().read().odr(self.pin.pin() as _);
|
||||||
state == vals::Odr::LOW
|
state == vals::Odr::LOW
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
impl<'d, T: Pin> Drop for Flex<'d, T> {
|
impl<'d, T: Pin> Drop for Flex<'d, T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
let r = self.pin.block();
|
let r = self.pin.block();
|
||||||
let n = self.pin.pin() as usize;
|
let n = self.pin.pin() as usize;
|
||||||
#[cfg(gpio_v1)]
|
#[cfg(gpio_v1)]
|
||||||
@ -534,29 +534,25 @@ pub(crate) mod sealed {
|
|||||||
/// Set the output as high.
|
/// Set the output as high.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn set_high(&self) {
|
fn set_high(&self) {
|
||||||
unsafe {
|
|
||||||
let n = self._pin() as _;
|
let n = self._pin() as _;
|
||||||
self.block().bsrr().write(|w| w.set_bs(n, true));
|
self.block().bsrr().write(|w| w.set_bs(n, true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the output as low.
|
/// Set the output as low.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn set_low(&self) {
|
fn set_low(&self) {
|
||||||
unsafe {
|
|
||||||
let n = self._pin() as _;
|
let n = self._pin() as _;
|
||||||
self.block().bsrr().write(|w| w.set_br(n, true));
|
self.block().bsrr().write(|w| w.set_br(n, true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_as_af(&self, af_num: u8, af_type: AFType) {
|
fn set_as_af(&self, af_num: u8, af_type: AFType) {
|
||||||
self.set_as_af_pull(af_num, af_type, Pull::None);
|
self.set_as_af_pull(af_num, af_type, Pull::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(gpio_v1)]
|
#[cfg(gpio_v1)]
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) {
|
fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) {
|
||||||
// F1 uses the AFIO register for remapping.
|
// F1 uses the AFIO register for remapping.
|
||||||
// For now, this is not implemented, so af_num is ignored
|
// For now, this is not implemented, so af_num is ignored
|
||||||
// _af_num should be zero here, since it is not set by stm32-data
|
// _af_num should be zero here, since it is not set by stm32-data
|
||||||
@ -599,7 +595,7 @@ pub(crate) mod sealed {
|
|||||||
|
|
||||||
#[cfg(gpio_v2)]
|
#[cfg(gpio_v2)]
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) {
|
fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) {
|
||||||
let pin = self._pin() as usize;
|
let pin = self._pin() as usize;
|
||||||
let block = self.block();
|
let block = self.block();
|
||||||
block.afr(pin / 8).modify(|w| w.set_afr(pin % 8, af_num));
|
block.afr(pin / 8).modify(|w| w.set_afr(pin % 8, af_num));
|
||||||
@ -614,7 +610,7 @@ pub(crate) mod sealed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_as_analog(&self) {
|
fn set_as_analog(&self) {
|
||||||
let pin = self._pin() as usize;
|
let pin = self._pin() as usize;
|
||||||
let block = self.block();
|
let block = self.block();
|
||||||
#[cfg(gpio_v1)]
|
#[cfg(gpio_v1)]
|
||||||
@ -635,12 +631,12 @@ pub(crate) mod sealed {
|
|||||||
/// This is currently the same as set_as_analog but is semantically different really.
|
/// This is currently the same as set_as_analog but is semantically different really.
|
||||||
/// Drivers should set_as_disconnected pins when dropped.
|
/// Drivers should set_as_disconnected pins when dropped.
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_as_disconnected(&self) {
|
fn set_as_disconnected(&self) {
|
||||||
self.set_as_analog();
|
self.set_as_analog();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_speed(&self, speed: Speed) {
|
fn set_speed(&self, speed: Speed) {
|
||||||
let pin = self._pin() as usize;
|
let pin = self._pin() as usize;
|
||||||
|
|
||||||
#[cfg(gpio_v1)]
|
#[cfg(gpio_v1)]
|
||||||
|
@ -68,7 +68,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
T::enable();
|
T::enable();
|
||||||
T::reset();
|
T::reset();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
scl.set_as_af_pull(
|
scl.set_as_af_pull(
|
||||||
scl.af_num(),
|
scl.af_num(),
|
||||||
AFType::OutputOpenDrain,
|
AFType::OutputOpenDrain,
|
||||||
@ -85,18 +84,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
false => Pull::None,
|
false => Pull::None,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
T::regs().cr1().modify(|reg| {
|
T::regs().cr1().modify(|reg| {
|
||||||
reg.set_pe(false);
|
reg.set_pe(false);
|
||||||
//reg.set_anfoff(false);
|
//reg.set_anfoff(false);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
let timings = Timings::new(T::frequency(), freq.into());
|
let timings = Timings::new(T::frequency(), freq.into());
|
||||||
|
|
||||||
unsafe {
|
|
||||||
T::regs().cr2().modify(|reg| {
|
T::regs().cr2().modify(|reg| {
|
||||||
reg.set_freq(timings.freq);
|
reg.set_freq(timings.freq);
|
||||||
});
|
});
|
||||||
@ -108,13 +103,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
T::regs().trise().modify(|reg| {
|
T::regs().trise().modify(|reg| {
|
||||||
reg.set_trise(timings.trise);
|
reg.set_trise(timings.trise);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
T::regs().cr1().modify(|reg| {
|
T::regs().cr1().modify(|reg| {
|
||||||
reg.set_pe(true);
|
reg.set_pe(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
@ -123,7 +115,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> {
|
fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> {
|
||||||
// Note that flags should only be cleared once they have been registered. If flags are
|
// Note that flags should only be cleared once they have been registered. If flags are
|
||||||
// cleared otherwise, there may be an inherent race condition and flags may be missed.
|
// cleared otherwise, there may be an inherent race condition and flags may be missed.
|
||||||
let sr1 = T::regs().sr1().read();
|
let sr1 = T::regs().sr1().read();
|
||||||
@ -162,7 +154,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
Ok(sr1)
|
Ok(sr1)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn write_bytes(
|
fn write_bytes(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: u8,
|
addr: u8,
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
@ -211,7 +203,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
|
fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
|
||||||
// Wait until we're ready for sending
|
// Wait until we're ready for sending
|
||||||
while {
|
while {
|
||||||
// Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
|
// Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
|
||||||
@ -234,7 +226,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> {
|
fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> {
|
||||||
while {
|
while {
|
||||||
// Check for any potential error conditions.
|
// Check for any potential error conditions.
|
||||||
self.check_and_clear_error_flags()?;
|
self.check_and_clear_error_flags()?;
|
||||||
@ -256,56 +248,52 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if let Some((last, buffer)) = buffer.split_last_mut() {
|
if let Some((last, buffer)) = buffer.split_last_mut() {
|
||||||
// Send a START condition and set ACK bit
|
// Send a START condition and set ACK bit
|
||||||
unsafe {
|
|
||||||
T::regs().cr1().modify(|reg| {
|
T::regs().cr1().modify(|reg| {
|
||||||
reg.set_start(true);
|
reg.set_start(true);
|
||||||
reg.set_ack(true);
|
reg.set_ack(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until START condition was generated
|
// Wait until START condition was generated
|
||||||
while unsafe { !self.check_and_clear_error_flags()?.start() } {
|
while !self.check_and_clear_error_flags()?.start() {
|
||||||
check_timeout()?;
|
check_timeout()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also wait until signalled we're master and everything is waiting for us
|
// Also wait until signalled we're master and everything is waiting for us
|
||||||
while {
|
while {
|
||||||
let sr2 = unsafe { T::regs().sr2().read() };
|
let sr2 = T::regs().sr2().read();
|
||||||
!sr2.msl() && !sr2.busy()
|
!sr2.msl() && !sr2.busy()
|
||||||
} {
|
} {
|
||||||
check_timeout()?;
|
check_timeout()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up current address, we're trying to talk to
|
// Set up current address, we're trying to talk to
|
||||||
unsafe { T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)) }
|
T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1));
|
||||||
|
|
||||||
// Wait until address was sent
|
// Wait until address was sent
|
||||||
// Wait for the address to be acknowledged
|
// Wait for the address to be acknowledged
|
||||||
while unsafe { !self.check_and_clear_error_flags()?.addr() } {
|
while !self.check_and_clear_error_flags()?.addr() {
|
||||||
check_timeout()?;
|
check_timeout()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear condition by reading SR2
|
// Clear condition by reading SR2
|
||||||
let _ = unsafe { T::regs().sr2().read() };
|
let _ = T::regs().sr2().read();
|
||||||
|
|
||||||
// Receive bytes into buffer
|
// Receive bytes into buffer
|
||||||
for c in buffer {
|
for c in buffer {
|
||||||
*c = unsafe { self.recv_byte(&check_timeout)? };
|
*c = self.recv_byte(&check_timeout)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare to send NACK then STOP after next byte
|
// Prepare to send NACK then STOP after next byte
|
||||||
unsafe {
|
|
||||||
T::regs().cr1().modify(|reg| {
|
T::regs().cr1().modify(|reg| {
|
||||||
reg.set_ack(false);
|
reg.set_ack(false);
|
||||||
reg.set_stop(true);
|
reg.set_stop(true);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Receive last byte
|
// Receive last byte
|
||||||
*last = unsafe { self.recv_byte(&check_timeout)? };
|
*last = self.recv_byte(&check_timeout)?;
|
||||||
|
|
||||||
// Wait for the STOP to be sent.
|
// Wait for the STOP to be sent.
|
||||||
while unsafe { T::regs().cr1().read().stop() } {
|
while T::regs().cr1().read().stop() {
|
||||||
check_timeout()?;
|
check_timeout()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +314,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
write: &[u8],
|
write: &[u8],
|
||||||
check_timeout: impl Fn() -> Result<(), Error>,
|
check_timeout: impl Fn() -> Result<(), Error>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
unsafe {
|
|
||||||
self.write_bytes(addr, write, &check_timeout)?;
|
self.write_bytes(addr, write, &check_timeout)?;
|
||||||
// Send a STOP condition
|
// Send a STOP condition
|
||||||
T::regs().cr1().modify(|reg| reg.set_stop(true));
|
T::regs().cr1().modify(|reg| reg.set_stop(true));
|
||||||
@ -334,7 +321,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
while T::regs().cr1().read().stop() {
|
while T::regs().cr1().read().stop() {
|
||||||
check_timeout()?;
|
check_timeout()?;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// Fallthrough is success
|
// Fallthrough is success
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -351,7 +337,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
read: &mut [u8],
|
read: &mut [u8],
|
||||||
check_timeout: impl Fn() -> Result<(), Error>,
|
check_timeout: impl Fn() -> Result<(), Error>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
unsafe { self.write_bytes(addr, write, &check_timeout)? };
|
self.write_bytes(addr, write, &check_timeout)?;
|
||||||
self.blocking_read_timeout(addr, read, &check_timeout)?;
|
self.blocking_read_timeout(addr, read, &check_timeout)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -478,8 +464,6 @@ impl Timings {
|
|||||||
assert!(freq >= 2 && freq <= 50);
|
assert!(freq >= 2 && freq <= 50);
|
||||||
|
|
||||||
// Configure bus frequency into I2C peripheral
|
// Configure bus frequency into I2C peripheral
|
||||||
//self.i2c.cr2.write(|w| unsafe { w.freq().bits(freq as u8) });
|
|
||||||
|
|
||||||
let trise = if speed <= 100_000 {
|
let trise = if speed <= 100_000 {
|
||||||
freq + 1
|
freq + 1
|
||||||
} else {
|
} else {
|
||||||
@ -539,7 +523,6 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> {
|
|||||||
type Config = Hertz;
|
type Config = Hertz;
|
||||||
fn set_config(&mut self, config: &Self::Config) {
|
fn set_config(&mut self, config: &Self::Config) {
|
||||||
let timings = Timings::new(T::frequency(), *config);
|
let timings = Timings::new(T::frequency(), *config);
|
||||||
unsafe {
|
|
||||||
T::regs().cr2().modify(|reg| {
|
T::regs().cr2().modify(|reg| {
|
||||||
reg.set_freq(timings.freq);
|
reg.set_freq(timings.freq);
|
||||||
});
|
});
|
||||||
@ -553,4 +536,3 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -89,7 +89,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
T::enable();
|
T::enable();
|
||||||
T::reset();
|
T::reset();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
scl.set_as_af_pull(
|
scl.set_as_af_pull(
|
||||||
scl.af_num(),
|
scl.af_num(),
|
||||||
AFType::OutputOpenDrain,
|
AFType::OutputOpenDrain,
|
||||||
@ -106,18 +105,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
false => Pull::None,
|
false => Pull::None,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
T::regs().cr1().modify(|reg| {
|
T::regs().cr1().modify(|reg| {
|
||||||
reg.set_pe(false);
|
reg.set_pe(false);
|
||||||
reg.set_anfoff(false);
|
reg.set_anfoff(false);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
let timings = Timings::new(T::frequency(), freq.into());
|
let timings = Timings::new(T::frequency(), freq.into());
|
||||||
|
|
||||||
unsafe {
|
|
||||||
T::regs().timingr().write(|reg| {
|
T::regs().timingr().write(|reg| {
|
||||||
reg.set_presc(timings.prescale);
|
reg.set_presc(timings.prescale);
|
||||||
reg.set_scll(timings.scll);
|
reg.set_scll(timings.scll);
|
||||||
@ -125,13 +120,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
reg.set_sdadel(timings.sdadel);
|
reg.set_sdadel(timings.sdadel);
|
||||||
reg.set_scldel(timings.scldel);
|
reg.set_scldel(timings.scldel);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
T::regs().cr1().modify(|reg| {
|
T::regs().cr1().modify(|reg| {
|
||||||
reg.set_pe(true);
|
reg.set_pe(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
T::Interrupt::unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::enable() };
|
unsafe { T::Interrupt::enable() };
|
||||||
@ -144,12 +136,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn master_stop(&mut self) {
|
fn master_stop(&mut self) {
|
||||||
unsafe {
|
|
||||||
T::regs().cr2().write(|w| w.set_stop(true));
|
T::regs().cr2().write(|w| w.set_stop(true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn master_read(
|
fn master_read(
|
||||||
address: u8,
|
address: u8,
|
||||||
length: usize,
|
length: usize,
|
||||||
stop: Stop,
|
stop: Stop,
|
||||||
@ -191,7 +181,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn master_write(
|
fn master_write(
|
||||||
address: u8,
|
address: u8,
|
||||||
length: usize,
|
length: usize,
|
||||||
stop: Stop,
|
stop: Stop,
|
||||||
@ -229,7 +219,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn master_continue(
|
fn master_continue(
|
||||||
length: usize,
|
length: usize,
|
||||||
reload: bool,
|
reload: bool,
|
||||||
check_timeout: impl Fn() -> Result<(), Error>,
|
check_timeout: impl Fn() -> Result<(), Error>,
|
||||||
@ -259,14 +249,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
//$i2c.txdr.write(|w| w.txdata().bits(0));
|
//$i2c.txdr.write(|w| w.txdata().bits(0));
|
||||||
//}
|
//}
|
||||||
|
|
||||||
unsafe {
|
|
||||||
if T::regs().isr().read().txis() {
|
if T::regs().isr().read().txis() {
|
||||||
T::regs().txdr().write(|w| w.set_txdata(0));
|
T::regs().txdr().write(|w| w.set_txdata(0));
|
||||||
}
|
}
|
||||||
if !T::regs().isr().read().txe() {
|
if !T::regs().isr().read().txe() {
|
||||||
T::regs().isr().modify(|w| w.set_txe(true))
|
T::regs().isr().modify(|w| w.set_txe(true))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If TXDR is not flagged as empty, write 1 to flush it
|
// If TXDR is not flagged as empty, write 1 to flush it
|
||||||
//if $i2c.isr.read().txe().is_not_empty() {
|
//if $i2c.isr.read().txe().is_not_empty() {
|
||||||
@ -276,7 +264,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
|
|
||||||
fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
|
fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
|
||||||
loop {
|
loop {
|
||||||
unsafe {
|
|
||||||
let isr = T::regs().isr().read();
|
let isr = T::regs().isr().read();
|
||||||
if isr.txe() {
|
if isr.txe() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -291,7 +278,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
self.flush_txdr();
|
self.flush_txdr();
|
||||||
return Err(Error::Nack);
|
return Err(Error::Nack);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
check_timeout()?;
|
check_timeout()?;
|
||||||
}
|
}
|
||||||
@ -299,7 +285,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
|
|
||||||
fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
|
fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
|
||||||
loop {
|
loop {
|
||||||
unsafe {
|
|
||||||
let isr = T::regs().isr().read();
|
let isr = T::regs().isr().read();
|
||||||
if isr.rxne() {
|
if isr.rxne() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -314,7 +299,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
self.flush_txdr();
|
self.flush_txdr();
|
||||||
return Err(Error::Nack);
|
return Err(Error::Nack);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
check_timeout()?;
|
check_timeout()?;
|
||||||
}
|
}
|
||||||
@ -322,7 +306,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
|
|
||||||
fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
|
fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
|
||||||
loop {
|
loop {
|
||||||
unsafe {
|
|
||||||
let isr = T::regs().isr().read();
|
let isr = T::regs().isr().read();
|
||||||
if isr.tc() {
|
if isr.tc() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -337,7 +320,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
self.flush_txdr();
|
self.flush_txdr();
|
||||||
return Err(Error::Nack);
|
return Err(Error::Nack);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
check_timeout()?;
|
check_timeout()?;
|
||||||
}
|
}
|
||||||
@ -358,7 +340,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
};
|
};
|
||||||
let last_chunk_idx = total_chunks.saturating_sub(1);
|
let last_chunk_idx = total_chunks.saturating_sub(1);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
Self::master_read(
|
Self::master_read(
|
||||||
address,
|
address,
|
||||||
read.len().min(255),
|
read.len().min(255),
|
||||||
@ -367,25 +348,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
restart,
|
restart,
|
||||||
&check_timeout,
|
&check_timeout,
|
||||||
)?;
|
)?;
|
||||||
}
|
|
||||||
|
|
||||||
for (number, chunk) in read.chunks_mut(255).enumerate() {
|
for (number, chunk) in read.chunks_mut(255).enumerate() {
|
||||||
if number != 0 {
|
if number != 0 {
|
||||||
// NOTE(unsafe) We have &mut self
|
|
||||||
unsafe {
|
|
||||||
Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
|
Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for byte in chunk {
|
for byte in chunk {
|
||||||
// Wait until we have received something
|
// Wait until we have received something
|
||||||
self.wait_rxne(&check_timeout)?;
|
self.wait_rxne(&check_timeout)?;
|
||||||
|
|
||||||
unsafe {
|
|
||||||
*byte = T::regs().rxdr().read().rxdata();
|
*byte = T::regs().rxdr().read().rxdata();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,8 +382,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
// I2C start
|
// I2C start
|
||||||
//
|
//
|
||||||
// ST SAD+W
|
// ST SAD+W
|
||||||
// NOTE(unsafe) We have &mut self
|
|
||||||
unsafe {
|
|
||||||
Self::master_write(
|
Self::master_write(
|
||||||
address,
|
address,
|
||||||
write.len().min(255),
|
write.len().min(255),
|
||||||
@ -416,15 +389,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
last_chunk_idx != 0,
|
last_chunk_idx != 0,
|
||||||
&check_timeout,
|
&check_timeout,
|
||||||
)?;
|
)?;
|
||||||
}
|
|
||||||
|
|
||||||
for (number, chunk) in write.chunks(255).enumerate() {
|
for (number, chunk) in write.chunks(255).enumerate() {
|
||||||
if number != 0 {
|
if number != 0 {
|
||||||
// NOTE(unsafe) We have &mut self
|
|
||||||
unsafe {
|
|
||||||
Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
|
Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for byte in chunk {
|
for byte in chunk {
|
||||||
// Wait until we are allowed to send data
|
// Wait until we are allowed to send data
|
||||||
@ -432,11 +401,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
// through)
|
// through)
|
||||||
self.wait_txe(&check_timeout)?;
|
self.wait_txe(&check_timeout)?;
|
||||||
|
|
||||||
unsafe {
|
|
||||||
T::regs().txdr().write(|w| w.set_txdata(*byte));
|
T::regs().txdr().write(|w| w.set_txdata(*byte));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Wait until the write finishes
|
// Wait until the write finishes
|
||||||
self.wait_tc(&check_timeout)?;
|
self.wait_tc(&check_timeout)?;
|
||||||
|
|
||||||
@ -467,7 +434,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
w.set_tcie(true);
|
w.set_tcie(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let dst = regs.txdr().ptr() as *mut u8;
|
let dst = regs.txdr().as_ptr() as *mut u8;
|
||||||
|
|
||||||
let ch = &mut self.tx_dma;
|
let ch = &mut self.tx_dma;
|
||||||
let request = ch.request();
|
let request = ch.request();
|
||||||
@ -479,24 +446,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
|
|
||||||
let on_drop = OnDrop::new(|| {
|
let on_drop = OnDrop::new(|| {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
unsafe {
|
|
||||||
regs.cr1().modify(|w| {
|
regs.cr1().modify(|w| {
|
||||||
if last_slice {
|
if last_slice {
|
||||||
w.set_txdmaen(false);
|
w.set_txdmaen(false);
|
||||||
}
|
}
|
||||||
w.set_tcie(false);
|
w.set_tcie(false);
|
||||||
})
|
})
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
state.waker.register(cx.waker());
|
state.waker.register(cx.waker());
|
||||||
|
|
||||||
let isr = unsafe { T::regs().isr().read() };
|
let isr = T::regs().isr().read();
|
||||||
if remaining_len == total_len {
|
if remaining_len == total_len {
|
||||||
// NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers
|
|
||||||
if first_slice {
|
if first_slice {
|
||||||
unsafe {
|
|
||||||
Self::master_write(
|
Self::master_write(
|
||||||
address,
|
address,
|
||||||
total_len.min(255),
|
total_len.min(255),
|
||||||
@ -504,13 +467,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
(total_len > 255) || !last_slice,
|
(total_len > 255) || !last_slice,
|
||||||
&check_timeout,
|
&check_timeout,
|
||||||
)?;
|
)?;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
|
||||||
Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?;
|
Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?;
|
||||||
T::regs().cr1().modify(|w| w.set_tcie(true));
|
T::regs().cr1().modify(|w| w.set_tcie(true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if !(isr.tcr() || isr.tc()) {
|
} else if !(isr.tcr() || isr.tc()) {
|
||||||
// poll_fn was woken without an interrupt present
|
// poll_fn was woken without an interrupt present
|
||||||
return Poll::Pending;
|
return Poll::Pending;
|
||||||
@ -519,14 +479,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
} else {
|
} else {
|
||||||
let last_piece = (remaining_len <= 255) && last_slice;
|
let last_piece = (remaining_len <= 255) && last_slice;
|
||||||
|
|
||||||
// NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers
|
|
||||||
unsafe {
|
|
||||||
if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
|
if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
|
||||||
return Poll::Ready(Err(e));
|
return Poll::Ready(Err(e));
|
||||||
}
|
}
|
||||||
T::regs().cr1().modify(|w| w.set_tcie(true));
|
T::regs().cr1().modify(|w| w.set_tcie(true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
remaining_len = remaining_len.saturating_sub(255);
|
remaining_len = remaining_len.saturating_sub(255);
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
@ -564,7 +521,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
w.set_rxdmaen(true);
|
w.set_rxdmaen(true);
|
||||||
w.set_tcie(true);
|
w.set_tcie(true);
|
||||||
});
|
});
|
||||||
let src = regs.rxdr().ptr() as *mut u8;
|
let src = regs.rxdr().as_ptr() as *mut u8;
|
||||||
|
|
||||||
let ch = &mut self.rx_dma;
|
let ch = &mut self.rx_dma;
|
||||||
let request = ch.request();
|
let request = ch.request();
|
||||||
@ -576,21 +533,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
|
|
||||||
let on_drop = OnDrop::new(|| {
|
let on_drop = OnDrop::new(|| {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
unsafe {
|
|
||||||
regs.cr1().modify(|w| {
|
regs.cr1().modify(|w| {
|
||||||
w.set_rxdmaen(false);
|
w.set_rxdmaen(false);
|
||||||
w.set_tcie(false);
|
w.set_tcie(false);
|
||||||
})
|
})
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
state.waker.register(cx.waker());
|
state.waker.register(cx.waker());
|
||||||
|
|
||||||
let isr = unsafe { T::regs().isr().read() };
|
let isr = T::regs().isr().read();
|
||||||
if remaining_len == total_len {
|
if remaining_len == total_len {
|
||||||
// NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers
|
|
||||||
unsafe {
|
|
||||||
Self::master_read(
|
Self::master_read(
|
||||||
address,
|
address,
|
||||||
total_len.min(255),
|
total_len.min(255),
|
||||||
@ -599,7 +552,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
restart,
|
restart,
|
||||||
&check_timeout,
|
&check_timeout,
|
||||||
)?;
|
)?;
|
||||||
}
|
|
||||||
} else if !(isr.tcr() || isr.tc()) {
|
} else if !(isr.tcr() || isr.tc()) {
|
||||||
// poll_fn was woken without an interrupt present
|
// poll_fn was woken without an interrupt present
|
||||||
return Poll::Pending;
|
return Poll::Pending;
|
||||||
@ -608,14 +560,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
} else {
|
} else {
|
||||||
let last_piece = remaining_len <= 255;
|
let last_piece = remaining_len <= 255;
|
||||||
|
|
||||||
// NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers
|
|
||||||
unsafe {
|
|
||||||
if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
|
if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
|
||||||
return Poll::Ready(Err(e));
|
return Poll::Ready(Err(e));
|
||||||
}
|
}
|
||||||
T::regs().cr1().modify(|w| w.set_tcie(true));
|
T::regs().cr1().modify(|w| w.set_tcie(true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
remaining_len = remaining_len.saturating_sub(255);
|
remaining_len = remaining_len.saturating_sub(255);
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
@ -758,8 +707,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
let first_length = write[0].len();
|
let first_length = write[0].len();
|
||||||
let last_slice_index = write.len() - 1;
|
let last_slice_index = write.len() - 1;
|
||||||
|
|
||||||
// NOTE(unsafe) We have &mut self
|
|
||||||
unsafe {
|
|
||||||
Self::master_write(
|
Self::master_write(
|
||||||
address,
|
address,
|
||||||
first_length.min(255),
|
first_length.min(255),
|
||||||
@ -767,7 +714,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
(first_length > 255) || (last_slice_index != 0),
|
(first_length > 255) || (last_slice_index != 0),
|
||||||
&check_timeout,
|
&check_timeout,
|
||||||
)?;
|
)?;
|
||||||
}
|
|
||||||
|
|
||||||
for (idx, slice) in write.iter().enumerate() {
|
for (idx, slice) in write.iter().enumerate() {
|
||||||
let slice_len = slice.len();
|
let slice_len = slice.len();
|
||||||
@ -780,27 +726,21 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
let last_chunk_idx = total_chunks.saturating_sub(1);
|
let last_chunk_idx = total_chunks.saturating_sub(1);
|
||||||
|
|
||||||
if idx != 0 {
|
if idx != 0 {
|
||||||
// NOTE(unsafe) We have &mut self
|
|
||||||
unsafe {
|
|
||||||
Self::master_continue(
|
Self::master_continue(
|
||||||
slice_len.min(255),
|
slice_len.min(255),
|
||||||
(idx != last_slice_index) || (slice_len > 255),
|
(idx != last_slice_index) || (slice_len > 255),
|
||||||
&check_timeout,
|
&check_timeout,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (number, chunk) in slice.chunks(255).enumerate() {
|
for (number, chunk) in slice.chunks(255).enumerate() {
|
||||||
if number != 0 {
|
if number != 0 {
|
||||||
// NOTE(unsafe) We have &mut self
|
|
||||||
unsafe {
|
|
||||||
Self::master_continue(
|
Self::master_continue(
|
||||||
chunk.len(),
|
chunk.len(),
|
||||||
(number != last_chunk_idx) || (idx != last_slice_index),
|
(number != last_chunk_idx) || (idx != last_slice_index),
|
||||||
&check_timeout,
|
&check_timeout,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for byte in chunk {
|
for byte in chunk {
|
||||||
// Wait until we are allowed to send data
|
// Wait until we are allowed to send data
|
||||||
@ -810,12 +750,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
|
|
||||||
// Put byte on the wire
|
// Put byte on the wire
|
||||||
//self.i2c.txdr.write(|w| w.txdata().bits(*byte));
|
//self.i2c.txdr.write(|w| w.txdata().bits(*byte));
|
||||||
unsafe {
|
|
||||||
T::regs().txdr().write(|w| w.set_txdata(*byte));
|
T::regs().txdr().write(|w| w.set_txdata(*byte));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Wait until the write finishes
|
// Wait until the write finishes
|
||||||
self.wait_tc(&check_timeout)?;
|
self.wait_tc(&check_timeout)?;
|
||||||
self.master_stop();
|
self.master_stop();
|
||||||
@ -1061,7 +999,6 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> {
|
|||||||
type Config = Hertz;
|
type Config = Hertz;
|
||||||
fn set_config(&mut self, config: &Self::Config) {
|
fn set_config(&mut self, config: &Self::Config) {
|
||||||
let timings = Timings::new(T::frequency(), *config);
|
let timings = Timings::new(T::frequency(), *config);
|
||||||
unsafe {
|
|
||||||
T::regs().timingr().write(|reg| {
|
T::regs().timingr().write(|reg| {
|
||||||
reg.set_presc(timings.prescale);
|
reg.set_presc(timings.prescale);
|
||||||
reg.set_scll(timings.scll);
|
reg.set_scll(timings.scll);
|
||||||
@ -1071,4 +1008,3 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -153,7 +153,6 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(sd, ws, ck, mck);
|
into_ref!(sd, ws, ck, mck);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
sd.set_as_af(sd.af_num(), AFType::OutputPushPull);
|
sd.set_as_af(sd.af_num(), AFType::OutputPushPull);
|
||||||
sd.set_speed(crate::gpio::Speed::VeryHigh);
|
sd.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
|
|
||||||
@ -165,7 +164,6 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
|
|||||||
|
|
||||||
mck.set_as_af(mck.af_num(), AFType::OutputPushPull);
|
mck.set_as_af(mck.af_num(), AFType::OutputPushPull);
|
||||||
mck.set_speed(crate::gpio::Speed::VeryHigh);
|
mck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
}
|
|
||||||
|
|
||||||
let spi = Spi::new_internal(peri, txdma, rxdma, freq, SpiConfig::default());
|
let spi = Spi::new_internal(peri, txdma, rxdma, freq, SpiConfig::default());
|
||||||
|
|
||||||
@ -178,7 +176,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
|
|||||||
let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format);
|
let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format);
|
||||||
|
|
||||||
#[cfg(any(spi_v1, spi_f1))]
|
#[cfg(any(spi_v1, spi_f1))]
|
||||||
unsafe {
|
{
|
||||||
use stm32_metapac::spi::vals::{I2scfg, Odd};
|
use stm32_metapac::spi::vals::{I2scfg, Odd};
|
||||||
|
|
||||||
// 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR register to define the serial clock baud
|
// 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR register to define the serial clock baud
|
||||||
@ -232,10 +230,6 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
|
|||||||
w.set_i2se(true)
|
w.set_i2se(true)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#[cfg(spi_v2)]
|
|
||||||
unsafe {}
|
|
||||||
#[cfg(any(spi_v3, spi_v4))]
|
|
||||||
unsafe {}
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
_peri: spi,
|
_peri: spi,
|
||||||
@ -264,14 +258,12 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
|
|||||||
|
|
||||||
impl<'d, T: Instance, Tx, Rx> Drop for I2S<'d, T, Tx, Rx> {
|
impl<'d, T: Instance, Tx, Rx> Drop for I2S<'d, T, Tx, Rx> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
|
||||||
self.sd.as_ref().map(|x| x.set_as_disconnected());
|
self.sd.as_ref().map(|x| x.set_as_disconnected());
|
||||||
self.ws.as_ref().map(|x| x.set_as_disconnected());
|
self.ws.as_ref().map(|x| x.set_as_disconnected());
|
||||||
self.ck.as_ref().map(|x| x.set_as_disconnected());
|
self.ck.as_ref().map(|x| x.set_as_disconnected());
|
||||||
self.mck.as_ref().map(|x| x.set_as_disconnected());
|
self.mck.as_ref().map(|x| x.set_as_disconnected());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Note, calculation details:
|
// Note, calculation details:
|
||||||
// Fs = i2s_clock / [256 * ((2 * div) + odd)] when master clock is enabled
|
// Fs = i2s_clock / [256 * ((2 * div) + odd)] when master clock is enabled
|
||||||
|
@ -1,7 +1,77 @@
|
|||||||
|
use core::future::poll_fn;
|
||||||
|
use core::task::Poll;
|
||||||
|
|
||||||
|
use atomic_polyfill::{compiler_fence, Ordering};
|
||||||
|
|
||||||
use self::sealed::Instance;
|
use self::sealed::Instance;
|
||||||
|
use crate::interrupt;
|
||||||
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::peripherals::IPCC;
|
use crate::peripherals::IPCC;
|
||||||
use crate::rcc::sealed::RccPeripheral;
|
use crate::rcc::sealed::RccPeripheral;
|
||||||
|
|
||||||
|
/// Interrupt handler.
|
||||||
|
pub struct ReceiveInterruptHandler {}
|
||||||
|
|
||||||
|
impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for ReceiveInterruptHandler {
|
||||||
|
unsafe fn on_interrupt() {
|
||||||
|
let regs = IPCC::regs();
|
||||||
|
|
||||||
|
let channels = [
|
||||||
|
IpccChannel::Channel1,
|
||||||
|
IpccChannel::Channel2,
|
||||||
|
IpccChannel::Channel3,
|
||||||
|
IpccChannel::Channel4,
|
||||||
|
IpccChannel::Channel5,
|
||||||
|
IpccChannel::Channel6,
|
||||||
|
];
|
||||||
|
|
||||||
|
// Status register gives channel occupied status. For rx, use cpu1.
|
||||||
|
let sr = regs.cpu(1).sr().read();
|
||||||
|
regs.cpu(0).mr().modify(|w| {
|
||||||
|
for channel in channels {
|
||||||
|
if sr.chf(channel as usize) {
|
||||||
|
// If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
|
||||||
|
w.set_chom(channel as usize, true);
|
||||||
|
|
||||||
|
// There shouldn't be a race because the channel is masked only if the interrupt has fired
|
||||||
|
IPCC::state().rx_waker_for(channel).wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TransmitInterruptHandler {}
|
||||||
|
|
||||||
|
impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler {
|
||||||
|
unsafe fn on_interrupt() {
|
||||||
|
let regs = IPCC::regs();
|
||||||
|
|
||||||
|
let channels = [
|
||||||
|
IpccChannel::Channel1,
|
||||||
|
IpccChannel::Channel2,
|
||||||
|
IpccChannel::Channel3,
|
||||||
|
IpccChannel::Channel4,
|
||||||
|
IpccChannel::Channel5,
|
||||||
|
IpccChannel::Channel6,
|
||||||
|
];
|
||||||
|
|
||||||
|
// Status register gives channel occupied status. For tx, use cpu0.
|
||||||
|
let sr = regs.cpu(0).sr().read();
|
||||||
|
regs.cpu(0).mr().modify(|w| {
|
||||||
|
for channel in channels {
|
||||||
|
if !sr.chf(channel as usize) {
|
||||||
|
// If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
|
||||||
|
w.set_chfm(channel as usize, true);
|
||||||
|
|
||||||
|
// There shouldn't be a race because the channel is masked only if the interrupt has fired
|
||||||
|
IPCC::state().tx_waker_for(channel).wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Copy, Default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
@ -20,13 +90,6 @@ pub enum IpccChannel {
|
|||||||
Channel6 = 5,
|
Channel6 = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod sealed {
|
|
||||||
pub trait Instance: crate::rcc::RccPeripheral {
|
|
||||||
fn regs() -> crate::pac::ipcc::Ipcc;
|
|
||||||
fn set_cpu2(enabled: bool);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Ipcc;
|
pub struct Ipcc;
|
||||||
|
|
||||||
impl Ipcc {
|
impl Ipcc {
|
||||||
@ -35,124 +98,107 @@ impl Ipcc {
|
|||||||
IPCC::reset();
|
IPCC::reset();
|
||||||
IPCC::set_cpu2(true);
|
IPCC::set_cpu2(true);
|
||||||
|
|
||||||
unsafe { _configure_pwr() };
|
_configure_pwr();
|
||||||
|
|
||||||
let regs = IPCC::regs();
|
let regs = IPCC::regs();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
regs.cpu(0).cr().modify(|w| {
|
regs.cpu(0).cr().modify(|w| {
|
||||||
w.set_rxoie(true);
|
w.set_rxoie(true);
|
||||||
w.set_txfie(true);
|
w.set_txfie(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// enable interrupts
|
||||||
|
crate::interrupt::typelevel::IPCC_C1_RX::unpend();
|
||||||
|
crate::interrupt::typelevel::IPCC_C1_TX::unpend();
|
||||||
|
|
||||||
|
unsafe { crate::interrupt::typelevel::IPCC_C1_RX::enable() };
|
||||||
|
unsafe { crate::interrupt::typelevel::IPCC_C1_TX::enable() };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send data to an IPCC channel. The closure is called to write the data when appropriate.
|
||||||
|
pub async fn send(channel: IpccChannel, f: impl FnOnce()) {
|
||||||
|
let regs = IPCC::regs();
|
||||||
|
|
||||||
|
Self::flush(channel).await;
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
f();
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
trace!("ipcc: ch {}: send data", channel as u8);
|
||||||
|
regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wait for the tx channel to become clear
|
||||||
|
pub async fn flush(channel: IpccChannel) {
|
||||||
|
let regs = IPCC::regs();
|
||||||
|
|
||||||
|
// This is a race, but is nice for debugging
|
||||||
|
if regs.cpu(0).sr().read().chf(channel as usize) {
|
||||||
|
trace!("ipcc: ch {}: wait for tx free", channel as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
poll_fn(|cx| {
|
||||||
|
IPCC::state().tx_waker_for(channel).register(cx.waker());
|
||||||
|
// If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
|
||||||
|
regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, false));
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
if !regs.cpu(0).sr().read().chf(channel as usize) {
|
||||||
|
// If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
|
||||||
|
regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true));
|
||||||
|
|
||||||
|
Poll::Ready(())
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn c1_set_rx_channel(channel: IpccChannel, enabled: bool) {
|
/// Receive data from an IPCC channel. The closure is called to read the data when appropriate.
|
||||||
|
pub async fn receive<R>(channel: IpccChannel, mut f: impl FnMut() -> Option<R>) -> R {
|
||||||
let regs = IPCC::regs();
|
let regs = IPCC::regs();
|
||||||
|
|
||||||
// If bit is set to 1 then interrupt is disabled
|
loop {
|
||||||
unsafe { regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, !enabled)) }
|
// This is a race, but is nice for debugging
|
||||||
|
if !regs.cpu(1).sr().read().chf(channel as usize) {
|
||||||
|
trace!("ipcc: ch {}: wait for rx occupied", channel as u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn c1_get_rx_channel(channel: IpccChannel) -> bool {
|
poll_fn(|cx| {
|
||||||
let regs = IPCC::regs();
|
IPCC::state().rx_waker_for(channel).register(cx.waker());
|
||||||
|
// If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
|
||||||
|
regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, false));
|
||||||
|
|
||||||
// If bit is set to 1 then interrupt is disabled
|
compiler_fence(Ordering::SeqCst);
|
||||||
unsafe { !regs.cpu(0).mr().read().chom(channel as usize) }
|
|
||||||
|
if regs.cpu(1).sr().read().chf(channel as usize) {
|
||||||
|
// If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
|
||||||
|
regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true));
|
||||||
|
|
||||||
|
Poll::Ready(())
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
trace!("ipcc: ch {}: read data", channel as u8);
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
match f() {
|
||||||
|
Some(ret) => return ret,
|
||||||
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
trace!("ipcc: ch {}: clear rx", channel as u8);
|
||||||
pub fn c2_set_rx_channel(channel: IpccChannel, enabled: bool) {
|
compiler_fence(Ordering::SeqCst);
|
||||||
let regs = IPCC::regs();
|
// If the channel is clear and the read function returns none, fetch more data
|
||||||
|
regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true));
|
||||||
// If bit is set to 1 then interrupt is disabled
|
|
||||||
unsafe { regs.cpu(1).mr().modify(|w| w.set_chom(channel as usize, !enabled)) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn c2_get_rx_channel(channel: IpccChannel) -> bool {
|
|
||||||
let regs = IPCC::regs();
|
|
||||||
|
|
||||||
// If bit is set to 1 then interrupt is disabled
|
|
||||||
unsafe { !regs.cpu(1).mr().read().chom(channel as usize) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn c1_set_tx_channel(channel: IpccChannel, enabled: bool) {
|
|
||||||
let regs = IPCC::regs();
|
|
||||||
|
|
||||||
// If bit is set to 1 then interrupt is disabled
|
|
||||||
unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn c1_get_tx_channel(channel: IpccChannel) -> bool {
|
|
||||||
let regs = IPCC::regs();
|
|
||||||
|
|
||||||
// If bit is set to 1 then interrupt is disabled
|
|
||||||
unsafe { !regs.cpu(0).mr().read().chfm(channel as usize) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn c2_set_tx_channel(channel: IpccChannel, enabled: bool) {
|
|
||||||
let regs = IPCC::regs();
|
|
||||||
|
|
||||||
// If bit is set to 1 then interrupt is disabled
|
|
||||||
unsafe { regs.cpu(1).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn c2_get_tx_channel(channel: IpccChannel) -> bool {
|
|
||||||
let regs = IPCC::regs();
|
|
||||||
|
|
||||||
// If bit is set to 1 then interrupt is disabled
|
|
||||||
unsafe { !regs.cpu(1).mr().read().chfm(channel as usize) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// clears IPCC receive channel status for CPU1
|
|
||||||
pub fn c1_clear_flag_channel(channel: IpccChannel) {
|
|
||||||
let regs = IPCC::regs();
|
|
||||||
|
|
||||||
unsafe { regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
/// clears IPCC receive channel status for CPU2
|
|
||||||
pub fn c2_clear_flag_channel(channel: IpccChannel) {
|
|
||||||
let regs = IPCC::regs();
|
|
||||||
|
|
||||||
unsafe { regs.cpu(1).scr().write(|w| w.set_chc(channel as usize, true)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn c1_set_flag_channel(channel: IpccChannel) {
|
|
||||||
let regs = IPCC::regs();
|
|
||||||
|
|
||||||
unsafe { regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn c2_set_flag_channel(channel: IpccChannel) {
|
|
||||||
let regs = IPCC::regs();
|
|
||||||
|
|
||||||
unsafe { regs.cpu(1).scr().write(|w| w.set_chs(channel as usize, true)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn c1_is_active_flag(channel: IpccChannel) -> bool {
|
|
||||||
let regs = IPCC::regs();
|
|
||||||
|
|
||||||
unsafe { regs.cpu(0).sr().read().chf(channel as usize) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn c2_is_active_flag(channel: IpccChannel) -> bool {
|
|
||||||
let regs = IPCC::regs();
|
|
||||||
|
|
||||||
unsafe { regs.cpu(1).sr().read().chf(channel as usize) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_tx_pending(channel: IpccChannel) -> bool {
|
|
||||||
!Self::c1_is_active_flag(channel) && Self::c1_get_tx_channel(channel)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_rx_pending(channel: IpccChannel) -> bool {
|
|
||||||
Self::c2_is_active_flag(channel) && Self::c1_get_rx_channel(channel)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,11 +208,68 @@ impl sealed::Instance for crate::peripherals::IPCC {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_cpu2(enabled: bool) {
|
fn set_cpu2(enabled: bool) {
|
||||||
unsafe { crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled)) }
|
crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state() -> &'static self::sealed::State {
|
||||||
|
static STATE: self::sealed::State = self::sealed::State::new();
|
||||||
|
&STATE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn _configure_pwr() {
|
pub(crate) mod sealed {
|
||||||
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub struct State {
|
||||||
|
rx_wakers: [AtomicWaker; 6],
|
||||||
|
tx_wakers: [AtomicWaker; 6],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
const WAKER: AtomicWaker = AtomicWaker::new();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
rx_wakers: [WAKER; 6],
|
||||||
|
tx_wakers: [WAKER; 6],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker {
|
||||||
|
match channel {
|
||||||
|
IpccChannel::Channel1 => &self.rx_wakers[0],
|
||||||
|
IpccChannel::Channel2 => &self.rx_wakers[1],
|
||||||
|
IpccChannel::Channel3 => &self.rx_wakers[2],
|
||||||
|
IpccChannel::Channel4 => &self.rx_wakers[3],
|
||||||
|
IpccChannel::Channel5 => &self.rx_wakers[4],
|
||||||
|
IpccChannel::Channel6 => &self.rx_wakers[5],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker {
|
||||||
|
match channel {
|
||||||
|
IpccChannel::Channel1 => &self.tx_wakers[0],
|
||||||
|
IpccChannel::Channel2 => &self.tx_wakers[1],
|
||||||
|
IpccChannel::Channel3 => &self.tx_wakers[2],
|
||||||
|
IpccChannel::Channel4 => &self.tx_wakers[3],
|
||||||
|
IpccChannel::Channel5 => &self.tx_wakers[4],
|
||||||
|
IpccChannel::Channel6 => &self.tx_wakers[5],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Instance: crate::rcc::RccPeripheral {
|
||||||
|
fn regs() -> crate::pac::ipcc::Ipcc;
|
||||||
|
fn set_cpu2(enabled: bool);
|
||||||
|
fn state() -> &'static State;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _configure_pwr() {
|
||||||
|
// TODO: move this to RCC
|
||||||
|
|
||||||
let pwr = crate::pac::PWR;
|
let pwr = crate::pac::PWR;
|
||||||
let rcc = crate::pac::RCC;
|
let rcc = crate::pac::RCC;
|
||||||
|
|
||||||
|
@ -146,7 +146,6 @@ impl Default for Config {
|
|||||||
pub fn init(config: Config) -> Peripherals {
|
pub fn init(config: Config) -> Peripherals {
|
||||||
let p = Peripherals::take();
|
let p = Peripherals::take();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
#[cfg(dbgmcu)]
|
#[cfg(dbgmcu)]
|
||||||
if config.enable_debug_during_sleep {
|
if config.enable_debug_during_sleep {
|
||||||
crate::pac::DBGMCU.cr().modify(|cr| {
|
crate::pac::DBGMCU.cr().modify(|cr| {
|
||||||
@ -175,6 +174,7 @@ pub fn init(config: Config) -> Peripherals {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
gpio::init();
|
gpio::init();
|
||||||
dma::init(
|
dma::init(
|
||||||
#[cfg(bdma)]
|
#[cfg(bdma)]
|
||||||
|
@ -21,7 +21,7 @@ macro_rules! complementary_channel_impl {
|
|||||||
impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> {
|
impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> {
|
||||||
pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self {
|
pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self {
|
||||||
into_ref!(pin);
|
into_ref!(pin);
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
pin.set_low();
|
pin.set_low();
|
||||||
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
|
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
|
||||||
#[cfg(gpio_v2)]
|
#[cfg(gpio_v2)]
|
||||||
@ -72,7 +72,6 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
|
|||||||
this.inner.set_frequency(freq);
|
this.inner.set_frequency(freq);
|
||||||
this.inner.start();
|
this.inner.start();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
this.inner.enable_outputs(true);
|
this.inner.enable_outputs(true);
|
||||||
|
|
||||||
this.inner
|
this.inner
|
||||||
@ -83,47 +82,40 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
|
|||||||
.set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
|
.set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
|
||||||
this.inner
|
this.inner
|
||||||
.set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
|
.set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
|
||||||
}
|
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable(&mut self, channel: Channel) {
|
pub fn enable(&mut self, channel: Channel) {
|
||||||
unsafe {
|
|
||||||
self.inner.enable_channel(channel, true);
|
self.inner.enable_channel(channel, true);
|
||||||
self.inner.enable_complementary_channel(channel, true);
|
self.inner.enable_complementary_channel(channel, true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn disable(&mut self, channel: Channel) {
|
pub fn disable(&mut self, channel: Channel) {
|
||||||
unsafe {
|
|
||||||
self.inner.enable_complementary_channel(channel, false);
|
self.inner.enable_complementary_channel(channel, false);
|
||||||
self.inner.enable_channel(channel, false);
|
self.inner.enable_channel(channel, false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_freq(&mut self, freq: Hertz) {
|
pub fn set_freq(&mut self, freq: Hertz) {
|
||||||
self.inner.set_frequency(freq);
|
self.inner.set_frequency(freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_max_duty(&self) -> u16 {
|
pub fn get_max_duty(&self) -> u16 {
|
||||||
unsafe { self.inner.get_max_compare_value() }
|
self.inner.get_max_compare_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_duty(&mut self, channel: Channel, duty: u16) {
|
pub fn set_duty(&mut self, channel: Channel, duty: u16) {
|
||||||
assert!(duty < self.get_max_duty());
|
assert!(duty < self.get_max_duty());
|
||||||
unsafe { self.inner.set_compare_value(channel, duty) }
|
self.inner.set_compare_value(channel, duty)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the dead time as a proportion of max_duty
|
/// Set the dead time as a proportion of max_duty
|
||||||
pub fn set_dead_time(&mut self, value: u16) {
|
pub fn set_dead_time(&mut self, value: u16) {
|
||||||
let (ckd, value) = compute_dead_time_value(value);
|
let (ckd, value) = compute_dead_time_value(value);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
self.inner.set_dead_time_clock_division(ckd);
|
self.inner.set_dead_time_clock_division(ckd);
|
||||||
self.inner.set_dead_time_value(value);
|
self.inner.set_dead_time_value(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_dead_time_value(value: u16) -> (Ckd, u8) {
|
fn compute_dead_time_value(value: u16) -> (Ckd, u8) {
|
||||||
/*
|
/*
|
||||||
|
@ -59,33 +59,33 @@ pub(crate) mod sealed {
|
|||||||
|
|
||||||
pub trait CaptureCompare16bitInstance: crate::timer::sealed::GeneralPurpose16bitInstance {
|
pub trait CaptureCompare16bitInstance: crate::timer::sealed::GeneralPurpose16bitInstance {
|
||||||
/// Global output enable. Does not do anything on non-advanced timers.
|
/// Global output enable. Does not do anything on non-advanced timers.
|
||||||
unsafe fn enable_outputs(&mut self, enable: bool);
|
fn enable_outputs(&mut self, enable: bool);
|
||||||
|
|
||||||
unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
|
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
|
||||||
|
|
||||||
unsafe fn enable_channel(&mut self, channel: Channel, enable: bool);
|
fn enable_channel(&mut self, channel: Channel, enable: bool);
|
||||||
|
|
||||||
unsafe fn set_compare_value(&mut self, channel: Channel, value: u16);
|
fn set_compare_value(&mut self, channel: Channel, value: u16);
|
||||||
|
|
||||||
unsafe fn get_max_compare_value(&self) -> u16;
|
fn get_max_compare_value(&self) -> u16;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance {
|
pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance {
|
||||||
unsafe fn set_dead_time_clock_division(&mut self, value: Ckd);
|
fn set_dead_time_clock_division(&mut self, value: Ckd);
|
||||||
|
|
||||||
unsafe fn set_dead_time_value(&mut self, value: u8);
|
fn set_dead_time_value(&mut self, value: u8);
|
||||||
|
|
||||||
unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool);
|
fn enable_complementary_channel(&mut self, channel: Channel, enable: bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance {
|
pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance {
|
||||||
unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
|
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
|
||||||
|
|
||||||
unsafe fn enable_channel(&mut self, channel: Channel, enable: bool);
|
fn enable_channel(&mut self, channel: Channel, enable: bool);
|
||||||
|
|
||||||
unsafe fn set_compare_value(&mut self, channel: Channel, value: u32);
|
fn set_compare_value(&mut self, channel: Channel, value: u32);
|
||||||
|
|
||||||
unsafe fn get_max_compare_value(&self) -> u32;
|
fn get_max_compare_value(&self) -> u32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,9 +108,9 @@ pub trait CaptureCompare32bitInstance:
|
|||||||
macro_rules! impl_compare_capable_16bit {
|
macro_rules! impl_compare_capable_16bit {
|
||||||
($inst:ident) => {
|
($inst:ident) => {
|
||||||
impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
|
impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||||
unsafe fn enable_outputs(&mut self, _enable: bool) {}
|
fn enable_outputs(&mut self, _enable: bool) {}
|
||||||
|
|
||||||
unsafe fn set_output_compare_mode(&mut self, channel: crate::pwm::Channel, mode: OutputCompareMode) {
|
fn set_output_compare_mode(&mut self, channel: crate::pwm::Channel, mode: OutputCompareMode) {
|
||||||
use crate::timer::sealed::GeneralPurpose16bitInstance;
|
use crate::timer::sealed::GeneralPurpose16bitInstance;
|
||||||
let r = Self::regs_gp16();
|
let r = Self::regs_gp16();
|
||||||
let raw_channel: usize = channel.raw();
|
let raw_channel: usize = channel.raw();
|
||||||
@ -118,19 +118,19 @@ macro_rules! impl_compare_capable_16bit {
|
|||||||
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
||||||
use crate::timer::sealed::GeneralPurpose16bitInstance;
|
use crate::timer::sealed::GeneralPurpose16bitInstance;
|
||||||
Self::regs_gp16()
|
Self::regs_gp16()
|
||||||
.ccer()
|
.ccer()
|
||||||
.modify(|w| w.set_cce(channel.raw(), enable));
|
.modify(|w| w.set_cce(channel.raw(), enable));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_compare_value(&mut self, channel: Channel, value: u16) {
|
fn set_compare_value(&mut self, channel: Channel, value: u16) {
|
||||||
use crate::timer::sealed::GeneralPurpose16bitInstance;
|
use crate::timer::sealed::GeneralPurpose16bitInstance;
|
||||||
Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value));
|
Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn get_max_compare_value(&self) -> u16 {
|
fn get_max_compare_value(&self) -> u16 {
|
||||||
use crate::timer::sealed::GeneralPurpose16bitInstance;
|
use crate::timer::sealed::GeneralPurpose16bitInstance;
|
||||||
Self::regs_gp16().arr().read().arr()
|
Self::regs_gp16().arr().read().arr()
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ foreach_interrupt! {
|
|||||||
($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
|
($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
|
||||||
impl_compare_capable_16bit!($inst);
|
impl_compare_capable_16bit!($inst);
|
||||||
impl crate::pwm::sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {
|
impl crate::pwm::sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {
|
||||||
unsafe fn set_output_compare_mode(
|
fn set_output_compare_mode(
|
||||||
&mut self,
|
&mut self,
|
||||||
channel: crate::pwm::Channel,
|
channel: crate::pwm::Channel,
|
||||||
mode: OutputCompareMode,
|
mode: OutputCompareMode,
|
||||||
@ -160,17 +160,17 @@ foreach_interrupt! {
|
|||||||
Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
||||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||||
Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable));
|
Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_compare_value(&mut self, channel: Channel, value: u32) {
|
fn set_compare_value(&mut self, channel: Channel, value: u32) {
|
||||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||||
Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value));
|
Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn get_max_compare_value(&self) -> u32 {
|
fn get_max_compare_value(&self) -> u32 {
|
||||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||||
Self::regs_gp32().arr().read().arr() as u32
|
Self::regs_gp32().arr().read().arr() as u32
|
||||||
}
|
}
|
||||||
@ -185,13 +185,13 @@ foreach_interrupt! {
|
|||||||
|
|
||||||
($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
|
($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
|
||||||
impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
|
impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||||
unsafe fn enable_outputs(&mut self, enable: bool) {
|
fn enable_outputs(&mut self, enable: bool) {
|
||||||
use crate::timer::sealed::AdvancedControlInstance;
|
use crate::timer::sealed::AdvancedControlInstance;
|
||||||
let r = Self::regs_advanced();
|
let r = Self::regs_advanced();
|
||||||
r.bdtr().modify(|w| w.set_moe(enable));
|
r.bdtr().modify(|w| w.set_moe(enable));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_output_compare_mode(
|
fn set_output_compare_mode(
|
||||||
&mut self,
|
&mut self,
|
||||||
channel: crate::pwm::Channel,
|
channel: crate::pwm::Channel,
|
||||||
mode: OutputCompareMode,
|
mode: OutputCompareMode,
|
||||||
@ -203,21 +203,21 @@ foreach_interrupt! {
|
|||||||
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
||||||
use crate::timer::sealed::AdvancedControlInstance;
|
use crate::timer::sealed::AdvancedControlInstance;
|
||||||
Self::regs_advanced()
|
Self::regs_advanced()
|
||||||
.ccer()
|
.ccer()
|
||||||
.modify(|w| w.set_cce(channel.raw(), enable));
|
.modify(|w| w.set_cce(channel.raw(), enable));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_compare_value(&mut self, channel: Channel, value: u16) {
|
fn set_compare_value(&mut self, channel: Channel, value: u16) {
|
||||||
use crate::timer::sealed::AdvancedControlInstance;
|
use crate::timer::sealed::AdvancedControlInstance;
|
||||||
Self::regs_advanced()
|
Self::regs_advanced()
|
||||||
.ccr(channel.raw())
|
.ccr(channel.raw())
|
||||||
.modify(|w| w.set_ccr(value));
|
.modify(|w| w.set_ccr(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn get_max_compare_value(&self) -> u16 {
|
fn get_max_compare_value(&self) -> u16 {
|
||||||
use crate::timer::sealed::AdvancedControlInstance;
|
use crate::timer::sealed::AdvancedControlInstance;
|
||||||
Self::regs_advanced().arr().read().arr()
|
Self::regs_advanced().arr().read().arr()
|
||||||
}
|
}
|
||||||
@ -228,17 +228,17 @@ foreach_interrupt! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {
|
impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||||
unsafe fn set_dead_time_clock_division(&mut self, value: Ckd) {
|
fn set_dead_time_clock_division(&mut self, value: Ckd) {
|
||||||
use crate::timer::sealed::AdvancedControlInstance;
|
use crate::timer::sealed::AdvancedControlInstance;
|
||||||
Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
|
Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_dead_time_value(&mut self, value: u8) {
|
fn set_dead_time_value(&mut self, value: u8) {
|
||||||
use crate::timer::sealed::AdvancedControlInstance;
|
use crate::timer::sealed::AdvancedControlInstance;
|
||||||
Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
|
Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
|
fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
|
||||||
use crate::timer::sealed::AdvancedControlInstance;
|
use crate::timer::sealed::AdvancedControlInstance;
|
||||||
Self::regs_advanced()
|
Self::regs_advanced()
|
||||||
.ccer()
|
.ccer()
|
||||||
|
@ -24,7 +24,7 @@ macro_rules! channel_impl {
|
|||||||
impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> {
|
impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> {
|
||||||
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
|
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
|
||||||
into_ref!(pin);
|
into_ref!(pin);
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
pin.set_low();
|
pin.set_low();
|
||||||
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
|
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
|
||||||
#[cfg(gpio_v2)]
|
#[cfg(gpio_v2)]
|
||||||
@ -71,7 +71,6 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
|||||||
this.inner.set_frequency(freq);
|
this.inner.set_frequency(freq);
|
||||||
this.inner.start();
|
this.inner.start();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
this.inner.enable_outputs(true);
|
this.inner.enable_outputs(true);
|
||||||
|
|
||||||
this.inner
|
this.inner
|
||||||
@ -82,32 +81,27 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
|||||||
.set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
|
.set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
|
||||||
this.inner
|
this.inner
|
||||||
.set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
|
.set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
|
||||||
}
|
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable(&mut self, channel: Channel) {
|
pub fn enable(&mut self, channel: Channel) {
|
||||||
unsafe {
|
|
||||||
self.inner.enable_channel(channel, true);
|
self.inner.enable_channel(channel, true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn disable(&mut self, channel: Channel) {
|
pub fn disable(&mut self, channel: Channel) {
|
||||||
unsafe {
|
|
||||||
self.inner.enable_channel(channel, false);
|
self.inner.enable_channel(channel, false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_freq(&mut self, freq: Hertz) {
|
pub fn set_freq(&mut self, freq: Hertz) {
|
||||||
self.inner.set_frequency(freq);
|
self.inner.set_frequency(freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_max_duty(&self) -> u16 {
|
pub fn get_max_duty(&self) -> u16 {
|
||||||
unsafe { self.inner.get_max_compare_value() }
|
self.inner.get_max_compare_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_duty(&mut self, channel: Channel, duty: u16) {
|
pub fn set_duty(&mut self, channel: Channel, duty: u16) {
|
||||||
assert!(duty < self.get_max_duty());
|
assert!(duty < self.get_max_duty());
|
||||||
unsafe { self.inner.set_compare_value(channel, duty) }
|
self.inner.set_compare_value(channel, duty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,6 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(peri, d0, d1, d2, d3, sck, nss);
|
into_ref!(peri, d0, d1, d2, d3, sck, nss);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
|
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
|
||||||
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
nss.set_as_af(nss.af_num(), AFType::OutputPushPull);
|
nss.set_as_af(nss.af_num(), AFType::OutputPushPull);
|
||||||
@ -109,7 +108,6 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
d2.set_speed(crate::gpio::Speed::VeryHigh);
|
d2.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
d3.set_as_af(d3.af_num(), AFType::OutputPushPull);
|
d3.set_as_af(d3.af_num(), AFType::OutputPushPull);
|
||||||
d3.set_speed(crate::gpio::Speed::VeryHigh);
|
d3.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
}
|
|
||||||
|
|
||||||
Self::new_inner(
|
Self::new_inner(
|
||||||
peri,
|
peri,
|
||||||
@ -138,7 +136,6 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
into_ref!(peri, dma);
|
into_ref!(peri, dma);
|
||||||
|
|
||||||
T::enable();
|
T::enable();
|
||||||
unsafe {
|
|
||||||
T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
|
T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
|
||||||
|
|
||||||
while T::REGS.sr().read().busy() {}
|
while T::REGS.sr().read().busy() {}
|
||||||
@ -152,7 +149,6 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
w.set_csht(config.cs_high_time.into());
|
w.set_csht(config.cs_high_time.into());
|
||||||
w.set_ckmode(false);
|
w.set_ckmode(false);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
_peri: peri,
|
_peri: peri,
|
||||||
@ -168,17 +164,14 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn command(&mut self, transaction: TransferConfig) {
|
pub fn command(&mut self, transaction: TransferConfig) {
|
||||||
unsafe {
|
|
||||||
T::REGS.cr().modify(|v| v.set_dmaen(false));
|
T::REGS.cr().modify(|v| v.set_dmaen(false));
|
||||||
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
||||||
|
|
||||||
while !T::REGS.sr().read().tcf() {}
|
while !T::REGS.sr().read().tcf() {}
|
||||||
T::REGS.fcr().modify(|v| v.set_ctcf(true));
|
T::REGS.fcr().modify(|v| v.set_ctcf(true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
|
pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
|
||||||
unsafe {
|
|
||||||
T::REGS.cr().modify(|v| v.set_dmaen(false));
|
T::REGS.cr().modify(|v| v.set_dmaen(false));
|
||||||
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
||||||
|
|
||||||
@ -193,17 +186,15 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
|
|
||||||
for idx in 0..len {
|
for idx in 0..len {
|
||||||
while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
|
while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
|
||||||
buf[idx] = *(T::REGS.dr().ptr() as *mut u8);
|
buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while !T::REGS.sr().read().tcf() {}
|
while !T::REGS.sr().read().tcf() {}
|
||||||
T::REGS.fcr().modify(|v| v.set_ctcf(true));
|
T::REGS.fcr().modify(|v| v.set_ctcf(true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
|
pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
|
||||||
unsafe {
|
|
||||||
T::REGS.cr().modify(|v| v.set_dmaen(false));
|
T::REGS.cr().modify(|v| v.set_dmaen(false));
|
||||||
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
||||||
|
|
||||||
@ -214,20 +205,18 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
|
|
||||||
for idx in 0..len {
|
for idx in 0..len {
|
||||||
while !T::REGS.sr().read().ftf() {}
|
while !T::REGS.sr().read().ftf() {}
|
||||||
*(T::REGS.dr().ptr() as *mut u8) = buf[idx];
|
unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while !T::REGS.sr().read().tcf() {}
|
while !T::REGS.sr().read().tcf() {}
|
||||||
T::REGS.fcr().modify(|v| v.set_ctcf(true));
|
T::REGS.fcr().modify(|v| v.set_ctcf(true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
|
pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
|
||||||
where
|
where
|
||||||
Dma: QuadDma<T>,
|
Dma: QuadDma<T>,
|
||||||
{
|
{
|
||||||
unsafe {
|
|
||||||
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
||||||
|
|
||||||
T::REGS.ccr().modify(|v| {
|
T::REGS.ccr().modify(|v| {
|
||||||
@ -239,25 +228,25 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let request = self.dma.request();
|
let request = self.dma.request();
|
||||||
let transfer = Transfer::new_read(
|
let transfer = unsafe {
|
||||||
|
Transfer::new_read(
|
||||||
&mut self.dma,
|
&mut self.dma,
|
||||||
request,
|
request,
|
||||||
T::REGS.dr().ptr() as *mut u8,
|
T::REGS.dr().as_ptr() as *mut u8,
|
||||||
buf,
|
buf,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
)
|
||||||
|
};
|
||||||
|
|
||||||
T::REGS.cr().modify(|v| v.set_dmaen(true));
|
T::REGS.cr().modify(|v| v.set_dmaen(true));
|
||||||
|
|
||||||
transfer.blocking_wait();
|
transfer.blocking_wait();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
|
pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
|
||||||
where
|
where
|
||||||
Dma: QuadDma<T>,
|
Dma: QuadDma<T>,
|
||||||
{
|
{
|
||||||
unsafe {
|
|
||||||
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
||||||
|
|
||||||
T::REGS.ccr().modify(|v| {
|
T::REGS.ccr().modify(|v| {
|
||||||
@ -265,22 +254,22 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let request = self.dma.request();
|
let request = self.dma.request();
|
||||||
let transfer = Transfer::new_write(
|
let transfer = unsafe {
|
||||||
|
Transfer::new_write(
|
||||||
&mut self.dma,
|
&mut self.dma,
|
||||||
request,
|
request,
|
||||||
buf,
|
buf,
|
||||||
T::REGS.dr().ptr() as *mut u8,
|
T::REGS.dr().as_ptr() as *mut u8,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
)
|
||||||
|
};
|
||||||
|
|
||||||
T::REGS.cr().modify(|v| v.set_dmaen(true));
|
T::REGS.cr().modify(|v| v.set_dmaen(true));
|
||||||
|
|
||||||
transfer.blocking_wait();
|
transfer.blocking_wait();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) {
|
fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) {
|
||||||
unsafe {
|
|
||||||
T::REGS.fcr().modify(|v| {
|
T::REGS.fcr().modify(|v| {
|
||||||
v.set_csmf(true);
|
v.set_csmf(true);
|
||||||
v.set_ctcf(true);
|
v.set_ctcf(true);
|
||||||
@ -312,7 +301,6 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -36,18 +36,18 @@ pub struct Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(stm32f410)]
|
#[cfg(stm32f410)]
|
||||||
unsafe fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
|
fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not currently implemented, but will be in the future
|
// Not currently implemented, but will be in the future
|
||||||
#[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))]
|
#[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))]
|
||||||
unsafe fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
|
fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
|
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
|
||||||
unsafe fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
|
fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
|
||||||
let min_div = 2;
|
let min_div = 2;
|
||||||
let max_div = 7;
|
let max_div = 7;
|
||||||
let target = match plli2s {
|
let target = match plli2s {
|
||||||
@ -82,13 +82,7 @@ unsafe fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
|
|||||||
Some(output)
|
Some(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn setup_pll(
|
fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Option<u32>, pll48clk: bool) -> PllResults {
|
||||||
pllsrcclk: u32,
|
|
||||||
use_hse: bool,
|
|
||||||
pllsysclk: Option<u32>,
|
|
||||||
plli2s: Option<u32>,
|
|
||||||
pll48clk: bool,
|
|
||||||
) -> PllResults {
|
|
||||||
use crate::pac::rcc::vals::{Pllp, Pllsrc};
|
use crate::pac::rcc::vals::{Pllp, Pllsrc};
|
||||||
|
|
||||||
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
|
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
|
||||||
@ -320,7 +314,7 @@ impl<'d, T: McoInstance> Mco<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn flash_setup(sysclk: u32) {
|
fn flash_setup(sysclk: u32) {
|
||||||
use crate::pac::flash::vals::Latency;
|
use crate::pac::flash::vals::Latency;
|
||||||
|
|
||||||
// Be conservative with voltage ranges
|
// Be conservative with voltage ranges
|
||||||
|
@ -25,7 +25,7 @@ pub struct Config {
|
|||||||
pub pll48: bool,
|
pub pll48: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults {
|
fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults {
|
||||||
use crate::pac::rcc::vals::{Pllp, Pllsrc};
|
use crate::pac::rcc::vals::{Pllp, Pllsrc};
|
||||||
|
|
||||||
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
|
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
|
||||||
@ -97,7 +97,7 @@ unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn flash_setup(sysclk: u32) {
|
fn flash_setup(sysclk: u32) {
|
||||||
use crate::pac::flash::vals::Latency;
|
use crate::pac::flash::vals::Latency;
|
||||||
|
|
||||||
// Be conservative with voltage ranges
|
// Be conservative with voltage ranges
|
||||||
|
@ -245,7 +245,7 @@ impl Default for Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PllConfig {
|
impl PllConfig {
|
||||||
pub(crate) unsafe fn init(self) -> u32 {
|
pub(crate) fn init(self) -> u32 {
|
||||||
assert!(self.n >= 8 && self.n <= 86);
|
assert!(self.n >= 8 && self.n <= 86);
|
||||||
let (src, input_freq) = match self.source {
|
let (src, input_freq) = match self.source {
|
||||||
PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ.0),
|
PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ.0),
|
||||||
|
@ -462,7 +462,7 @@ struct PllOutput {
|
|||||||
r: Option<Hertz>,
|
r: Option<Hertz>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
|
fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
|
||||||
let Some(config) = config else {
|
let Some(config) = config else {
|
||||||
// Stop PLL
|
// Stop PLL
|
||||||
RCC.cr().modify(|w| w.set_pllon(num, false));
|
RCC.cr().modify(|w| w.set_pllon(num, false));
|
||||||
@ -595,12 +595,9 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) {
|
|||||||
|
|
||||||
defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
|
defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
|
||||||
|
|
||||||
// NOTE(unsafe) Atomic write
|
|
||||||
unsafe {
|
|
||||||
FLASH.acr().write(|w| {
|
FLASH.acr().write(|w| {
|
||||||
w.set_wrhighfreq(wrhighfreq);
|
w.set_wrhighfreq(wrhighfreq);
|
||||||
w.set_latency(latency);
|
w.set_latency(latency);
|
||||||
});
|
});
|
||||||
while FLASH.acr().read().latency() != latency {}
|
while FLASH.acr().read().latency() != latency {}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -253,15 +253,12 @@ fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE(unsafe) Atomic write
|
|
||||||
unsafe {
|
|
||||||
FLASH.acr().write(|w| {
|
FLASH.acr().write(|w| {
|
||||||
w.set_wrhighfreq(progr_delay);
|
w.set_wrhighfreq(progr_delay);
|
||||||
w.set_latency(wait_states)
|
w.set_latency(wait_states)
|
||||||
});
|
});
|
||||||
while FLASH.acr().read().latency() != wait_states {}
|
while FLASH.acr().read().latency() != wait_states {}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub enum McoClock {
|
pub enum McoClock {
|
||||||
Disabled,
|
Disabled,
|
||||||
@ -474,7 +471,6 @@ pub(crate) unsafe fn init(mut config: Config) {
|
|||||||
// Configure traceclk from PLL if needed
|
// Configure traceclk from PLL if needed
|
||||||
traceclk_setup(&mut config, sys_use_pll1_p);
|
traceclk_setup(&mut config, sys_use_pll1_p);
|
||||||
|
|
||||||
// NOTE(unsafe) We have exclusive access to the RCC
|
|
||||||
let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0);
|
let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0);
|
||||||
let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1);
|
let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1);
|
||||||
let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2);
|
let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2);
|
||||||
@ -756,7 +752,7 @@ mod pll {
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// Must have exclusive access to the RCC register block
|
/// Must have exclusive access to the RCC register block
|
||||||
unsafe fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
|
fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
|
||||||
use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
|
use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
|
||||||
|
|
||||||
let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
|
let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
|
||||||
@ -785,11 +781,7 @@ mod pll {
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// Must have exclusive access to the RCC register block
|
/// Must have exclusive access to the RCC register block
|
||||||
pub(super) unsafe fn pll_setup(
|
pub(super) fn pll_setup(pll_src: u32, config: &PllConfig, plln: usize) -> (Option<u32>, Option<u32>, Option<u32>) {
|
||||||
pll_src: u32,
|
|
||||||
config: &PllConfig,
|
|
||||||
plln: usize,
|
|
||||||
) -> (Option<u32>, Option<u32>, Option<u32>) {
|
|
||||||
use crate::pac::rcc::vals::Divp;
|
use crate::pac::rcc::vals::Divp;
|
||||||
|
|
||||||
match config.p_ck {
|
match config.p_ck {
|
||||||
|
@ -34,10 +34,9 @@ impl<'d, T: Instance> Rng<'d, T> {
|
|||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
// rng_v2 locks up on seed error, needs reset
|
// rng_v2 locks up on seed error, needs reset
|
||||||
#[cfg(rng_v2)]
|
#[cfg(rng_v2)]
|
||||||
if unsafe { T::regs().sr().read().seis() } {
|
if T::regs().sr().read().seis() {
|
||||||
T::reset();
|
T::reset();
|
||||||
}
|
}
|
||||||
unsafe {
|
|
||||||
T::regs().cr().modify(|reg| {
|
T::regs().cr().modify(|reg| {
|
||||||
reg.set_rngen(true);
|
reg.set_rngen(true);
|
||||||
reg.set_ie(true);
|
reg.set_ie(true);
|
||||||
@ -46,28 +45,23 @@ impl<'d, T: Instance> Rng<'d, T> {
|
|||||||
reg.set_seis(false);
|
reg.set_seis(false);
|
||||||
reg.set_ceis(false);
|
reg.set_ceis(false);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
// Reference manual says to discard the first.
|
// Reference manual says to discard the first.
|
||||||
let _ = self.next_u32();
|
let _ = self.next_u32();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
||||||
unsafe {
|
|
||||||
T::regs().cr().modify(|reg| {
|
T::regs().cr().modify(|reg| {
|
||||||
reg.set_rngen(true);
|
reg.set_rngen(true);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
|
|
||||||
for chunk in dest.chunks_mut(4) {
|
for chunk in dest.chunks_mut(4) {
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
RNG_WAKER.register(cx.waker());
|
RNG_WAKER.register(cx.waker());
|
||||||
unsafe {
|
|
||||||
T::regs().cr().modify(|reg| {
|
T::regs().cr().modify(|reg| {
|
||||||
reg.set_ie(true);
|
reg.set_ie(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
let bits = unsafe { T::regs().sr().read() };
|
let bits = T::regs().sr().read();
|
||||||
|
|
||||||
if bits.drdy() {
|
if bits.drdy() {
|
||||||
Poll::Ready(Ok(()))
|
Poll::Ready(Ok(()))
|
||||||
@ -82,7 +76,7 @@ impl<'d, T: Instance> Rng<'d, T> {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
let random_bytes = unsafe { T::regs().dr().read() }.to_be_bytes();
|
let random_bytes = T::regs().dr().read().to_be_bytes();
|
||||||
for (dest, src) in chunk.iter_mut().zip(random_bytes.iter()) {
|
for (dest, src) in chunk.iter_mut().zip(random_bytes.iter()) {
|
||||||
*dest = *src
|
*dest = *src
|
||||||
}
|
}
|
||||||
@ -95,11 +89,11 @@ impl<'d, T: Instance> Rng<'d, T> {
|
|||||||
impl<'d, T: Instance> RngCore for Rng<'d, T> {
|
impl<'d, T: Instance> RngCore for Rng<'d, T> {
|
||||||
fn next_u32(&mut self) -> u32 {
|
fn next_u32(&mut self) -> u32 {
|
||||||
loop {
|
loop {
|
||||||
let sr = unsafe { T::regs().sr().read() };
|
let sr = T::regs().sr().read();
|
||||||
if sr.seis() | sr.ceis() {
|
if sr.seis() | sr.ceis() {
|
||||||
self.reset();
|
self.reset();
|
||||||
} else if sr.drdy() {
|
} else if sr.drdy() {
|
||||||
return unsafe { T::regs().dr().read() };
|
return T::regs().dr().read();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,6 @@ pub(super) fn write_date_time(rtc: &Rtc, t: DateTime) {
|
|||||||
let yr_offset = (yr - 1970_u16) as u8;
|
let yr_offset = (yr - 1970_u16) as u8;
|
||||||
let (yt, yu) = byte_to_bcd2(yr_offset);
|
let (yt, yu) = byte_to_bcd2(yr_offset);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
use crate::pac::rtc::vals::Ampm;
|
use crate::pac::rtc::vals::Ampm;
|
||||||
|
|
||||||
rtc.tr().write(|w| {
|
rtc.tr().write(|w| {
|
||||||
@ -177,7 +176,6 @@ pub(super) fn write_date_time(rtc: &Rtc, t: DateTime) {
|
|||||||
w.set_wdu(day_of_week_to_u8(t.day_of_week));
|
w.set_wdu(day_of_week_to_u8(t.day_of_week));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn datetime(
|
pub(super) fn datetime(
|
||||||
year: u16,
|
year: u16,
|
||||||
|
@ -113,7 +113,7 @@ impl Default for RtcCalibrationCyclePeriod {
|
|||||||
|
|
||||||
impl<'d, T: Instance> Rtc<'d, T> {
|
impl<'d, T: Instance> Rtc<'d, T> {
|
||||||
pub fn new(_rtc: impl Peripheral<P = T> + 'd, rtc_config: RtcConfig) -> Self {
|
pub fn new(_rtc: impl Peripheral<P = T> + 'd, rtc_config: RtcConfig) -> Self {
|
||||||
unsafe { T::enable_peripheral_clk() };
|
T::enable_peripheral_clk();
|
||||||
|
|
||||||
let mut rtc_struct = Self {
|
let mut rtc_struct = Self {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
@ -144,7 +144,6 @@ impl<'d, T: Instance> Rtc<'d, T> {
|
|||||||
/// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
|
/// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
|
||||||
pub fn now(&self) -> Result<DateTime, RtcError> {
|
pub fn now(&self) -> Result<DateTime, RtcError> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
unsafe {
|
|
||||||
let tr = r.tr().read();
|
let tr = r.tr().read();
|
||||||
let second = bcd2_to_byte((tr.st(), tr.su()));
|
let second = bcd2_to_byte((tr.st(), tr.su()));
|
||||||
let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
|
let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
|
||||||
@ -160,18 +159,17 @@ impl<'d, T: Instance> Rtc<'d, T> {
|
|||||||
|
|
||||||
self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
|
self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if daylight savings time is active.
|
/// Check if daylight savings time is active.
|
||||||
pub fn get_daylight_savings(&self) -> bool {
|
pub fn get_daylight_savings(&self) -> bool {
|
||||||
let cr = unsafe { T::regs().cr().read() };
|
let cr = T::regs().cr().read();
|
||||||
cr.bkp()
|
cr.bkp()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enable/disable daylight savings time.
|
/// Enable/disable daylight savings time.
|
||||||
pub fn set_daylight_savings(&mut self, daylight_savings: bool) {
|
pub fn set_daylight_savings(&mut self, daylight_savings: bool) {
|
||||||
self.write(true, |rtc| {
|
self.write(true, |rtc| {
|
||||||
unsafe { rtc.cr().modify(|w| w.set_bkp(daylight_savings)) };
|
rtc.cr().modify(|w| w.set_bkp(daylight_savings));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +226,7 @@ pub(crate) mod sealed {
|
|||||||
crate::pac::RTC
|
crate::pac::RTC
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enable_peripheral_clk() {}
|
fn enable_peripheral_clk() {}
|
||||||
|
|
||||||
/// Read content of the backup register.
|
/// Read content of the backup register.
|
||||||
///
|
///
|
||||||
|
@ -8,7 +8,6 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
/// It this changes the RTC clock source the time will be reset
|
/// It this changes the RTC clock source the time will be reset
|
||||||
pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) {
|
pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) {
|
||||||
// Unlock the backup domain
|
// Unlock the backup domain
|
||||||
unsafe {
|
|
||||||
let clock_config = rtc_config.clock_config as u8;
|
let clock_config = rtc_config.clock_config as u8;
|
||||||
|
|
||||||
#[cfg(not(rtc_v2wb))]
|
#[cfg(not(rtc_v2wb))]
|
||||||
@ -73,9 +72,8 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
w.set_lsebyp(reg.lsebyp());
|
w.set_lsebyp(reg.lsebyp());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
self.write(true, |rtc| unsafe {
|
self.write(true, |rtc| {
|
||||||
rtc.cr().modify(|w| {
|
rtc.cr().modify(|w| {
|
||||||
#[cfg(rtc_v2f2)]
|
#[cfg(rtc_v2f2)]
|
||||||
w.set_fmt(false);
|
w.set_fmt(false);
|
||||||
@ -117,7 +115,6 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
clock_drift = clock_drift / RTC_CALR_RESOLUTION_PPM;
|
clock_drift = clock_drift / RTC_CALR_RESOLUTION_PPM;
|
||||||
|
|
||||||
self.write(false, |rtc| {
|
self.write(false, |rtc| {
|
||||||
unsafe {
|
|
||||||
rtc.calr().write(|w| {
|
rtc.calr().write(|w| {
|
||||||
match period {
|
match period {
|
||||||
super::RtcCalibrationCyclePeriod::Seconds8 => {
|
super::RtcCalibrationCyclePeriod::Seconds8 => {
|
||||||
@ -157,7 +154,6 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
w.set_calm((clock_drift * -1.0) as u16);
|
w.set_calm((clock_drift * -1.0) as u16);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +164,6 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
// Disable write protection.
|
// Disable write protection.
|
||||||
// This is safe, as we're only writin the correct and expected values.
|
// This is safe, as we're only writin the correct and expected values.
|
||||||
unsafe {
|
|
||||||
r.wpr().write(|w| w.set_key(0xca));
|
r.wpr().write(|w| w.set_key(0xca));
|
||||||
r.wpr().write(|w| w.set_key(0x53));
|
r.wpr().write(|w| w.set_key(0x53));
|
||||||
|
|
||||||
@ -180,11 +175,9 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
// ~2 RTCCLK cycles
|
// ~2 RTCCLK cycles
|
||||||
while !r.isr().read().initf() {}
|
while !r.isr().read().initf() {}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let result = f(&r);
|
let result = f(&r);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
if init_mode {
|
if init_mode {
|
||||||
r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
|
r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
|
||||||
}
|
}
|
||||||
@ -192,7 +185,6 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
// Re-enable write protection.
|
// Re-enable write protection.
|
||||||
// This is safe, as the field accepts the full range of 8-bit values.
|
// This is safe, as the field accepts the full range of 8-bit values.
|
||||||
r.wpr().write(|w| w.set_key(0xff));
|
r.wpr().write(|w| w.set_key(0xff));
|
||||||
}
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,7 +192,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
impl sealed::Instance for crate::peripherals::RTC {
|
impl sealed::Instance for crate::peripherals::RTC {
|
||||||
const BACKUP_REGISTER_COUNT: usize = 20;
|
const BACKUP_REGISTER_COUNT: usize = 20;
|
||||||
|
|
||||||
unsafe fn enable_peripheral_clk() {
|
fn enable_peripheral_clk() {
|
||||||
#[cfg(any(rtc_v2l4, rtc_v2wb))]
|
#[cfg(any(rtc_v2l4, rtc_v2wb))]
|
||||||
{
|
{
|
||||||
// enable peripheral clock for communication
|
// enable peripheral clock for communication
|
||||||
@ -213,7 +205,7 @@ impl sealed::Instance for crate::peripherals::RTC {
|
|||||||
|
|
||||||
fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> {
|
fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> {
|
||||||
if register < Self::BACKUP_REGISTER_COUNT {
|
if register < Self::BACKUP_REGISTER_COUNT {
|
||||||
Some(unsafe { rtc.bkpr(register).read().bkp() })
|
Some(rtc.bkpr(register).read().bkp())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -221,7 +213,7 @@ impl sealed::Instance for crate::peripherals::RTC {
|
|||||||
|
|
||||||
fn write_backup_register(rtc: &Rtc, register: usize, value: u32) {
|
fn write_backup_register(rtc: &Rtc, register: usize, value: u32) {
|
||||||
if register < Self::BACKUP_REGISTER_COUNT {
|
if register < Self::BACKUP_REGISTER_COUNT {
|
||||||
unsafe { rtc.bkpr(register).write(|w| w.set_bkp(value)) }
|
rtc.bkpr(register).write(|w| w.set_bkp(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
/// It this changes the RTC clock source the time will be reset
|
/// It this changes the RTC clock source the time will be reset
|
||||||
pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) {
|
pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) {
|
||||||
// Unlock the backup domain
|
// Unlock the backup domain
|
||||||
unsafe {
|
|
||||||
#[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))]
|
#[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))]
|
||||||
{
|
{
|
||||||
crate::pac::PWR.cr1().modify(|w| w.set_dbp(true));
|
crate::pac::PWR.cr1().modify(|w| w.set_dbp(true));
|
||||||
@ -50,10 +49,8 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
w.set_lsebyp(reg.lsebyp());
|
w.set_lsebyp(reg.lsebyp());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
self.write(true, |rtc| {
|
self.write(true, |rtc| {
|
||||||
unsafe {
|
|
||||||
rtc.cr().modify(|w| {
|
rtc.cr().modify(|w| {
|
||||||
w.set_fmt(Fmt::TWENTYFOURHOUR);
|
w.set_fmt(Fmt::TWENTYFOURHOUR);
|
||||||
w.set_osel(Osel::DISABLED);
|
w.set_osel(Osel::DISABLED);
|
||||||
@ -71,7 +68,6 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
w.set_tampalrm_type(TampalrmType::PUSHPULL);
|
w.set_tampalrm_type(TampalrmType::PUSHPULL);
|
||||||
w.set_tampalrm_pu(TampalrmPu::NOPULLUP);
|
w.set_tampalrm_pu(TampalrmPu::NOPULLUP);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
self.rtc_config = rtc_config;
|
self.rtc_config = rtc_config;
|
||||||
@ -99,7 +95,6 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
clock_drift = clock_drift / Self::RTC_CALR_RESOLUTION_PPM;
|
clock_drift = clock_drift / Self::RTC_CALR_RESOLUTION_PPM;
|
||||||
|
|
||||||
self.write(false, |rtc| {
|
self.write(false, |rtc| {
|
||||||
unsafe {
|
|
||||||
rtc.calr().write(|w| {
|
rtc.calr().write(|w| {
|
||||||
match period {
|
match period {
|
||||||
RtcCalibrationCyclePeriod::Seconds8 => {
|
RtcCalibrationCyclePeriod::Seconds8 => {
|
||||||
@ -139,7 +134,6 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
w.set_calm((clock_drift * -1.0) as u16);
|
w.set_calm((clock_drift * -1.0) as u16);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +144,6 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
// Disable write protection.
|
// Disable write protection.
|
||||||
// This is safe, as we're only writin the correct and expected values.
|
// This is safe, as we're only writin the correct and expected values.
|
||||||
unsafe {
|
|
||||||
r.wpr().write(|w| w.set_key(Key::DEACTIVATE1));
|
r.wpr().write(|w| w.set_key(Key::DEACTIVATE1));
|
||||||
r.wpr().write(|w| w.set_key(Key::DEACTIVATE2));
|
r.wpr().write(|w| w.set_key(Key::DEACTIVATE2));
|
||||||
|
|
||||||
@ -160,11 +153,9 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
// ~2 RTCCLK cycles
|
// ~2 RTCCLK cycles
|
||||||
while !r.icsr().read().initf() {}
|
while !r.icsr().read().initf() {}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let result = f(&r);
|
let result = f(&r);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
if init_mode {
|
if init_mode {
|
||||||
r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
|
r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
|
||||||
}
|
}
|
||||||
@ -172,7 +163,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
|||||||
// Re-enable write protection.
|
// Re-enable write protection.
|
||||||
// This is safe, as the field accepts the full range of 8-bit values.
|
// This is safe, as the field accepts the full range of 8-bit values.
|
||||||
r.wpr().write(|w| w.set_key(Key::ACTIVATE));
|
r.wpr().write(|w| w.set_key(Key::ACTIVATE));
|
||||||
}
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,7 +183,7 @@ impl sealed::Instance for crate::peripherals::RTC {
|
|||||||
fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) {
|
fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) {
|
||||||
if register < Self::BACKUP_REGISTER_COUNT {
|
if register < Self::BACKUP_REGISTER_COUNT {
|
||||||
// RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC
|
// RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC
|
||||||
//unsafe { self.rtc.bkpr()[register].write(|w| w.bits(value)) }
|
//self.rtc.bkpr()[register].write(|w| w.bits(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,6 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
impl<T: Instance> InterruptHandler<T> {
|
impl<T: Instance> InterruptHandler<T> {
|
||||||
fn data_interrupts(enable: bool) {
|
fn data_interrupts(enable: bool) {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
// NOTE(unsafe) Atomic write
|
|
||||||
unsafe {
|
|
||||||
regs.maskr().write(|w| {
|
regs.maskr().write(|w| {
|
||||||
w.set_dcrcfailie(enable);
|
w.set_dcrcfailie(enable);
|
||||||
w.set_dtimeoutie(enable);
|
w.set_dtimeoutie(enable);
|
||||||
@ -40,7 +38,6 @@ impl<T: Instance> InterruptHandler<T> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
@ -285,7 +282,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(clk, cmd, d0);
|
into_ref!(clk, cmd, d0);
|
||||||
|
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
|
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
|
||||||
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
|
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||||
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
|
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||||
@ -322,7 +319,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(clk, cmd, d0, d1, d2, d3);
|
into_ref!(clk, cmd, d0, d1, d2, d3);
|
||||||
|
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
|
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
|
||||||
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
|
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||||
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
|
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||||
@ -364,7 +361,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(clk, cmd, d0);
|
into_ref!(clk, cmd, d0);
|
||||||
|
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
|
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
|
||||||
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
|
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||||
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
|
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||||
@ -400,7 +397,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(clk, cmd, d0, d1, d2, d3);
|
into_ref!(clk, cmd, d0, d1, d2, d3);
|
||||||
|
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
|
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
|
||||||
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
|
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||||
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
|
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||||
@ -451,7 +448,6 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
unsafe { T::Interrupt::enable() };
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
unsafe {
|
|
||||||
regs.clkcr().write(|w| {
|
regs.clkcr().write(|w| {
|
||||||
w.set_pwrsav(false);
|
w.set_pwrsav(false);
|
||||||
w.set_negedge(false);
|
w.set_negedge(false);
|
||||||
@ -470,7 +466,6 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
// Power off, writen 00: Clock to the card is stopped;
|
// Power off, writen 00: Clock to the card is stopped;
|
||||||
// D[7:0], CMD, and CK are driven high.
|
// D[7:0], CMD, and CK are driven high.
|
||||||
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
|
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
_peri: sdmmc,
|
_peri: sdmmc,
|
||||||
@ -495,30 +490,24 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
fn data_active() -> bool {
|
fn data_active() -> bool {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
// NOTE(unsafe) Atomic read with no side-effects
|
|
||||||
unsafe {
|
|
||||||
let status = regs.star().read();
|
let status = regs.star().read();
|
||||||
#[cfg(sdmmc_v1)]
|
#[cfg(sdmmc_v1)]
|
||||||
return status.rxact() || status.txact();
|
return status.rxact() || status.txact();
|
||||||
#[cfg(sdmmc_v2)]
|
#[cfg(sdmmc_v2)]
|
||||||
return status.dpsmact();
|
return status.dpsmact();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Coammand transfer is in progress
|
/// Coammand transfer is in progress
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn cmd_active() -> bool {
|
fn cmd_active() -> bool {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
// NOTE(unsafe) Atomic read with no side-effects
|
|
||||||
unsafe {
|
|
||||||
let status = regs.star().read();
|
let status = regs.star().read();
|
||||||
#[cfg(sdmmc_v1)]
|
#[cfg(sdmmc_v1)]
|
||||||
return status.cmdact();
|
return status.cmdact();
|
||||||
#[cfg(sdmmc_v2)]
|
#[cfg(sdmmc_v2)]
|
||||||
return status.cpsmact();
|
return status.cpsmact();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
|
/// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -542,19 +531,17 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
Self::wait_idle();
|
Self::wait_idle();
|
||||||
Self::clear_interrupt_flags();
|
Self::clear_interrupt_flags();
|
||||||
|
|
||||||
// NOTE(unsafe) We have exclusive access to the regisers
|
|
||||||
unsafe {
|
|
||||||
regs.dtimer()
|
regs.dtimer()
|
||||||
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
|
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
|
||||||
regs.dlenr().write(|w| w.set_datalength(length_bytes));
|
regs.dlenr().write(|w| w.set_datalength(length_bytes));
|
||||||
|
|
||||||
#[cfg(sdmmc_v1)]
|
#[cfg(sdmmc_v1)]
|
||||||
let transfer = {
|
let transfer = unsafe {
|
||||||
let request = self.dma.request();
|
let request = self.dma.request();
|
||||||
Transfer::new_read(
|
Transfer::new_read(
|
||||||
&mut self.dma,
|
&mut self.dma,
|
||||||
request,
|
request,
|
||||||
regs.fifor().ptr() as *mut u32,
|
regs.fifor().as_ptr() as *mut u32,
|
||||||
buffer,
|
buffer,
|
||||||
DMA_TRANSFER_OPTIONS,
|
DMA_TRANSFER_OPTIONS,
|
||||||
)
|
)
|
||||||
@ -580,7 +567,6 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
|
|
||||||
transfer
|
transfer
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
@ -598,20 +584,18 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
Self::wait_idle();
|
Self::wait_idle();
|
||||||
Self::clear_interrupt_flags();
|
Self::clear_interrupt_flags();
|
||||||
|
|
||||||
// NOTE(unsafe) We have exclusive access to the regisers
|
|
||||||
unsafe {
|
|
||||||
regs.dtimer()
|
regs.dtimer()
|
||||||
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
|
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
|
||||||
regs.dlenr().write(|w| w.set_datalength(length_bytes));
|
regs.dlenr().write(|w| w.set_datalength(length_bytes));
|
||||||
|
|
||||||
#[cfg(sdmmc_v1)]
|
#[cfg(sdmmc_v1)]
|
||||||
let transfer = {
|
let transfer = unsafe {
|
||||||
let request = self.dma.request();
|
let request = self.dma.request();
|
||||||
Transfer::new_write(
|
Transfer::new_write(
|
||||||
&mut self.dma,
|
&mut self.dma,
|
||||||
request,
|
request,
|
||||||
buffer,
|
buffer,
|
||||||
regs.fifor().ptr() as *mut u32,
|
regs.fifor().as_ptr() as *mut u32,
|
||||||
DMA_TRANSFER_OPTIONS,
|
DMA_TRANSFER_OPTIONS,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
@ -636,13 +620,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
|
|
||||||
transfer
|
transfer
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Stops the DMA datapath
|
/// Stops the DMA datapath
|
||||||
fn stop_datapath() {
|
fn stop_datapath() {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
#[cfg(sdmmc_v1)]
|
#[cfg(sdmmc_v1)]
|
||||||
regs.dctrl().modify(|w| {
|
regs.dctrl().modify(|w| {
|
||||||
w.set_dmaen(false);
|
w.set_dmaen(false);
|
||||||
@ -651,7 +633,6 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
#[cfg(sdmmc_v2)]
|
#[cfg(sdmmc_v2)]
|
||||||
regs.idmactrlr().modify(|w| w.set_idmaen(false));
|
regs.idmactrlr().modify(|w| w.set_idmaen(false));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the CLKDIV field in CLKCR. Updates clock field in self
|
/// Sets the CLKDIV field in CLKCR. Updates clock field in self
|
||||||
fn clkcr_set_clkdiv(&mut self, freq: u32, width: BusWidth) -> Result<(), Error> {
|
fn clkcr_set_clkdiv(&mut self, freq: u32, width: BusWidth) -> Result<(), Error> {
|
||||||
@ -673,8 +654,6 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32);
|
assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32);
|
||||||
self.clock = new_clock;
|
self.clock = new_clock;
|
||||||
|
|
||||||
// NOTE(unsafe) We have exclusive access to the regblock
|
|
||||||
unsafe {
|
|
||||||
// CPSMACT and DPSMACT must be 0 to set CLKDIV
|
// CPSMACT and DPSMACT must be 0 to set CLKDIV
|
||||||
Self::wait_idle();
|
Self::wait_idle();
|
||||||
regs.clkcr().modify(|w| {
|
regs.clkcr().modify(|w| {
|
||||||
@ -682,7 +661,6 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
#[cfg(sdmmc_v1)]
|
#[cfg(sdmmc_v1)]
|
||||||
w.set_bypass(_bypass);
|
w.set_bypass(_bypass);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -710,7 +688,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
|
|
||||||
// Arm `OnDrop` after the buffer, so it will be dropped first
|
// Arm `OnDrop` after the buffer, so it will be dropped first
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
|
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||||
|
|
||||||
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
|
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
|
||||||
InterruptHandler::<T>::data_interrupts(true);
|
InterruptHandler::<T>::data_interrupts(true);
|
||||||
@ -718,7 +696,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
|
|
||||||
let res = poll_fn(|cx| {
|
let res = poll_fn(|cx| {
|
||||||
T::state().register(cx.waker());
|
T::state().register(cx.waker());
|
||||||
let status = unsafe { regs.star().read() };
|
let status = regs.star().read();
|
||||||
|
|
||||||
if status.dcrcfail() {
|
if status.dcrcfail() {
|
||||||
return Poll::Ready(Err(Error::Crc));
|
return Poll::Ready(Err(Error::Crc));
|
||||||
@ -769,8 +747,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
|
|
||||||
Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13
|
Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13
|
||||||
|
|
||||||
// NOTE(unsafe) Atomic read with no side-effects
|
let r1 = regs.respr(0).read().cardstatus();
|
||||||
let r1 = unsafe { regs.respr(0).read().cardstatus() };
|
|
||||||
Ok(r1.into())
|
Ok(r1.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -786,7 +763,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
|
|
||||||
// Arm `OnDrop` after the buffer, so it will be dropped first
|
// Arm `OnDrop` after the buffer, so it will be dropped first
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
|
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||||
|
|
||||||
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
|
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
|
||||||
InterruptHandler::<T>::data_interrupts(true);
|
InterruptHandler::<T>::data_interrupts(true);
|
||||||
@ -794,7 +771,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
|
|
||||||
let res = poll_fn(|cx| {
|
let res = poll_fn(|cx| {
|
||||||
T::state().register(cx.waker());
|
T::state().register(cx.waker());
|
||||||
let status = unsafe { regs.star().read() };
|
let status = regs.star().read();
|
||||||
|
|
||||||
if status.dcrcfail() {
|
if status.dcrcfail() {
|
||||||
return Poll::Ready(Err(Error::Crc));
|
return Poll::Ready(Err(Error::Crc));
|
||||||
@ -840,8 +817,6 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn clear_interrupt_flags() {
|
fn clear_interrupt_flags() {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
// NOTE(unsafe) Atomic write
|
|
||||||
unsafe {
|
|
||||||
regs.icr().write(|w| {
|
regs.icr().write(|w| {
|
||||||
w.set_ccrcfailc(true);
|
w.set_ccrcfailc(true);
|
||||||
w.set_dcrcfailc(true);
|
w.set_dcrcfailc(true);
|
||||||
@ -869,7 +844,6 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> {
|
async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> {
|
||||||
// Read the the 64-bit SCR register
|
// Read the the 64-bit SCR register
|
||||||
@ -880,7 +854,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
|
|
||||||
// Arm `OnDrop` after the buffer, so it will be dropped first
|
// Arm `OnDrop` after the buffer, so it will be dropped first
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
|
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||||
|
|
||||||
let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3);
|
let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3);
|
||||||
InterruptHandler::<T>::data_interrupts(true);
|
InterruptHandler::<T>::data_interrupts(true);
|
||||||
@ -888,7 +862,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
|
|
||||||
let res = poll_fn(|cx| {
|
let res = poll_fn(|cx| {
|
||||||
T::state().register(cx.waker());
|
T::state().register(cx.waker());
|
||||||
let status = unsafe { regs.star().read() };
|
let status = regs.star().read();
|
||||||
|
|
||||||
if status.dcrcfail() {
|
if status.dcrcfail() {
|
||||||
return Poll::Ready(Err(Error::Crc));
|
return Poll::Ready(Err(Error::Crc));
|
||||||
@ -921,8 +895,6 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
Self::clear_interrupt_flags();
|
Self::clear_interrupt_flags();
|
||||||
// NOTE(safety) Atomic operations
|
|
||||||
unsafe {
|
|
||||||
// CP state machine must be idle
|
// CP state machine must be idle
|
||||||
while Self::cmd_active() {}
|
while Self::cmd_active() {}
|
||||||
|
|
||||||
@ -968,12 +940,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
fn on_drop() {
|
||||||
///
|
|
||||||
/// Ensure that `regs` has exclusive access to the regblocks
|
|
||||||
unsafe fn on_drop() {
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
if Self::data_active() {
|
if Self::data_active() {
|
||||||
Self::clear_interrupt_flags();
|
Self::clear_interrupt_flags();
|
||||||
@ -1017,8 +985,6 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
false => BusWidth::One,
|
false => BusWidth::One,
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE(unsafe) We have exclusive access to the peripheral
|
|
||||||
unsafe {
|
|
||||||
// While the SD/SDIO card or eMMC is in identification mode,
|
// While the SD/SDIO card or eMMC is in identification mode,
|
||||||
// the SDMMC_CK frequency must be no more than 400 kHz.
|
// the SDMMC_CK frequency must be no more than 400 kHz.
|
||||||
let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
|
let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
|
||||||
@ -1151,7 +1117,6 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
}
|
}
|
||||||
// Read status after signalling change
|
// Read status after signalling change
|
||||||
self.read_sd_status().await?;
|
self.read_sd_status().await?;
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1172,7 +1137,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
|
Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
|
||||||
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
|
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||||
|
|
||||||
let transfer = self.prepare_datapath_read(buffer, 512, 9);
|
let transfer = self.prepare_datapath_read(buffer, 512, 9);
|
||||||
InterruptHandler::<T>::data_interrupts(true);
|
InterruptHandler::<T>::data_interrupts(true);
|
||||||
@ -1180,7 +1145,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
|
|
||||||
let res = poll_fn(|cx| {
|
let res = poll_fn(|cx| {
|
||||||
T::state().register(cx.waker());
|
T::state().register(cx.waker());
|
||||||
let status = unsafe { regs.star().read() };
|
let status = regs.star().read();
|
||||||
|
|
||||||
if status.dcrcfail() {
|
if status.dcrcfail() {
|
||||||
return Poll::Ready(Err(Error::Crc));
|
return Poll::Ready(Err(Error::Crc));
|
||||||
@ -1217,7 +1182,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
|
Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
|
||||||
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
|
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||||
|
|
||||||
// sdmmc_v1 uses different cmd/dma order than v2, but only for writes
|
// sdmmc_v1 uses different cmd/dma order than v2, but only for writes
|
||||||
#[cfg(sdmmc_v1)]
|
#[cfg(sdmmc_v1)]
|
||||||
@ -1231,7 +1196,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
|
|
||||||
let res = poll_fn(|cx| {
|
let res = poll_fn(|cx| {
|
||||||
T::state().register(cx.waker());
|
T::state().register(cx.waker());
|
||||||
let status = unsafe { regs.star().read() };
|
let status = regs.star().read();
|
||||||
|
|
||||||
if status.dcrcfail() {
|
if status.dcrcfail() {
|
||||||
return Poll::Ready(Err(Error::Crc));
|
return Poll::Ready(Err(Error::Crc));
|
||||||
@ -1289,9 +1254,9 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
|||||||
impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> {
|
impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
T::Interrupt::disable();
|
T::Interrupt::disable();
|
||||||
unsafe { Self::on_drop() };
|
Self::on_drop();
|
||||||
|
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
self.clk.set_as_disconnected();
|
self.clk.set_as_disconnected();
|
||||||
self.cmd.set_as_disconnected();
|
self.cmd.set_as_disconnected();
|
||||||
self.d0.set_as_disconnected();
|
self.d0.set_as_disconnected();
|
||||||
|
@ -98,14 +98,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
Polarity::IdleHigh => Pull::Up,
|
Polarity::IdleHigh => Pull::Up,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
|
||||||
sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode);
|
sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode);
|
||||||
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
|
mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
|
||||||
mosi.set_speed(crate::gpio::Speed::VeryHigh);
|
mosi.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
miso.set_as_af(miso.af_num(), AFType::Input);
|
miso.set_as_af(miso.af_num(), AFType::Input);
|
||||||
miso.set_speed(crate::gpio::Speed::VeryHigh);
|
miso.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
}
|
|
||||||
|
|
||||||
Self::new_inner(
|
Self::new_inner(
|
||||||
peri,
|
peri,
|
||||||
@ -129,12 +127,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(sck, miso);
|
into_ref!(sck, miso);
|
||||||
unsafe {
|
|
||||||
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
|
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
|
||||||
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
miso.set_as_af(miso.af_num(), AFType::Input);
|
miso.set_as_af(miso.af_num(), AFType::Input);
|
||||||
miso.set_speed(crate::gpio::Speed::VeryHigh);
|
miso.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
}
|
|
||||||
|
|
||||||
Self::new_inner(
|
Self::new_inner(
|
||||||
peri,
|
peri,
|
||||||
@ -158,12 +154,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(sck, mosi);
|
into_ref!(sck, mosi);
|
||||||
unsafe {
|
|
||||||
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
|
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
|
||||||
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
|
mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
|
||||||
mosi.set_speed(crate::gpio::Speed::VeryHigh);
|
mosi.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
}
|
|
||||||
|
|
||||||
Self::new_inner(
|
Self::new_inner(
|
||||||
peri,
|
peri,
|
||||||
@ -186,10 +180,8 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(mosi);
|
into_ref!(mosi);
|
||||||
unsafe {
|
|
||||||
mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down);
|
mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down);
|
||||||
mosi.set_speed(crate::gpio::Speed::Medium);
|
mosi.set_speed(crate::gpio::Speed::Medium);
|
||||||
}
|
|
||||||
|
|
||||||
Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, freq, config)
|
Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, freq, config)
|
||||||
}
|
}
|
||||||
@ -247,7 +239,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
T::reset();
|
T::reset();
|
||||||
|
|
||||||
#[cfg(any(spi_v1, spi_f1))]
|
#[cfg(any(spi_v1, spi_f1))]
|
||||||
unsafe {
|
{
|
||||||
T::REGS.cr2().modify(|w| {
|
T::REGS.cr2().modify(|w| {
|
||||||
w.set_ssoe(false);
|
w.set_ssoe(false);
|
||||||
});
|
});
|
||||||
@ -270,7 +262,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
#[cfg(spi_v2)]
|
#[cfg(spi_v2)]
|
||||||
unsafe {
|
{
|
||||||
T::REGS.cr2().modify(|w| {
|
T::REGS.cr2().modify(|w| {
|
||||||
let (ds, frxth) = <u8 as sealed::Word>::CONFIG;
|
let (ds, frxth) = <u8 as sealed::Word>::CONFIG;
|
||||||
w.set_frxth(frxth);
|
w.set_frxth(frxth);
|
||||||
@ -292,7 +284,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||||
unsafe {
|
{
|
||||||
T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff);
|
T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff);
|
||||||
T::REGS.cfg2().modify(|w| {
|
T::REGS.cfg2().modify(|w| {
|
||||||
//w.set_ssoe(true);
|
//w.set_ssoe(true);
|
||||||
@ -343,29 +335,25 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
let lsbfirst = config.raw_byte_order();
|
let lsbfirst = config.raw_byte_order();
|
||||||
|
|
||||||
#[cfg(any(spi_v1, spi_f1, spi_v2))]
|
#[cfg(any(spi_v1, spi_f1, spi_v2))]
|
||||||
unsafe {
|
|
||||||
T::REGS.cr1().modify(|w| {
|
T::REGS.cr1().modify(|w| {
|
||||||
w.set_cpha(cpha);
|
w.set_cpha(cpha);
|
||||||
w.set_cpol(cpol);
|
w.set_cpol(cpol);
|
||||||
w.set_lsbfirst(lsbfirst);
|
w.set_lsbfirst(lsbfirst);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||||
unsafe {
|
|
||||||
T::REGS.cfg2().modify(|w| {
|
T::REGS.cfg2().modify(|w| {
|
||||||
w.set_cpha(cpha);
|
w.set_cpha(cpha);
|
||||||
w.set_cpol(cpol);
|
w.set_cpol(cpol);
|
||||||
w.set_lsbfirst(lsbfirst);
|
w.set_lsbfirst(lsbfirst);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_current_config(&self) -> Config {
|
pub fn get_current_config(&self) -> Config {
|
||||||
#[cfg(any(spi_v1, spi_f1, spi_v2))]
|
#[cfg(any(spi_v1, spi_f1, spi_v2))]
|
||||||
let cfg = unsafe { T::REGS.cr1().read() };
|
let cfg = T::REGS.cr1().read();
|
||||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||||
let cfg = unsafe { T::REGS.cfg2().read() };
|
let cfg = T::REGS.cfg2().read();
|
||||||
let polarity = if cfg.cpol() == vals::Cpol::IDLELOW {
|
let polarity = if cfg.cpol() == vals::Cpol::IDLELOW {
|
||||||
Polarity::IdleLow
|
Polarity::IdleLow
|
||||||
} else {
|
} else {
|
||||||
@ -395,7 +383,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(spi_v1, spi_f1))]
|
#[cfg(any(spi_v1, spi_f1))]
|
||||||
unsafe {
|
{
|
||||||
T::REGS.cr1().modify(|reg| {
|
T::REGS.cr1().modify(|reg| {
|
||||||
reg.set_spe(false);
|
reg.set_spe(false);
|
||||||
reg.set_dff(word_size)
|
reg.set_dff(word_size)
|
||||||
@ -405,7 +393,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
#[cfg(spi_v2)]
|
#[cfg(spi_v2)]
|
||||||
unsafe {
|
{
|
||||||
T::REGS.cr1().modify(|w| {
|
T::REGS.cr1().modify(|w| {
|
||||||
w.set_spe(false);
|
w.set_spe(false);
|
||||||
});
|
});
|
||||||
@ -418,7 +406,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||||
unsafe {
|
{
|
||||||
T::REGS.cr1().modify(|w| {
|
T::REGS.cr1().modify(|w| {
|
||||||
w.set_csusp(true);
|
w.set_csusp(true);
|
||||||
});
|
});
|
||||||
@ -447,17 +435,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.set_word_size(W::CONFIG);
|
self.set_word_size(W::CONFIG);
|
||||||
unsafe {
|
|
||||||
T::REGS.cr1().modify(|w| {
|
T::REGS.cr1().modify(|w| {
|
||||||
w.set_spe(false);
|
w.set_spe(false);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
let tx_request = self.txdma.request();
|
let tx_request = self.txdma.request();
|
||||||
let tx_dst = T::REGS.tx_ptr();
|
let tx_dst = T::REGS.tx_ptr();
|
||||||
let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) };
|
let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) };
|
||||||
|
|
||||||
unsafe {
|
|
||||||
set_txdmaen(T::REGS, true);
|
set_txdmaen(T::REGS, true);
|
||||||
T::REGS.cr1().modify(|w| {
|
T::REGS.cr1().modify(|w| {
|
||||||
w.set_spe(true);
|
w.set_spe(true);
|
||||||
@ -466,7 +451,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
T::REGS.cr1().modify(|w| {
|
T::REGS.cr1().modify(|w| {
|
||||||
w.set_cstart(true);
|
w.set_cstart(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
tx_f.await;
|
tx_f.await;
|
||||||
|
|
||||||
@ -485,11 +469,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.set_word_size(W::CONFIG);
|
self.set_word_size(W::CONFIG);
|
||||||
unsafe {
|
|
||||||
T::REGS.cr1().modify(|w| {
|
T::REGS.cr1().modify(|w| {
|
||||||
w.set_spe(false);
|
w.set_spe(false);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// SPIv3 clears rxfifo on SPE=0
|
// SPIv3 clears rxfifo on SPE=0
|
||||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||||
@ -517,7 +499,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
|
||||||
set_txdmaen(T::REGS, true);
|
set_txdmaen(T::REGS, true);
|
||||||
T::REGS.cr1().modify(|w| {
|
T::REGS.cr1().modify(|w| {
|
||||||
w.set_spe(true);
|
w.set_spe(true);
|
||||||
@ -526,7 +507,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
T::REGS.cr1().modify(|w| {
|
T::REGS.cr1().modify(|w| {
|
||||||
w.set_cstart(true);
|
w.set_cstart(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
join(tx_f, rx_f).await;
|
join(tx_f, rx_f).await;
|
||||||
|
|
||||||
@ -548,11 +528,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.set_word_size(W::CONFIG);
|
self.set_word_size(W::CONFIG);
|
||||||
unsafe {
|
|
||||||
T::REGS.cr1().modify(|w| {
|
T::REGS.cr1().modify(|w| {
|
||||||
w.set_spe(false);
|
w.set_spe(false);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// SPIv3 clears rxfifo on SPE=0
|
// SPIv3 clears rxfifo on SPE=0
|
||||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||||
@ -568,7 +546,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
let tx_dst = T::REGS.tx_ptr();
|
let tx_dst = T::REGS.tx_ptr();
|
||||||
let tx_f = unsafe { Transfer::new_write_raw(&mut self.txdma, tx_request, write, tx_dst, Default::default()) };
|
let tx_f = unsafe { Transfer::new_write_raw(&mut self.txdma, tx_request, write, tx_dst, Default::default()) };
|
||||||
|
|
||||||
unsafe {
|
|
||||||
set_txdmaen(T::REGS, true);
|
set_txdmaen(T::REGS, true);
|
||||||
T::REGS.cr1().modify(|w| {
|
T::REGS.cr1().modify(|w| {
|
||||||
w.set_spe(true);
|
w.set_spe(true);
|
||||||
@ -577,7 +554,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
T::REGS.cr1().modify(|w| {
|
T::REGS.cr1().modify(|w| {
|
||||||
w.set_cstart(true);
|
w.set_cstart(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
join(tx_f, rx_f).await;
|
join(tx_f, rx_f).await;
|
||||||
|
|
||||||
@ -603,7 +579,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
|
pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
|
||||||
unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) }
|
T::REGS.cr1().modify(|w| w.set_spe(true));
|
||||||
flush_rx_fifo(T::REGS);
|
flush_rx_fifo(T::REGS);
|
||||||
self.set_word_size(W::CONFIG);
|
self.set_word_size(W::CONFIG);
|
||||||
for word in words.iter() {
|
for word in words.iter() {
|
||||||
@ -613,7 +589,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
|
pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
|
||||||
unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) }
|
T::REGS.cr1().modify(|w| w.set_spe(true));
|
||||||
flush_rx_fifo(T::REGS);
|
flush_rx_fifo(T::REGS);
|
||||||
self.set_word_size(W::CONFIG);
|
self.set_word_size(W::CONFIG);
|
||||||
for word in words.iter_mut() {
|
for word in words.iter_mut() {
|
||||||
@ -623,7 +599,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
|
pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
|
||||||
unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) }
|
T::REGS.cr1().modify(|w| w.set_spe(true));
|
||||||
flush_rx_fifo(T::REGS);
|
flush_rx_fifo(T::REGS);
|
||||||
self.set_word_size(W::CONFIG);
|
self.set_word_size(W::CONFIG);
|
||||||
for word in words.iter_mut() {
|
for word in words.iter_mut() {
|
||||||
@ -633,7 +609,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
|
pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
|
||||||
unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) }
|
T::REGS.cr1().modify(|w| w.set_spe(true));
|
||||||
flush_rx_fifo(T::REGS);
|
flush_rx_fifo(T::REGS);
|
||||||
self.set_word_size(W::CONFIG);
|
self.set_word_size(W::CONFIG);
|
||||||
let len = read.len().max(write.len());
|
let len = read.len().max(write.len());
|
||||||
@ -650,13 +626,11 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
|
|
||||||
impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> {
|
impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
|
||||||
self.sck.as_ref().map(|x| x.set_as_disconnected());
|
self.sck.as_ref().map(|x| x.set_as_disconnected());
|
||||||
self.mosi.as_ref().map(|x| x.set_as_disconnected());
|
self.mosi.as_ref().map(|x| x.set_as_disconnected());
|
||||||
self.miso.as_ref().map(|x| x.set_as_disconnected());
|
self.miso.as_ref().map(|x| x.set_as_disconnected());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||||
use vals::Br;
|
use vals::Br;
|
||||||
@ -690,7 +664,7 @@ impl RegsExt for Regs {
|
|||||||
let dr = self.dr();
|
let dr = self.dr();
|
||||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||||
let dr = self.txdr();
|
let dr = self.txdr();
|
||||||
dr.ptr() as *mut W
|
dr.as_ptr() as *mut W
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rx_ptr<W>(&self) -> *mut W {
|
fn rx_ptr<W>(&self) -> *mut W {
|
||||||
@ -698,7 +672,7 @@ impl RegsExt for Regs {
|
|||||||
let dr = self.dr();
|
let dr = self.dr();
|
||||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||||
let dr = self.rxdr();
|
let dr = self.rxdr();
|
||||||
dr.ptr() as *mut W
|
dr.as_ptr() as *mut W
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -731,7 +705,7 @@ fn check_error_flags(sr: regs::Sr) -> Result<(), Error> {
|
|||||||
|
|
||||||
fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> {
|
fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> {
|
||||||
loop {
|
loop {
|
||||||
let sr = unsafe { regs.sr().read() };
|
let sr = regs.sr().read();
|
||||||
|
|
||||||
check_error_flags(sr)?;
|
check_error_flags(sr)?;
|
||||||
|
|
||||||
@ -748,7 +722,7 @@ fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> {
|
|||||||
|
|
||||||
fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
|
fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
|
||||||
loop {
|
loop {
|
||||||
let sr = unsafe { regs.sr().read() };
|
let sr = regs.sr().read();
|
||||||
|
|
||||||
check_error_flags(sr)?;
|
check_error_flags(sr)?;
|
||||||
|
|
||||||
@ -764,7 +738,6 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn flush_rx_fifo(regs: Regs) {
|
fn flush_rx_fifo(regs: Regs) {
|
||||||
unsafe {
|
|
||||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||||
while regs.sr().read().rxne() {
|
while regs.sr().read().rxne() {
|
||||||
let _ = regs.dr().read();
|
let _ = regs.dr().read();
|
||||||
@ -774,10 +747,8 @@ fn flush_rx_fifo(regs: Regs) {
|
|||||||
let _ = regs.rxdr().read();
|
let _ = regs.rxdr().read();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn set_txdmaen(regs: Regs, val: bool) {
|
fn set_txdmaen(regs: Regs, val: bool) {
|
||||||
unsafe {
|
|
||||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||||
regs.cr2().modify(|reg| {
|
regs.cr2().modify(|reg| {
|
||||||
reg.set_txdmaen(val);
|
reg.set_txdmaen(val);
|
||||||
@ -787,10 +758,8 @@ fn set_txdmaen(regs: Regs, val: bool) {
|
|||||||
reg.set_txdmaen(val);
|
reg.set_txdmaen(val);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn set_rxdmaen(regs: Regs, val: bool) {
|
fn set_rxdmaen(regs: Regs, val: bool) {
|
||||||
unsafe {
|
|
||||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||||
regs.cr2().modify(|reg| {
|
regs.cr2().modify(|reg| {
|
||||||
reg.set_rxdmaen(val);
|
reg.set_rxdmaen(val);
|
||||||
@ -800,10 +769,8 @@ fn set_rxdmaen(regs: Regs, val: bool) {
|
|||||||
reg.set_rxdmaen(val);
|
reg.set_rxdmaen(val);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn finish_dma(regs: Regs) {
|
fn finish_dma(regs: Regs) {
|
||||||
unsafe {
|
|
||||||
#[cfg(spi_v2)]
|
#[cfg(spi_v2)]
|
||||||
while regs.sr().read().ftlvl() > 0 {}
|
while regs.sr().read().ftlvl() > 0 {}
|
||||||
|
|
||||||
@ -830,7 +797,6 @@ fn finish_dma(regs: Regs) {
|
|||||||
reg.set_rxdmaen(false);
|
reg.set_rxdmaen(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {
|
fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {
|
||||||
spin_until_tx_ready(regs)?;
|
spin_until_tx_ready(regs)?;
|
||||||
|
@ -155,8 +155,7 @@ impl RtcDriver {
|
|||||||
|
|
||||||
let timer_freq = T::frequency();
|
let timer_freq = T::frequency();
|
||||||
|
|
||||||
// NOTE(unsafe) Critical section to use the unsafe methods
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
r.cr1().modify(|w| w.set_cen(false));
|
r.cr1().modify(|w| w.set_cen(false));
|
||||||
r.cnt().write(|w| w.set_cnt(0));
|
r.cnt().write(|w| w.set_cnt(0));
|
||||||
|
|
||||||
@ -184,7 +183,7 @@ impl RtcDriver {
|
|||||||
});
|
});
|
||||||
|
|
||||||
<T as BasicInstance>::Interrupt::unpend();
|
<T as BasicInstance>::Interrupt::unpend();
|
||||||
<T as BasicInstance>::Interrupt::enable();
|
unsafe { <T as BasicInstance>::Interrupt::enable() };
|
||||||
|
|
||||||
r.cr1().modify(|w| w.set_cen(true));
|
r.cr1().modify(|w| w.set_cen(true));
|
||||||
})
|
})
|
||||||
@ -193,9 +192,8 @@ impl RtcDriver {
|
|||||||
fn on_interrupt(&self) {
|
fn on_interrupt(&self) {
|
||||||
let r = T::regs_gp16();
|
let r = T::regs_gp16();
|
||||||
|
|
||||||
// NOTE(unsafe) Use critical section to access the methods
|
|
||||||
// XXX: reduce the size of this critical section ?
|
// XXX: reduce the size of this critical section ?
|
||||||
critical_section::with(|cs| unsafe {
|
critical_section::with(|cs| {
|
||||||
let sr = r.sr().read();
|
let sr = r.sr().read();
|
||||||
let dier = r.dier().read();
|
let dier = r.dier().read();
|
||||||
|
|
||||||
@ -228,7 +226,7 @@ impl RtcDriver {
|
|||||||
let period = self.period.fetch_add(1, Ordering::Relaxed) + 1;
|
let period = self.period.fetch_add(1, Ordering::Relaxed) + 1;
|
||||||
let t = (period as u64) << 15;
|
let t = (period as u64) << 15;
|
||||||
|
|
||||||
critical_section::with(move |cs| unsafe {
|
critical_section::with(move |cs| {
|
||||||
r.dier().modify(move |w| {
|
r.dier().modify(move |w| {
|
||||||
for n in 0..ALARM_COUNT {
|
for n in 0..ALARM_COUNT {
|
||||||
let alarm = &self.alarms.borrow(cs)[n];
|
let alarm = &self.alarms.borrow(cs)[n];
|
||||||
@ -269,8 +267,7 @@ impl Driver for RtcDriver {
|
|||||||
|
|
||||||
let period = self.period.load(Ordering::Relaxed);
|
let period = self.period.load(Ordering::Relaxed);
|
||||||
compiler_fence(Ordering::Acquire);
|
compiler_fence(Ordering::Acquire);
|
||||||
// NOTE(unsafe) Atomic read with no side-effects
|
let counter = r.cnt().read().cnt();
|
||||||
let counter = unsafe { r.cnt().read().cnt() };
|
|
||||||
calc_now(period, counter)
|
calc_now(period, counter)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +307,7 @@ impl Driver for RtcDriver {
|
|||||||
if timestamp <= t {
|
if timestamp <= t {
|
||||||
// If alarm timestamp has passed the alarm will not fire.
|
// If alarm timestamp has passed the alarm will not fire.
|
||||||
// Disarm the alarm and return `false` to indicate that.
|
// Disarm the alarm and return `false` to indicate that.
|
||||||
unsafe { r.dier().modify(|w| w.set_ccie(n + 1, false)) };
|
r.dier().modify(|w| w.set_ccie(n + 1, false));
|
||||||
|
|
||||||
alarm.timestamp.set(u64::MAX);
|
alarm.timestamp.set(u64::MAX);
|
||||||
|
|
||||||
@ -321,12 +318,11 @@ impl Driver for RtcDriver {
|
|||||||
|
|
||||||
// Write the CCR value regardless of whether we're going to enable it now or not.
|
// Write the CCR value regardless of whether we're going to enable it now or not.
|
||||||
// This way, when we enable it later, the right value is already set.
|
// This way, when we enable it later, the right value is already set.
|
||||||
unsafe { r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16)) };
|
r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16));
|
||||||
|
|
||||||
// Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
|
// Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
|
||||||
let diff = timestamp - t;
|
let diff = timestamp - t;
|
||||||
// NOTE(unsafe) We're in a critical section
|
r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000));
|
||||||
unsafe { r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)) };
|
|
||||||
|
|
||||||
true
|
true
|
||||||
})
|
})
|
||||||
|
@ -60,26 +60,20 @@ macro_rules! impl_basic_16bit_timer {
|
|||||||
type Interrupt = crate::interrupt::typelevel::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
|
|
||||||
fn regs() -> crate::pac::timer::TimBasic {
|
fn regs() -> crate::pac::timer::TimBasic {
|
||||||
crate::pac::timer::TimBasic(crate::pac::$inst.0)
|
unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(&mut self) {
|
fn start(&mut self) {
|
||||||
unsafe {
|
|
||||||
Self::regs().cr1().modify(|r| r.set_cen(true));
|
Self::regs().cr1().modify(|r| r.set_cen(true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn stop(&mut self) {
|
fn stop(&mut self) {
|
||||||
unsafe {
|
|
||||||
Self::regs().cr1().modify(|r| r.set_cen(false));
|
Self::regs().cr1().modify(|r| r.set_cen(false));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&mut self) {
|
fn reset(&mut self) {
|
||||||
unsafe {
|
|
||||||
Self::regs().cnt().write(|r| r.set_cnt(0));
|
Self::regs().cnt().write(|r| r.set_cnt(0));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn set_frequency(&mut self, frequency: Hertz) {
|
fn set_frequency(&mut self, frequency: Hertz) {
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
@ -90,7 +84,6 @@ macro_rules! impl_basic_16bit_timer {
|
|||||||
let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into());
|
let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into());
|
||||||
|
|
||||||
let regs = Self::regs();
|
let regs = Self::regs();
|
||||||
unsafe {
|
|
||||||
regs.psc().write(|r| r.set_psc(psc));
|
regs.psc().write(|r| r.set_psc(psc));
|
||||||
regs.arr().write(|r| r.set_arr(arr));
|
regs.arr().write(|r| r.set_arr(arr));
|
||||||
|
|
||||||
@ -98,11 +91,9 @@ macro_rules! impl_basic_16bit_timer {
|
|||||||
regs.egr().write(|r| r.set_ug(true));
|
regs.egr().write(|r| r.set_ug(true));
|
||||||
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
|
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_update_interrupt(&mut self) -> bool {
|
fn clear_update_interrupt(&mut self) -> bool {
|
||||||
let regs = Self::regs();
|
let regs = Self::regs();
|
||||||
unsafe {
|
|
||||||
let sr = regs.sr().read();
|
let sr = regs.sr().read();
|
||||||
if sr.uif() {
|
if sr.uif() {
|
||||||
regs.sr().modify(|r| {
|
regs.sr().modify(|r| {
|
||||||
@ -113,14 +104,11 @@ macro_rules! impl_basic_16bit_timer {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn enable_update_interrupt(&mut self, enable: bool) {
|
fn enable_update_interrupt(&mut self, enable: bool) {
|
||||||
unsafe {
|
|
||||||
Self::regs().dier().write(|r| r.set_uie(enable));
|
Self::regs().dier().write(|r| r.set_uie(enable));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +129,6 @@ macro_rules! impl_32bit_timer {
|
|||||||
let arr: u32 = unwrap!(((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into()));
|
let arr: u32 = unwrap!(((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into()));
|
||||||
|
|
||||||
let regs = Self::regs_gp32();
|
let regs = Self::regs_gp32();
|
||||||
unsafe {
|
|
||||||
regs.psc().write(|r| r.set_psc(psc));
|
regs.psc().write(|r| r.set_psc(psc));
|
||||||
regs.arr().write(|r| r.set_arr(arr));
|
regs.arr().write(|r| r.set_arr(arr));
|
||||||
|
|
||||||
@ -150,7 +137,6 @@ macro_rules! impl_32bit_timer {
|
|||||||
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
|
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +171,7 @@ foreach_interrupt! {
|
|||||||
|
|
||||||
impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
|
impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
|
||||||
fn regs_gp16() -> crate::pac::timer::TimGp16 {
|
fn regs_gp16() -> crate::pac::timer::TimGp16 {
|
||||||
crate::pac::timer::TimGp16(crate::pac::$inst.0)
|
unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,7 +192,7 @@ foreach_interrupt! {
|
|||||||
|
|
||||||
impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
|
impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
|
||||||
fn regs_gp16() -> crate::pac::timer::TimGp16 {
|
fn regs_gp16() -> crate::pac::timer::TimGp16 {
|
||||||
crate::pac::timer::TimGp16(crate::pac::$inst.0)
|
unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,29 +19,34 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
|
|||||||
let state = T::buffered_state();
|
let state = T::buffered_state();
|
||||||
|
|
||||||
// RX
|
// RX
|
||||||
unsafe {
|
let sr_val = sr(r).read();
|
||||||
let sr = sr(r).read();
|
// On v1 & v2, reading DR clears the rxne, error and idle interrupt
|
||||||
clear_interrupt_flags(r, sr);
|
// flags. Keep this close to the SR read to reduce the chance of a
|
||||||
|
// flag being set in-between.
|
||||||
|
let dr = if sr_val.rxne() || cfg!(any(usart_v1, usart_v2)) && (sr_val.ore() || sr_val.idle()) {
|
||||||
|
Some(rdr(r).read_volatile())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
clear_interrupt_flags(r, sr_val);
|
||||||
|
|
||||||
if sr.rxne() {
|
if sr_val.pe() {
|
||||||
if sr.pe() {
|
|
||||||
warn!("Parity error");
|
warn!("Parity error");
|
||||||
}
|
}
|
||||||
if sr.fe() {
|
if sr_val.fe() {
|
||||||
warn!("Framing error");
|
warn!("Framing error");
|
||||||
}
|
}
|
||||||
if sr.ne() {
|
if sr_val.ne() {
|
||||||
warn!("Noise error");
|
warn!("Noise error");
|
||||||
}
|
}
|
||||||
if sr.ore() {
|
if sr_val.ore() {
|
||||||
warn!("Overrun error");
|
warn!("Overrun error");
|
||||||
}
|
}
|
||||||
|
if sr_val.rxne() {
|
||||||
let mut rx_writer = state.rx_buf.writer();
|
let mut rx_writer = state.rx_buf.writer();
|
||||||
let buf = rx_writer.push_slice();
|
let buf = rx_writer.push_slice();
|
||||||
if !buf.is_empty() {
|
if !buf.is_empty() {
|
||||||
// This read also clears the error and idle interrupt flags on v1.
|
buf[0] = dr.unwrap();
|
||||||
buf[0] = rdr(r).read_volatile();
|
|
||||||
rx_writer.push_done(1);
|
rx_writer.push_done(1);
|
||||||
} else {
|
} else {
|
||||||
// FIXME: Should we disable any further RX interrupts when the buffer becomes full.
|
// FIXME: Should we disable any further RX interrupts when the buffer becomes full.
|
||||||
@ -52,13 +57,11 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sr.idle() {
|
if sr_val.idle() {
|
||||||
state.rx_waker.wake();
|
state.rx_waker.wake();
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TX
|
// TX
|
||||||
unsafe {
|
|
||||||
if sr(r).read().txe() {
|
if sr(r).read().txe() {
|
||||||
let mut tx_reader = state.tx_buf.reader();
|
let mut tx_reader = state.tx_buf.reader();
|
||||||
let buf = tx_reader.pop_slice();
|
let buf = tx_reader.pop_slice();
|
||||||
@ -78,7 +81,6 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
rx_waker: AtomicWaker,
|
rx_waker: AtomicWaker,
|
||||||
@ -144,14 +146,12 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
|||||||
T::enable();
|
T::enable();
|
||||||
T::reset();
|
T::reset();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
|
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
|
||||||
cts.set_as_af(cts.af_num(), AFType::Input);
|
cts.set_as_af(cts.af_num(), AFType::Input);
|
||||||
T::regs().cr3().write(|w| {
|
T::regs().cr3().write(|w| {
|
||||||
w.set_rtse(true);
|
w.set_rtse(true);
|
||||||
w.set_ctse(true);
|
w.set_ctse(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
|
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
|
||||||
}
|
}
|
||||||
@ -172,12 +172,10 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
|||||||
T::enable();
|
T::enable();
|
||||||
T::reset();
|
T::reset();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
de.set_as_af(de.af_num(), AFType::OutputPushPull);
|
de.set_as_af(de.af_num(), AFType::OutputPushPull);
|
||||||
T::regs().cr3().write(|w| {
|
T::regs().cr3().write(|w| {
|
||||||
w.set_dem(true);
|
w.set_dem(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
|
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
|
||||||
}
|
}
|
||||||
@ -199,14 +197,11 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
|||||||
unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
|
unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
|
||||||
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
unsafe {
|
|
||||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||||
}
|
|
||||||
|
|
||||||
configure(r, &config, T::frequency(), T::KIND, true, true);
|
configure(r, &config, T::frequency(), T::KIND, true, true);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
r.cr1().modify(|w| {
|
r.cr1().modify(|w| {
|
||||||
#[cfg(lpuart_v2)]
|
#[cfg(lpuart_v2)]
|
||||||
w.set_fifoen(true);
|
w.set_fifoen(true);
|
||||||
@ -214,7 +209,6 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
|||||||
w.set_rxneie(true);
|
w.set_rxneie(true);
|
||||||
w.set_idleie(true);
|
w.set_idleie(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
T::Interrupt::unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::enable() };
|
unsafe { T::Interrupt::enable() };
|
||||||
|
@ -36,12 +36,11 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
|
|||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
let s = T::state();
|
let s = T::state();
|
||||||
|
|
||||||
let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) };
|
let (sr, cr1, cr3) = (sr(r).read(), r.cr1().read(), r.cr3().read());
|
||||||
|
|
||||||
let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie());
|
let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie());
|
||||||
if has_errors {
|
if has_errors {
|
||||||
// clear all interrupts and DMA Rx Request
|
// clear all interrupts and DMA Rx Request
|
||||||
unsafe {
|
|
||||||
r.cr1().modify(|w| {
|
r.cr1().modify(|w| {
|
||||||
// disable RXNE interrupt
|
// disable RXNE interrupt
|
||||||
w.set_rxneie(false);
|
w.set_rxneie(false);
|
||||||
@ -56,15 +55,12 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
|
|||||||
// disable DMA Rx Request
|
// disable DMA Rx Request
|
||||||
w.set_dmar(false);
|
w.set_dmar(false);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
} else if cr1.idleie() && sr.idle() {
|
} else if cr1.idleie() && sr.idle() {
|
||||||
// IDLE detected: no more data will come
|
// IDLE detected: no more data will come
|
||||||
unsafe {
|
|
||||||
r.cr1().modify(|w| {
|
r.cr1().modify(|w| {
|
||||||
// disable idle line detection
|
// disable idle line detection
|
||||||
w.set_idleie(false);
|
w.set_idleie(false);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
} else if cr1.rxneie() {
|
} else if cr1.rxneie() {
|
||||||
// We cannot check the RXNE flag as it is auto-cleared by the DMA controller
|
// We cannot check the RXNE flag as it is auto-cleared by the DMA controller
|
||||||
|
|
||||||
@ -205,12 +201,10 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
|
|||||||
T::enable();
|
T::enable();
|
||||||
T::reset();
|
T::reset();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
cts.set_as_af(cts.af_num(), AFType::Input);
|
cts.set_as_af(cts.af_num(), AFType::Input);
|
||||||
T::regs().cr3().write(|w| {
|
T::regs().cr3().write(|w| {
|
||||||
w.set_ctse(true);
|
w.set_ctse(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
Self::new_inner(peri, tx, tx_dma, config)
|
Self::new_inner(peri, tx, tx_dma, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,9 +218,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
|
|||||||
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||||
}
|
|
||||||
|
|
||||||
configure(r, &config, T::frequency(), T::KIND, false, true);
|
configure(r, &config, T::frequency(), T::KIND, false, true);
|
||||||
|
|
||||||
@ -245,11 +237,9 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
|
|||||||
{
|
{
|
||||||
let ch = &mut self.tx_dma;
|
let ch = &mut self.tx_dma;
|
||||||
let request = ch.request();
|
let request = ch.request();
|
||||||
unsafe {
|
|
||||||
T::regs().cr3().modify(|reg| {
|
T::regs().cr3().modify(|reg| {
|
||||||
reg.set_dmat(true);
|
reg.set_dmat(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
// If we don't assign future to a variable, the data register pointer
|
// If we don't assign future to a variable, the data register pointer
|
||||||
// is held across an await and makes the future non-Send.
|
// is held across an await and makes the future non-Send.
|
||||||
let transfer = unsafe { Transfer::new_write(ch, request, buffer, tdr(T::regs()), Default::default()) };
|
let transfer = unsafe { Transfer::new_write(ch, request, buffer, tdr(T::regs()), Default::default()) };
|
||||||
@ -258,21 +248,17 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
unsafe {
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
for &b in buffer {
|
for &b in buffer {
|
||||||
while !sr(r).read().txe() {}
|
while !sr(r).read().txe() {}
|
||||||
tdr(r).write_volatile(b);
|
unsafe { tdr(r).write_volatile(b) };
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
||||||
unsafe {
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
while !sr(r).read().tc() {}
|
while !sr(r).read().tc() {}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -305,12 +291,10 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
|||||||
T::enable();
|
T::enable();
|
||||||
T::reset();
|
T::reset();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
|
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
|
||||||
T::regs().cr3().write(|w| {
|
T::regs().cr3().write(|w| {
|
||||||
w.set_rtse(true);
|
w.set_rtse(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Self::new_inner(peri, rx, rx_dma, config)
|
Self::new_inner(peri, rx, rx_dma, config)
|
||||||
}
|
}
|
||||||
@ -325,9 +309,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
|||||||
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||||
}
|
|
||||||
|
|
||||||
configure(r, &config, T::frequency(), T::KIND, true, false);
|
configure(r, &config, T::frequency(), T::KIND, true, false);
|
||||||
|
|
||||||
@ -347,7 +329,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(usart_v1, usart_v2))]
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
unsafe fn check_rx_flags(&mut self) -> Result<bool, Error> {
|
fn check_rx_flags(&mut self) -> Result<bool, Error> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
loop {
|
loop {
|
||||||
// Handle all buffered error flags.
|
// Handle all buffered error flags.
|
||||||
@ -380,7 +362,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(usart_v3, usart_v4))]
|
#[cfg(any(usart_v3, usart_v4))]
|
||||||
unsafe fn check_rx_flags(&mut self) -> Result<bool, Error> {
|
fn check_rx_flags(&mut self) -> Result<bool, Error> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
let sr = r.isr().read();
|
let sr = r.isr().read();
|
||||||
if sr.pe() {
|
if sr.pe() {
|
||||||
@ -410,22 +392,18 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
|||||||
|
|
||||||
pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
|
pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
unsafe {
|
|
||||||
if self.check_rx_flags()? {
|
if self.check_rx_flags()? {
|
||||||
Ok(rdr(r).read_volatile())
|
Ok(unsafe { rdr(r).read_volatile() })
|
||||||
} else {
|
} else {
|
||||||
Err(nb::Error::WouldBlock)
|
Err(nb::Error::WouldBlock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
unsafe {
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
for b in buffer {
|
for b in buffer {
|
||||||
while !self.check_rx_flags()? {}
|
while !self.check_rx_flags()? {}
|
||||||
*b = rdr(r).read_volatile();
|
unsafe { *b = rdr(r).read_volatile() }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -451,8 +429,6 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
|||||||
let on_drop = OnDrop::new(move || {
|
let on_drop = OnDrop::new(move || {
|
||||||
// defmt::trace!("Clear all USART interrupts and DMA Read Request");
|
// defmt::trace!("Clear all USART interrupts and DMA Read Request");
|
||||||
// clear all interrupts and DMA Rx Request
|
// clear all interrupts and DMA Rx Request
|
||||||
// SAFETY: only clears Rx related flags
|
|
||||||
unsafe {
|
|
||||||
r.cr1().modify(|w| {
|
r.cr1().modify(|w| {
|
||||||
// disable RXNE interrupt
|
// disable RXNE interrupt
|
||||||
w.set_rxneie(false);
|
w.set_rxneie(false);
|
||||||
@ -467,7 +443,6 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
|||||||
// disable DMA Rx Request
|
// disable DMA Rx Request
|
||||||
w.set_dmar(false);
|
w.set_dmar(false);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let ch = &mut self.rx_dma;
|
let ch = &mut self.rx_dma;
|
||||||
@ -480,14 +455,11 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
|||||||
// future which will complete when DMA Read request completes
|
// future which will complete when DMA Read request completes
|
||||||
let transfer = unsafe { Transfer::new_read(ch, request, rdr(T::regs()), buffer, Default::default()) };
|
let transfer = unsafe { Transfer::new_read(ch, request, rdr(T::regs()), buffer, Default::default()) };
|
||||||
|
|
||||||
// SAFETY: The only way we might have a problem is using split rx and tx
|
|
||||||
// here we only modify or read Rx related flags, interrupts and DMA channel
|
|
||||||
unsafe {
|
|
||||||
// clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer
|
// clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer
|
||||||
if !self.detect_previous_overrun {
|
if !self.detect_previous_overrun {
|
||||||
let sr = sr(r).read();
|
let sr = sr(r).read();
|
||||||
// This read also clears the error and idle interrupt flags on v1.
|
// This read also clears the error and idle interrupt flags on v1.
|
||||||
rdr(r).read_volatile();
|
unsafe { rdr(r).read_volatile() };
|
||||||
clear_interrupt_flags(r, sr);
|
clear_interrupt_flags(r, sr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,7 +493,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
|||||||
|
|
||||||
let sr = sr(r).read();
|
let sr = sr(r).read();
|
||||||
// This read also clears the error and idle interrupt flags on v1.
|
// This read also clears the error and idle interrupt flags on v1.
|
||||||
rdr(r).read_volatile();
|
unsafe { rdr(r).read_volatile() };
|
||||||
clear_interrupt_flags(r, sr);
|
clear_interrupt_flags(r, sr);
|
||||||
|
|
||||||
if sr.pe() {
|
if sr.pe() {
|
||||||
@ -544,7 +516,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
|||||||
// clear idle flag
|
// clear idle flag
|
||||||
let sr = sr(r).read();
|
let sr = sr(r).read();
|
||||||
// This read also clears the error and idle interrupt flags on v1.
|
// This read also clears the error and idle interrupt flags on v1.
|
||||||
rdr(r).read_volatile();
|
unsafe { rdr(r).read_volatile() };
|
||||||
clear_interrupt_flags(r, sr);
|
clear_interrupt_flags(r, sr);
|
||||||
|
|
||||||
// enable idle interrupt
|
// enable idle interrupt
|
||||||
@ -552,7 +524,6 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
|||||||
w.set_idleie(true);
|
w.set_idleie(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
@ -562,15 +533,11 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
|||||||
|
|
||||||
s.rx_waker.register(cx.waker());
|
s.rx_waker.register(cx.waker());
|
||||||
|
|
||||||
// SAFETY: read only and we only use Rx related flags
|
let sr = sr(r).read();
|
||||||
let sr = unsafe { sr(r).read() };
|
|
||||||
|
|
||||||
// SAFETY: only clears Rx related flags
|
|
||||||
unsafe {
|
|
||||||
// This read also clears the error and idle interrupt flags on v1.
|
// This read also clears the error and idle interrupt flags on v1.
|
||||||
rdr(r).read_volatile();
|
unsafe { rdr(r).read_volatile() };
|
||||||
clear_interrupt_flags(r, sr);
|
clear_interrupt_flags(r, sr);
|
||||||
}
|
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
@ -677,14 +644,12 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
|||||||
T::enable();
|
T::enable();
|
||||||
T::reset();
|
T::reset();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
|
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
|
||||||
cts.set_as_af(cts.af_num(), AFType::Input);
|
cts.set_as_af(cts.af_num(), AFType::Input);
|
||||||
T::regs().cr3().write(|w| {
|
T::regs().cr3().write(|w| {
|
||||||
w.set_rtse(true);
|
w.set_rtse(true);
|
||||||
w.set_ctse(true);
|
w.set_ctse(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
|
Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -704,12 +669,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
|||||||
T::enable();
|
T::enable();
|
||||||
T::reset();
|
T::reset();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
de.set_as_af(de.af_num(), AFType::OutputPushPull);
|
de.set_as_af(de.af_num(), AFType::OutputPushPull);
|
||||||
T::regs().cr3().write(|w| {
|
T::regs().cr3().write(|w| {
|
||||||
w.set_dem(true);
|
w.set_dem(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
|
Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -725,10 +688,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
|||||||
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||||
}
|
|
||||||
|
|
||||||
configure(r, &config, T::frequency(), T::KIND, true, true);
|
configure(r, &config, T::frequency(), T::KIND, true, true);
|
||||||
|
|
||||||
@ -847,11 +808,9 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
|
|||||||
if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) {
|
if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) {
|
||||||
over8 = true;
|
over8 = true;
|
||||||
let div = div as u32;
|
let div = div as u32;
|
||||||
unsafe {
|
|
||||||
r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07)));
|
r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07)));
|
||||||
#[cfg(usart_v4)]
|
#[cfg(usart_v4)]
|
||||||
r.presc().write(|w| w.set_prescaler(_presc_val));
|
r.presc().write(|w| w.set_prescaler(_presc_val));
|
||||||
}
|
|
||||||
found = Some(div);
|
found = Some(div);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -860,11 +819,9 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
|
|||||||
|
|
||||||
if div < brr_max {
|
if div < brr_max {
|
||||||
let div = div as u32;
|
let div = div as u32;
|
||||||
unsafe {
|
|
||||||
r.brr().write_value(regs::Brr(div));
|
r.brr().write_value(regs::Brr(div));
|
||||||
#[cfg(usart_v4)]
|
#[cfg(usart_v4)]
|
||||||
r.presc().write(|w| w.set_prescaler(_presc_val));
|
r.presc().write(|w| w.set_prescaler(_presc_val));
|
||||||
}
|
|
||||||
found = Some(div);
|
found = Some(div);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -883,7 +840,6 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
|
|||||||
pclk_freq.0 / div
|
pclk_freq.0 / div
|
||||||
);
|
);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
r.cr2().write(|w| {
|
r.cr2().write(|w| {
|
||||||
w.set_stop(match config.stop_bits {
|
w.set_stop(match config.stop_bits {
|
||||||
StopBits::STOP0P5 => vals::Stop::STOP0P5,
|
StopBits::STOP0P5 => vals::Stop::STOP0P5,
|
||||||
@ -921,7 +877,6 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
|
|||||||
w.set_onebit(config.assume_noise_free);
|
w.set_onebit(config.assume_noise_free);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
mod eh02 {
|
mod eh02 {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -1111,12 +1066,12 @@ use self::sealed::Kind;
|
|||||||
|
|
||||||
#[cfg(any(usart_v1, usart_v2))]
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
fn tdr(r: crate::pac::usart::Usart) -> *mut u8 {
|
fn tdr(r: crate::pac::usart::Usart) -> *mut u8 {
|
||||||
r.dr().ptr() as _
|
r.dr().as_ptr() as _
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(usart_v1, usart_v2))]
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
|
fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
|
||||||
r.dr().ptr() as _
|
r.dr().as_ptr() as _
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(usart_v1, usart_v2))]
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
@ -1126,18 +1081,18 @@ fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::p
|
|||||||
|
|
||||||
#[cfg(any(usart_v1, usart_v2))]
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) {
|
fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) {
|
||||||
// On v1 the flags are cleared implicitly by reads and writes to DR.
|
// On v1 the flags are cleared implicitly by reads and writes to DR.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(usart_v3, usart_v4))]
|
#[cfg(any(usart_v3, usart_v4))]
|
||||||
fn tdr(r: Regs) -> *mut u8 {
|
fn tdr(r: Regs) -> *mut u8 {
|
||||||
r.tdr().ptr() as _
|
r.tdr().as_ptr() as _
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(usart_v3, usart_v4))]
|
#[cfg(any(usart_v3, usart_v4))]
|
||||||
fn rdr(r: Regs) -> *mut u8 {
|
fn rdr(r: Regs) -> *mut u8 {
|
||||||
r.rdr().ptr() as _
|
r.rdr().as_ptr() as _
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(usart_v3, usart_v4))]
|
#[cfg(any(usart_v3, usart_v4))]
|
||||||
@ -1147,7 +1102,7 @@ fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> {
|
|||||||
|
|
||||||
#[cfg(any(usart_v3, usart_v4))]
|
#[cfg(any(usart_v3, usart_v4))]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
|
fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
|
||||||
r.icr().write(|w| *w = regs::Icr(sr.0));
|
r.icr().write(|w| *w = regs::Icr(sr.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1214,7 +1169,7 @@ macro_rules! impl_usart {
|
|||||||
type Interrupt = crate::interrupt::typelevel::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
|
|
||||||
fn regs() -> Regs {
|
fn regs() -> Regs {
|
||||||
Regs(crate::pac::$inst.0)
|
unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state() -> &'static crate::usart::sealed::State {
|
fn state() -> &'static crate::usart::sealed::State {
|
||||||
|
@ -59,8 +59,6 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
|
|||||||
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
// clear all interrupts and DMA Rx Request
|
// clear all interrupts and DMA Rx Request
|
||||||
// SAFETY: only clears Rx related flags
|
|
||||||
unsafe {
|
|
||||||
r.cr1().modify(|w| {
|
r.cr1().modify(|w| {
|
||||||
// disable RXNE interrupt
|
// disable RXNE interrupt
|
||||||
w.set_rxneie(false);
|
w.set_rxneie(false);
|
||||||
@ -76,7 +74,6 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
|
|||||||
w.set_dmar(true);
|
w.set_dmar(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Stop uart background receive
|
/// Stop uart background receive
|
||||||
fn teardown_uart(&mut self) {
|
fn teardown_uart(&mut self) {
|
||||||
@ -84,8 +81,6 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
|
|||||||
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
// clear all interrupts and DMA Rx Request
|
// clear all interrupts and DMA Rx Request
|
||||||
// SAFETY: only clears Rx related flags
|
|
||||||
unsafe {
|
|
||||||
r.cr1().modify(|w| {
|
r.cr1().modify(|w| {
|
||||||
// disable RXNE interrupt
|
// disable RXNE interrupt
|
||||||
w.set_rxneie(false);
|
w.set_rxneie(false);
|
||||||
@ -100,7 +95,6 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
|
|||||||
// disable DMA Rx Request
|
// disable DMA Rx Request
|
||||||
w.set_dmar(false);
|
w.set_dmar(false);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
@ -117,8 +111,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
|
|||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
// Start background receive if it was not already started
|
// Start background receive if it was not already started
|
||||||
// SAFETY: read only
|
match r.cr3().read().dmar() {
|
||||||
match unsafe { r.cr3().read().dmar() } {
|
|
||||||
false => self.start()?,
|
false => self.start()?,
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
@ -213,20 +206,18 @@ fn check_for_errors(s: Sr) -> Result<(), Error> {
|
|||||||
|
|
||||||
/// Clear IDLE and return the Sr register
|
/// Clear IDLE and return the Sr register
|
||||||
fn clear_idle_flag(r: Regs) -> Sr {
|
fn clear_idle_flag(r: Regs) -> Sr {
|
||||||
unsafe {
|
|
||||||
// SAFETY: read only and we only use Rx related flags
|
// SAFETY: read only and we only use Rx related flags
|
||||||
|
|
||||||
let sr = sr(r).read();
|
let sr = sr(r).read();
|
||||||
|
|
||||||
// This read also clears the error and idle interrupt flags on v1.
|
// This read also clears the error and idle interrupt flags on v1.
|
||||||
rdr(r).read_volatile();
|
unsafe { rdr(r).read_volatile() };
|
||||||
clear_interrupt_flags(r, sr);
|
clear_interrupt_flags(r, sr);
|
||||||
|
|
||||||
r.cr1().modify(|w| w.set_idleie(true));
|
r.cr1().modify(|w| w.set_idleie(true));
|
||||||
|
|
||||||
sr
|
sr
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
|
#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
|
||||||
mod eio {
|
mod eio {
|
||||||
|
@ -28,7 +28,6 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
|
|
||||||
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
unsafe {
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
//let x = regs.istr().read().0;
|
//let x = regs.istr().read().0;
|
||||||
//trace!("USB IRQ: {:08x}", x);
|
//trace!("USB IRQ: {:08x}", x);
|
||||||
@ -106,7 +105,6 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const EP_COUNT: usize = 8;
|
const EP_COUNT: usize = 8;
|
||||||
|
|
||||||
@ -168,20 +166,20 @@ fn calc_out_len(len: u16) -> (u16, u16) {
|
|||||||
mod btable {
|
mod btable {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub(super) unsafe fn write_in<T: Instance>(index: usize, addr: u16) {
|
pub(super) fn write_in<T: Instance>(index: usize, addr: u16) {
|
||||||
USBRAM.mem(index * 4 + 0).write_value(addr);
|
USBRAM.mem(index * 4 + 0).write_value(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) unsafe fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) {
|
pub(super) fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) {
|
||||||
USBRAM.mem(index * 4 + 1).write_value(len);
|
USBRAM.mem(index * 4 + 1).write_value(len);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
|
pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
|
||||||
USBRAM.mem(index * 4 + 2).write_value(addr);
|
USBRAM.mem(index * 4 + 2).write_value(addr);
|
||||||
USBRAM.mem(index * 4 + 3).write_value(max_len_bits);
|
USBRAM.mem(index * 4 + 3).write_value(max_len_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 {
|
pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 {
|
||||||
USBRAM.mem(index * 4 + 3).read()
|
USBRAM.mem(index * 4 + 3).read()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,19 +187,19 @@ mod btable {
|
|||||||
mod btable {
|
mod btable {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub(super) unsafe fn write_in<T: Instance>(_index: usize, _addr: u16) {}
|
pub(super) fn write_in<T: Instance>(_index: usize, _addr: u16) {}
|
||||||
|
|
||||||
pub(super) unsafe fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) {
|
pub(super) fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) {
|
||||||
USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16));
|
USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
|
pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
|
||||||
USBRAM
|
USBRAM
|
||||||
.mem(index * 2 + 1)
|
.mem(index * 2 + 1)
|
||||||
.write_value((addr as u32) | ((max_len_bits as u32) << 16));
|
.write_value((addr as u32) | ((max_len_bits as u32) << 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 {
|
pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 {
|
||||||
(USBRAM.mem(index * 2 + 1).read() >> 16) as u16
|
(USBRAM.mem(index * 2 + 1).read() >> 16) as u16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,7 +214,7 @@ impl<T: Instance> EndpointBuffer<T> {
|
|||||||
fn read(&mut self, buf: &mut [u8]) {
|
fn read(&mut self, buf: &mut [u8]) {
|
||||||
assert!(buf.len() <= self.len as usize);
|
assert!(buf.len() <= self.len as usize);
|
||||||
for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN {
|
for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN {
|
||||||
let val = unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read() };
|
let val = USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read();
|
||||||
let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN);
|
let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN);
|
||||||
buf[i * USBRAM_ALIGN..][..n].copy_from_slice(&val.to_le_bytes()[..n]);
|
buf[i * USBRAM_ALIGN..][..n].copy_from_slice(&val.to_le_bytes()[..n]);
|
||||||
}
|
}
|
||||||
@ -233,7 +231,7 @@ impl<T: Instance> EndpointBuffer<T> {
|
|||||||
let val = u16::from_le_bytes(val);
|
let val = u16::from_le_bytes(val);
|
||||||
#[cfg(usbram_32_2048)]
|
#[cfg(usbram_32_2048)]
|
||||||
let val = u32::from_le_bytes(val);
|
let val = u32::from_le_bytes(val);
|
||||||
unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val) };
|
USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,17 +264,14 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
#[cfg(stm32l5)]
|
#[cfg(stm32l5)]
|
||||||
unsafe {
|
{
|
||||||
crate::peripherals::PWR::enable();
|
crate::peripherals::PWR::enable();
|
||||||
crate::pac::PWR.cr2().modify(|w| w.set_usv(true));
|
crate::pac::PWR.cr2().modify(|w| w.set_usv(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(pwr_h5)]
|
#[cfg(pwr_h5)]
|
||||||
unsafe {
|
crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true));
|
||||||
crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true))
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
<T as RccPeripheral>::enable();
|
<T as RccPeripheral>::enable();
|
||||||
<T as RccPeripheral>::reset();
|
<T as RccPeripheral>::reset();
|
||||||
|
|
||||||
@ -288,14 +283,13 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
#[cfg(time)]
|
#[cfg(time)]
|
||||||
embassy_time::block_for(embassy_time::Duration::from_millis(100));
|
embassy_time::block_for(embassy_time::Duration::from_millis(100));
|
||||||
#[cfg(not(time))]
|
#[cfg(not(time))]
|
||||||
cortex_m::asm::delay(crate::rcc::get_freqs().sys.0 / 10);
|
cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.0 / 10);
|
||||||
|
|
||||||
#[cfg(not(usb_v4))]
|
#[cfg(not(usb_v4))]
|
||||||
regs.btable().write(|w| w.set_btable(0));
|
regs.btable().write(|w| w.set_btable(0));
|
||||||
|
|
||||||
dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
|
dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
|
||||||
dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
|
dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the bus so that it signals that power is available
|
// Initialize the bus so that it signals that power is available
|
||||||
BUS_WAKER.wake();
|
BUS_WAKER.wake();
|
||||||
@ -363,7 +357,7 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
let addr = self.alloc_ep_mem(len);
|
let addr = self.alloc_ep_mem(len);
|
||||||
|
|
||||||
trace!(" len_bits = {:04x}", len_bits);
|
trace!(" len_bits = {:04x}", len_bits);
|
||||||
unsafe { btable::write_out::<T>(index, addr, len_bits) }
|
btable::write_out::<T>(index, addr, len_bits);
|
||||||
|
|
||||||
EndpointBuffer {
|
EndpointBuffer {
|
||||||
addr,
|
addr,
|
||||||
@ -379,7 +373,7 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
let addr = self.alloc_ep_mem(len);
|
let addr = self.alloc_ep_mem(len);
|
||||||
|
|
||||||
// ep_in_len is written when actually TXing packets.
|
// ep_in_len is written when actually TXing packets.
|
||||||
unsafe { btable::write_in::<T>(index, addr) }
|
btable::write_in::<T>(index, addr);
|
||||||
|
|
||||||
EndpointBuffer {
|
EndpointBuffer {
|
||||||
addr,
|
addr,
|
||||||
@ -440,7 +434,6 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
|||||||
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
regs.cntr().write(|w| {
|
regs.cntr().write(|w| {
|
||||||
w.set_pdwn(false);
|
w.set_pdwn(false);
|
||||||
w.set_fres(false);
|
w.set_fres(false);
|
||||||
@ -451,8 +444,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(any(usb_v3, usb_v4))]
|
#[cfg(any(usb_v3, usb_v4))]
|
||||||
regs.bcdr().write(|w| w.set_dppu(true))
|
regs.bcdr().write(|w| w.set_dppu(true));
|
||||||
}
|
|
||||||
|
|
||||||
trace!("enabled");
|
trace!("enabled");
|
||||||
|
|
||||||
@ -485,7 +477,7 @@ pub struct Bus<'d, T: Instance> {
|
|||||||
|
|
||||||
impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
||||||
async fn poll(&mut self) -> Event {
|
async fn poll(&mut self) -> Event {
|
||||||
poll_fn(move |cx| unsafe {
|
poll_fn(move |cx| {
|
||||||
BUS_WAKER.register(cx.waker());
|
BUS_WAKER.register(cx.waker());
|
||||||
|
|
||||||
if self.inited {
|
if self.inited {
|
||||||
@ -548,7 +540,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
match ep_addr.direction() {
|
match ep_addr.direction() {
|
||||||
Direction::In => {
|
Direction::In => {
|
||||||
loop {
|
loop {
|
||||||
let r = unsafe { reg.read() };
|
let r = reg.read();
|
||||||
match r.stat_tx() {
|
match r.stat_tx() {
|
||||||
Stat::DISABLED => break, // if disabled, stall does nothing.
|
Stat::DISABLED => break, // if disabled, stall does nothing.
|
||||||
Stat::STALL => break, // done!
|
Stat::STALL => break, // done!
|
||||||
@ -559,7 +551,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
};
|
};
|
||||||
let mut w = invariant(r);
|
let mut w = invariant(r);
|
||||||
w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0));
|
w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0));
|
||||||
unsafe { reg.write_value(w) };
|
reg.write_value(w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -567,7 +559,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
}
|
}
|
||||||
Direction::Out => {
|
Direction::Out => {
|
||||||
loop {
|
loop {
|
||||||
let r = unsafe { reg.read() };
|
let r = reg.read();
|
||||||
match r.stat_rx() {
|
match r.stat_rx() {
|
||||||
Stat::DISABLED => break, // if disabled, stall does nothing.
|
Stat::DISABLED => break, // if disabled, stall does nothing.
|
||||||
Stat::STALL => break, // done!
|
Stat::STALL => break, // done!
|
||||||
@ -578,7 +570,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
};
|
};
|
||||||
let mut w = invariant(r);
|
let mut w = invariant(r);
|
||||||
w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0));
|
w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0));
|
||||||
unsafe { reg.write_value(w) };
|
reg.write_value(w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -589,7 +581,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
|
|
||||||
fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
|
fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let epr = unsafe { regs.epr(ep_addr.index() as _).read() };
|
let epr = regs.epr(ep_addr.index() as _).read();
|
||||||
match ep_addr.direction() {
|
match ep_addr.direction() {
|
||||||
Direction::In => epr.stat_tx() == Stat::STALL,
|
Direction::In => epr.stat_tx() == Stat::STALL,
|
||||||
Direction::Out => epr.stat_rx() == Stat::STALL,
|
Direction::Out => epr.stat_rx() == Stat::STALL,
|
||||||
@ -600,7 +592,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
trace!("set_enabled {:x} {}", ep_addr, enabled);
|
trace!("set_enabled {:x} {}", ep_addr, enabled);
|
||||||
// This can race, so do a retry loop.
|
// This can race, so do a retry loop.
|
||||||
let reg = T::regs().epr(ep_addr.index() as _);
|
let reg = T::regs().epr(ep_addr.index() as _);
|
||||||
trace!("EPR before: {:04x}", unsafe { reg.read() }.0);
|
trace!("EPR before: {:04x}", reg.read().0);
|
||||||
match ep_addr.direction() {
|
match ep_addr.direction() {
|
||||||
Direction::In => {
|
Direction::In => {
|
||||||
loop {
|
loop {
|
||||||
@ -608,13 +600,13 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
false => Stat::DISABLED,
|
false => Stat::DISABLED,
|
||||||
true => Stat::NAK,
|
true => Stat::NAK,
|
||||||
};
|
};
|
||||||
let r = unsafe { reg.read() };
|
let r = reg.read();
|
||||||
if r.stat_tx() == want_stat {
|
if r.stat_tx() == want_stat {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let mut w = invariant(r);
|
let mut w = invariant(r);
|
||||||
w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0));
|
w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0));
|
||||||
unsafe { reg.write_value(w) };
|
reg.write_value(w);
|
||||||
}
|
}
|
||||||
EP_IN_WAKERS[ep_addr.index()].wake();
|
EP_IN_WAKERS[ep_addr.index()].wake();
|
||||||
}
|
}
|
||||||
@ -624,18 +616,18 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
false => Stat::DISABLED,
|
false => Stat::DISABLED,
|
||||||
true => Stat::VALID,
|
true => Stat::VALID,
|
||||||
};
|
};
|
||||||
let r = unsafe { reg.read() };
|
let r = reg.read();
|
||||||
if r.stat_rx() == want_stat {
|
if r.stat_rx() == want_stat {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let mut w = invariant(r);
|
let mut w = invariant(r);
|
||||||
w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0));
|
w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0));
|
||||||
unsafe { reg.write_value(w) };
|
reg.write_value(w);
|
||||||
}
|
}
|
||||||
EP_OUT_WAKERS[ep_addr.index()].wake();
|
EP_OUT_WAKERS[ep_addr.index()].wake();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trace!("EPR after: {:04x}", unsafe { reg.read() }.0);
|
trace!("EPR after: {:04x}", reg.read().0);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn enable(&mut self) {}
|
async fn enable(&mut self) {}
|
||||||
@ -685,12 +677,12 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> {
|
|||||||
fn write_data(&mut self, buf: &[u8]) {
|
fn write_data(&mut self, buf: &[u8]) {
|
||||||
let index = self.info.addr.index();
|
let index = self.info.addr.index();
|
||||||
self.buf.write(buf);
|
self.buf.write(buf);
|
||||||
unsafe { btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _) }
|
btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
|
fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
|
||||||
let index = self.info.addr.index();
|
let index = self.info.addr.index();
|
||||||
let rx_len = unsafe { btable::read_out_len::<T>(index) as usize } & 0x3FF;
|
let rx_len = btable::read_out_len::<T>(index) as usize & 0x3FF;
|
||||||
trace!("READ DONE, rx_len = {}", rx_len);
|
trace!("READ DONE, rx_len = {}", rx_len);
|
||||||
if rx_len > buf.len() {
|
if rx_len > buf.len() {
|
||||||
return Err(EndpointError::BufferOverflow);
|
return Err(EndpointError::BufferOverflow);
|
||||||
@ -711,7 +703,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
|
|||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
EP_OUT_WAKERS[index].register(cx.waker());
|
EP_OUT_WAKERS[index].register(cx.waker());
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
if unsafe { regs.epr(index).read() }.stat_tx() == Stat::DISABLED {
|
if regs.epr(index).read().stat_tx() == Stat::DISABLED {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
} else {
|
} else {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
@ -733,7 +725,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> {
|
|||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
EP_OUT_WAKERS[index].register(cx.waker());
|
EP_OUT_WAKERS[index].register(cx.waker());
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
if unsafe { regs.epr(index).read() }.stat_rx() == Stat::DISABLED {
|
if regs.epr(index).read().stat_rx() == Stat::DISABLED {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
} else {
|
} else {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
@ -751,7 +743,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
|
|||||||
let stat = poll_fn(|cx| {
|
let stat = poll_fn(|cx| {
|
||||||
EP_OUT_WAKERS[index].register(cx.waker());
|
EP_OUT_WAKERS[index].register(cx.waker());
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let stat = unsafe { regs.epr(index).read() }.stat_rx();
|
let stat = regs.epr(index).read().stat_rx();
|
||||||
if matches!(stat, Stat::NAK | Stat::DISABLED) {
|
if matches!(stat, Stat::NAK | Stat::DISABLED) {
|
||||||
Poll::Ready(stat)
|
Poll::Ready(stat)
|
||||||
} else {
|
} else {
|
||||||
@ -767,7 +759,6 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
|
|||||||
let rx_len = self.read_data(buf)?;
|
let rx_len = self.read_data(buf)?;
|
||||||
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
unsafe {
|
|
||||||
regs.epr(index).write(|w| {
|
regs.epr(index).write(|w| {
|
||||||
w.set_ep_type(convert_type(self.info.ep_type));
|
w.set_ep_type(convert_type(self.info.ep_type));
|
||||||
w.set_ea(self.info.addr.index() as _);
|
w.set_ea(self.info.addr.index() as _);
|
||||||
@ -775,8 +766,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
|
|||||||
w.set_stat_tx(Stat(0));
|
w.set_stat_tx(Stat(0));
|
||||||
w.set_ctr_rx(true); // don't clear
|
w.set_ctr_rx(true); // don't clear
|
||||||
w.set_ctr_tx(true); // don't clear
|
w.set_ctr_tx(true); // don't clear
|
||||||
})
|
});
|
||||||
};
|
|
||||||
trace!("READ OK, rx_len = {}", rx_len);
|
trace!("READ OK, rx_len = {}", rx_len);
|
||||||
|
|
||||||
Ok(rx_len)
|
Ok(rx_len)
|
||||||
@ -795,7 +785,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
|
|||||||
let stat = poll_fn(|cx| {
|
let stat = poll_fn(|cx| {
|
||||||
EP_IN_WAKERS[index].register(cx.waker());
|
EP_IN_WAKERS[index].register(cx.waker());
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let stat = unsafe { regs.epr(index).read() }.stat_tx();
|
let stat = regs.epr(index).read().stat_tx();
|
||||||
if matches!(stat, Stat::NAK | Stat::DISABLED) {
|
if matches!(stat, Stat::NAK | Stat::DISABLED) {
|
||||||
Poll::Ready(stat)
|
Poll::Ready(stat)
|
||||||
} else {
|
} else {
|
||||||
@ -811,7 +801,6 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
|
|||||||
self.write_data(buf);
|
self.write_data(buf);
|
||||||
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
unsafe {
|
|
||||||
regs.epr(index).write(|w| {
|
regs.epr(index).write(|w| {
|
||||||
w.set_ep_type(convert_type(self.info.ep_type));
|
w.set_ep_type(convert_type(self.info.ep_type));
|
||||||
w.set_ea(self.info.addr.index() as _);
|
w.set_ea(self.info.addr.index() as _);
|
||||||
@ -819,8 +808,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
|
|||||||
w.set_stat_rx(Stat(0));
|
w.set_stat_rx(Stat(0));
|
||||||
w.set_ctr_rx(true); // don't clear
|
w.set_ctr_rx(true); // don't clear
|
||||||
w.set_ctr_tx(true); // don't clear
|
w.set_ctr_tx(true); // don't clear
|
||||||
})
|
});
|
||||||
};
|
|
||||||
|
|
||||||
trace!("WRITE OK");
|
trace!("WRITE OK");
|
||||||
|
|
||||||
@ -889,22 +877,20 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
}
|
}
|
||||||
// Note: if this is the first AND last transfer, the above effectively
|
// Note: if this is the first AND last transfer, the above effectively
|
||||||
// changes stat_tx like NAK -> NAK, so noop.
|
// changes stat_tx like NAK -> NAK, so noop.
|
||||||
unsafe {
|
|
||||||
regs.epr(0).write(|w| {
|
regs.epr(0).write(|w| {
|
||||||
w.set_ep_type(EpType::CONTROL);
|
w.set_ep_type(EpType::CONTROL);
|
||||||
w.set_stat_rx(Stat(stat_rx));
|
w.set_stat_rx(Stat(stat_rx));
|
||||||
w.set_stat_tx(Stat(stat_tx));
|
w.set_stat_tx(Stat(stat_tx));
|
||||||
w.set_ctr_rx(true); // don't clear
|
w.set_ctr_rx(true); // don't clear
|
||||||
w.set_ctr_tx(true); // don't clear
|
w.set_ctr_tx(true); // don't clear
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("data_out WAITING, buf.len() = {}", buf.len());
|
trace!("data_out WAITING, buf.len() = {}", buf.len());
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
EP_OUT_WAKERS[0].register(cx.waker());
|
EP_OUT_WAKERS[0].register(cx.waker());
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
if unsafe { regs.epr(0).read() }.stat_rx() == Stat::NAK {
|
if regs.epr(0).read().stat_rx() == Stat::NAK {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
} else {
|
} else {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
@ -919,7 +905,6 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
|
|
||||||
let rx_len = self.ep_out.read_data(buf)?;
|
let rx_len = self.ep_out.read_data(buf)?;
|
||||||
|
|
||||||
unsafe {
|
|
||||||
regs.epr(0).write(|w| {
|
regs.epr(0).write(|w| {
|
||||||
w.set_ep_type(EpType::CONTROL);
|
w.set_ep_type(EpType::CONTROL);
|
||||||
w.set_stat_rx(Stat(match last {
|
w.set_stat_rx(Stat(match last {
|
||||||
@ -930,8 +915,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
}));
|
}));
|
||||||
w.set_ctr_rx(true); // don't clear
|
w.set_ctr_rx(true); // don't clear
|
||||||
w.set_ctr_tx(true); // don't clear
|
w.set_ctr_tx(true); // don't clear
|
||||||
})
|
});
|
||||||
};
|
|
||||||
|
|
||||||
Ok(rx_len)
|
Ok(rx_len)
|
||||||
}
|
}
|
||||||
@ -960,15 +944,13 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
}
|
}
|
||||||
// Note: if this is the first AND last transfer, the above effectively
|
// Note: if this is the first AND last transfer, the above effectively
|
||||||
// does a change of NAK -> VALID.
|
// does a change of NAK -> VALID.
|
||||||
unsafe {
|
|
||||||
regs.epr(0).write(|w| {
|
regs.epr(0).write(|w| {
|
||||||
w.set_ep_type(EpType::CONTROL);
|
w.set_ep_type(EpType::CONTROL);
|
||||||
w.set_stat_rx(Stat(stat_rx));
|
w.set_stat_rx(Stat(stat_rx));
|
||||||
w.set_ep_kind(last); // set OUT_STATUS if last.
|
w.set_ep_kind(last); // set OUT_STATUS if last.
|
||||||
w.set_ctr_rx(true); // don't clear
|
w.set_ctr_rx(true); // don't clear
|
||||||
w.set_ctr_tx(true); // don't clear
|
w.set_ctr_tx(true); // don't clear
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("WRITE WAITING");
|
trace!("WRITE WAITING");
|
||||||
@ -976,7 +958,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
EP_IN_WAKERS[0].register(cx.waker());
|
EP_IN_WAKERS[0].register(cx.waker());
|
||||||
EP_OUT_WAKERS[0].register(cx.waker());
|
EP_OUT_WAKERS[0].register(cx.waker());
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK {
|
if regs.epr(0).read().stat_tx() == Stat::NAK {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
} else {
|
} else {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
@ -992,15 +974,13 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
self.ep_in.write_data(data);
|
self.ep_in.write_data(data);
|
||||||
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
unsafe {
|
|
||||||
regs.epr(0).write(|w| {
|
regs.epr(0).write(|w| {
|
||||||
w.set_ep_type(EpType::CONTROL);
|
w.set_ep_type(EpType::CONTROL);
|
||||||
w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
|
w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
|
||||||
w.set_ep_kind(last); // set OUT_STATUS if last.
|
w.set_ep_kind(last); // set OUT_STATUS if last.
|
||||||
w.set_ctr_rx(true); // don't clear
|
w.set_ctr_rx(true); // don't clear
|
||||||
w.set_ctr_tx(true); // don't clear
|
w.set_ctr_tx(true); // don't clear
|
||||||
})
|
});
|
||||||
};
|
|
||||||
|
|
||||||
trace!("WRITE OK");
|
trace!("WRITE OK");
|
||||||
|
|
||||||
@ -1014,7 +994,6 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
self.ep_in.write_data(&[]);
|
self.ep_in.write_data(&[]);
|
||||||
|
|
||||||
// Set OUT=stall, IN=accept
|
// Set OUT=stall, IN=accept
|
||||||
unsafe {
|
|
||||||
let epr = regs.epr(0).read();
|
let epr = regs.epr(0).read();
|
||||||
regs.epr(0).write(|w| {
|
regs.epr(0).write(|w| {
|
||||||
w.set_ep_type(EpType::CONTROL);
|
w.set_ep_type(EpType::CONTROL);
|
||||||
@ -1023,7 +1002,6 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
w.set_ctr_rx(true); // don't clear
|
w.set_ctr_rx(true); // don't clear
|
||||||
w.set_ctr_tx(true); // don't clear
|
w.set_ctr_tx(true); // don't clear
|
||||||
});
|
});
|
||||||
}
|
|
||||||
trace!("control: accept WAITING");
|
trace!("control: accept WAITING");
|
||||||
|
|
||||||
// Wait is needed, so that we don't set the address too soon, breaking the status stage.
|
// Wait is needed, so that we don't set the address too soon, breaking the status stage.
|
||||||
@ -1031,7 +1009,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
EP_IN_WAKERS[0].register(cx.waker());
|
EP_IN_WAKERS[0].register(cx.waker());
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK {
|
if regs.epr(0).read().stat_tx() == Stat::NAK {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
} else {
|
} else {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
@ -1047,7 +1025,6 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
trace!("control: reject");
|
trace!("control: reject");
|
||||||
|
|
||||||
// Set IN+OUT to stall
|
// Set IN+OUT to stall
|
||||||
unsafe {
|
|
||||||
let epr = regs.epr(0).read();
|
let epr = regs.epr(0).read();
|
||||||
regs.epr(0).write(|w| {
|
regs.epr(0).write(|w| {
|
||||||
w.set_ep_type(EpType::CONTROL);
|
w.set_ep_type(EpType::CONTROL);
|
||||||
@ -1057,18 +1034,15 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
w.set_ctr_tx(true); // don't clear
|
w.set_ctr_tx(true); // don't clear
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
async fn accept_set_address(&mut self, addr: u8) {
|
async fn accept_set_address(&mut self, addr: u8) {
|
||||||
self.accept().await;
|
self.accept().await;
|
||||||
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
trace!("setting addr: {}", addr);
|
trace!("setting addr: {}", addr);
|
||||||
unsafe {
|
|
||||||
regs.daddr().write(|w| {
|
regs.daddr().write(|w| {
|
||||||
w.set_ef(true);
|
w.set_ef(true);
|
||||||
w.set_add(addr);
|
w.set_add(addr);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,7 +148,7 @@ foreach_interrupt!(
|
|||||||
|
|
||||||
fn regs() -> crate::pac::otg::Otg {
|
fn regs() -> crate::pac::otg::Otg {
|
||||||
// OTG HS registers are a superset of FS registers
|
// OTG HS registers are a superset of FS registers
|
||||||
crate::pac::otg::Otg(crate::pac::USB_OTG_HS.0)
|
unsafe { crate::pac::otg::Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
|
@ -30,19 +30,16 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
|||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
let state = T::state();
|
let state = T::state();
|
||||||
|
|
||||||
// SAFETY: atomic read/write
|
let ints = r.gintsts().read();
|
||||||
let ints = unsafe { r.gintsts().read() };
|
|
||||||
if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() {
|
if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() {
|
||||||
// Mask interrupts and notify `Bus` to process them
|
// Mask interrupts and notify `Bus` to process them
|
||||||
unsafe { r.gintmsk().write(|_| {}) };
|
r.gintmsk().write(|_| {});
|
||||||
T::state().bus_waker.wake();
|
T::state().bus_waker.wake();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle RX
|
// Handle RX
|
||||||
// SAFETY: atomic read with no side effects
|
while r.gintsts().read().rxflvl() {
|
||||||
while unsafe { r.gintsts().read().rxflvl() } {
|
let status = r.grxstsp().read();
|
||||||
// SAFETY: atomic "pop" register
|
|
||||||
let status = unsafe { r.grxstsp().read() };
|
|
||||||
let ep_num = status.epnum() as usize;
|
let ep_num = status.epnum() as usize;
|
||||||
let len = status.bcnt() as usize;
|
let len = status.bcnt() as usize;
|
||||||
|
|
||||||
@ -57,23 +54,17 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
|||||||
if state.ep0_setup_ready.load(Ordering::Relaxed) == false {
|
if state.ep0_setup_ready.load(Ordering::Relaxed) == false {
|
||||||
// SAFETY: exclusive access ensured by atomic bool
|
// SAFETY: exclusive access ensured by atomic bool
|
||||||
let data = unsafe { &mut *state.ep0_setup_data.get() };
|
let data = unsafe { &mut *state.ep0_setup_data.get() };
|
||||||
// SAFETY: FIFO reads are exclusive to this IRQ
|
|
||||||
unsafe {
|
|
||||||
data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
|
data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
|
||||||
data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
|
data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
|
||||||
}
|
|
||||||
state.ep0_setup_ready.store(true, Ordering::Release);
|
state.ep0_setup_ready.store(true, Ordering::Release);
|
||||||
state.ep_out_wakers[0].wake();
|
state.ep_out_wakers[0].wake();
|
||||||
} else {
|
} else {
|
||||||
error!("received SETUP before previous finished processing");
|
error!("received SETUP before previous finished processing");
|
||||||
// discard FIFO
|
// discard FIFO
|
||||||
// SAFETY: FIFO reads are exclusive to IRQ
|
|
||||||
unsafe {
|
|
||||||
r.fifo(0).read();
|
r.fifo(0).read();
|
||||||
r.fifo(0).read();
|
r.fifo(0).read();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
vals::Pktstsd::OUT_DATA_RX => {
|
vals::Pktstsd::OUT_DATA_RX => {
|
||||||
trace!("OUT_DATA_RX ep={} len={}", ep_num, len);
|
trace!("OUT_DATA_RX ep={} len={}", ep_num, len);
|
||||||
|
|
||||||
@ -84,8 +75,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
|||||||
|
|
||||||
for chunk in buf.chunks_mut(4) {
|
for chunk in buf.chunks_mut(4) {
|
||||||
// RX FIFO is shared so always read from fifo(0)
|
// RX FIFO is shared so always read from fifo(0)
|
||||||
// SAFETY: FIFO reads are exclusive to IRQ
|
let data = r.fifo(0).read().0;
|
||||||
let data = unsafe { r.fifo(0).read().0 };
|
|
||||||
chunk.copy_from_slice(&data.to_ne_bytes()[0..chunk.len()]);
|
chunk.copy_from_slice(&data.to_ne_bytes()[0..chunk.len()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,8 +87,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
|||||||
// discard FIFO data
|
// discard FIFO data
|
||||||
let len_words = (len + 3) / 4;
|
let len_words = (len + 3) / 4;
|
||||||
for _ in 0..len_words {
|
for _ in 0..len_words {
|
||||||
// SAFETY: FIFO reads are exclusive to IRQ
|
r.fifo(0).read().data();
|
||||||
unsafe { r.fifo(0).read().data() };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,24 +103,20 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
|||||||
|
|
||||||
// IN endpoint interrupt
|
// IN endpoint interrupt
|
||||||
if ints.iepint() {
|
if ints.iepint() {
|
||||||
// SAFETY: atomic read with no side effects
|
let mut ep_mask = r.daint().read().iepint();
|
||||||
let mut ep_mask = unsafe { r.daint().read().iepint() };
|
|
||||||
let mut ep_num = 0;
|
let mut ep_num = 0;
|
||||||
|
|
||||||
// Iterate over endpoints while there are non-zero bits in the mask
|
// Iterate over endpoints while there are non-zero bits in the mask
|
||||||
while ep_mask != 0 {
|
while ep_mask != 0 {
|
||||||
if ep_mask & 1 != 0 {
|
if ep_mask & 1 != 0 {
|
||||||
// SAFETY: atomic read with no side effects
|
let ep_ints = r.diepint(ep_num).read();
|
||||||
let ep_ints = unsafe { r.diepint(ep_num).read() };
|
|
||||||
|
|
||||||
// clear all
|
// clear all
|
||||||
// SAFETY: DIEPINT is exclusive to IRQ
|
r.diepint(ep_num).write_value(ep_ints);
|
||||||
unsafe { r.diepint(ep_num).write_value(ep_ints) };
|
|
||||||
|
|
||||||
// TXFE is cleared in DIEPEMPMSK
|
// TXFE is cleared in DIEPEMPMSK
|
||||||
if ep_ints.txfe() {
|
if ep_ints.txfe() {
|
||||||
// SAFETY: DIEPEMPMSK is shared with `Endpoint` so critical section is needed for RMW
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
r.diepempmsk().modify(|w| {
|
r.diepempmsk().modify(|w| {
|
||||||
w.set_ineptxfem(w.ineptxfem() & !(1 << ep_num));
|
w.set_ineptxfem(w.ineptxfem() & !(1 << ep_num));
|
||||||
});
|
});
|
||||||
@ -172,8 +157,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
|||||||
macro_rules! config_ulpi_pins {
|
macro_rules! config_ulpi_pins {
|
||||||
($($pin:ident),*) => {
|
($($pin:ident),*) => {
|
||||||
into_ref!($($pin),*);
|
into_ref!($($pin),*);
|
||||||
// NOTE(unsafe) Exclusive access to the registers
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
$(
|
$(
|
||||||
$pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
|
$pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
|
||||||
#[cfg(gpio_v2)]
|
#[cfg(gpio_v2)]
|
||||||
@ -298,10 +282,8 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(dp, dm);
|
into_ref!(dp, dm);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
|
dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
|
||||||
dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
|
dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
@ -508,8 +490,6 @@ pub struct Bus<'d, T: Instance> {
|
|||||||
|
|
||||||
impl<'d, T: Instance> Bus<'d, T> {
|
impl<'d, T: Instance> Bus<'d, T> {
|
||||||
fn restore_irqs() {
|
fn restore_irqs() {
|
||||||
// SAFETY: atomic write
|
|
||||||
unsafe {
|
|
||||||
T::regs().gintmsk().write(|w| {
|
T::regs().gintmsk().write(|w| {
|
||||||
w.set_usbrst(true);
|
w.set_usbrst(true);
|
||||||
w.set_enumdnem(true);
|
w.set_enumdnem(true);
|
||||||
@ -521,7 +501,6 @@ impl<'d, T: Instance> Bus<'d, T> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> Bus<'d, T> {
|
impl<'d, T: Instance> Bus<'d, T> {
|
||||||
fn init_fifo(&mut self) {
|
fn init_fifo(&mut self) {
|
||||||
@ -533,8 +512,7 @@ impl<'d, T: Instance> Bus<'d, T> {
|
|||||||
let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out);
|
let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out);
|
||||||
trace!("configuring rx fifo size={}", rx_fifo_size_words);
|
trace!("configuring rx fifo size={}", rx_fifo_size_words);
|
||||||
|
|
||||||
// SAFETY: register is exclusive to `Bus` with `&mut self`
|
r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words));
|
||||||
unsafe { r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)) };
|
|
||||||
|
|
||||||
// Configure TX (USB in direction) fifo size for each endpoint
|
// Configure TX (USB in direction) fifo size for each endpoint
|
||||||
let mut fifo_top = rx_fifo_size_words;
|
let mut fifo_top = rx_fifo_size_words;
|
||||||
@ -549,13 +527,10 @@ impl<'d, T: Instance> Bus<'d, T> {
|
|||||||
|
|
||||||
let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) };
|
let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) };
|
||||||
|
|
||||||
// SAFETY: register is exclusive to `Bus` with `&mut self`
|
|
||||||
unsafe {
|
|
||||||
dieptxf.write(|w| {
|
dieptxf.write(|w| {
|
||||||
w.set_fd(ep.fifo_size_words);
|
w.set_fd(ep.fifo_size_words);
|
||||||
w.set_sa(fifo_top);
|
w.set_sa(fifo_top);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
fifo_top += ep.fifo_size_words;
|
fifo_top += ep.fifo_size_words;
|
||||||
}
|
}
|
||||||
@ -575,8 +550,7 @@ impl<'d, T: Instance> Bus<'d, T> {
|
|||||||
// Configure IN endpoints
|
// Configure IN endpoints
|
||||||
for (index, ep) in self.ep_in.iter().enumerate() {
|
for (index, ep) in self.ep_in.iter().enumerate() {
|
||||||
if let Some(ep) = ep {
|
if let Some(ep) = ep {
|
||||||
// SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
r.diepctl(index).write(|w| {
|
r.diepctl(index).write(|w| {
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
|
w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
|
||||||
@ -593,8 +567,7 @@ impl<'d, T: Instance> Bus<'d, T> {
|
|||||||
// Configure OUT endpoints
|
// Configure OUT endpoints
|
||||||
for (index, ep) in self.ep_out.iter().enumerate() {
|
for (index, ep) in self.ep_out.iter().enumerate() {
|
||||||
if let Some(ep) = ep {
|
if let Some(ep) = ep {
|
||||||
// SAFETY: DOEPCTL/DOEPTSIZ is shared with `Endpoint` so critical section is needed for RMW
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
r.doepctl(index).write(|w| {
|
r.doepctl(index).write(|w| {
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
|
w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
|
||||||
@ -618,15 +591,12 @@ impl<'d, T: Instance> Bus<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Enable IRQs for allocated endpoints
|
// Enable IRQs for allocated endpoints
|
||||||
// SAFETY: register is exclusive to `Bus` with `&mut self`
|
|
||||||
unsafe {
|
|
||||||
r.daintmsk().modify(|w| {
|
r.daintmsk().modify(|w| {
|
||||||
w.set_iepm(ep_irq_mask(&self.ep_in));
|
w.set_iepm(ep_irq_mask(&self.ep_in));
|
||||||
// OUT interrupts not used, handled in RXFLVL
|
// OUT interrupts not used, handled in RXFLVL
|
||||||
// w.set_oepm(ep_irq_mask(&self.ep_out));
|
// w.set_oepm(ep_irq_mask(&self.ep_out));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn disable(&mut self) {
|
fn disable(&mut self) {
|
||||||
T::Interrupt::disable();
|
T::Interrupt::disable();
|
||||||
@ -634,12 +604,10 @@ impl<'d, T: Instance> Bus<'d, T> {
|
|||||||
<T as RccPeripheral>::disable();
|
<T as RccPeripheral>::disable();
|
||||||
|
|
||||||
#[cfg(stm32l4)]
|
#[cfg(stm32l4)]
|
||||||
unsafe {
|
|
||||||
crate::pac::PWR.cr2().modify(|w| w.set_usv(false));
|
crate::pac::PWR.cr2().modify(|w| w.set_usv(false));
|
||||||
// Cannot disable PWR, because other peripherals might be using it
|
// Cannot disable PWR, because other peripherals might be using it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
|
impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
|
||||||
async fn poll(&mut self) -> Event {
|
async fn poll(&mut self) -> Event {
|
||||||
@ -653,7 +621,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
|
|||||||
|
|
||||||
T::state().bus_waker.register(cx.waker());
|
T::state().bus_waker.register(cx.waker());
|
||||||
|
|
||||||
let ints = unsafe { r.gintsts().read() };
|
let ints = r.gintsts().read();
|
||||||
if ints.usbrst() {
|
if ints.usbrst() {
|
||||||
trace!("reset");
|
trace!("reset");
|
||||||
|
|
||||||
@ -661,34 +629,27 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
|
|||||||
self.configure_endpoints();
|
self.configure_endpoints();
|
||||||
|
|
||||||
// Reset address
|
// Reset address
|
||||||
// SAFETY: DCFG is shared with `ControlPipe` so critical section is needed for RMW
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
r.dcfg().modify(|w| {
|
r.dcfg().modify(|w| {
|
||||||
w.set_dad(0);
|
w.set_dad(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// SAFETY: atomic clear on rc_w1 register
|
r.gintsts().write(|w| w.set_usbrst(true)); // clear
|
||||||
unsafe { r.gintsts().write(|w| w.set_usbrst(true)) }; // clear
|
|
||||||
Self::restore_irqs();
|
Self::restore_irqs();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ints.enumdne() {
|
if ints.enumdne() {
|
||||||
trace!("enumdne");
|
trace!("enumdne");
|
||||||
|
|
||||||
// SAFETY: atomic read with no side effects
|
let speed = r.dsts().read().enumspd();
|
||||||
let speed = unsafe { r.dsts().read().enumspd() };
|
|
||||||
trace!(" speed={}", speed.0);
|
trace!(" speed={}", speed.0);
|
||||||
|
|
||||||
// SAFETY: register is only accessed by `Bus` under `&mut self`
|
|
||||||
unsafe {
|
|
||||||
r.gusbcfg().modify(|w| {
|
r.gusbcfg().modify(|w| {
|
||||||
w.set_trdt(calculate_trdt(speed, T::frequency()));
|
w.set_trdt(calculate_trdt(speed, T::frequency()));
|
||||||
})
|
});
|
||||||
};
|
|
||||||
|
|
||||||
// SAFETY: atomic clear on rc_w1 register
|
r.gintsts().write(|w| w.set_enumdne(true)); // clear
|
||||||
unsafe { r.gintsts().write(|w| w.set_enumdne(true)) }; // clear
|
|
||||||
Self::restore_irqs();
|
Self::restore_irqs();
|
||||||
|
|
||||||
return Poll::Ready(Event::Reset);
|
return Poll::Ready(Event::Reset);
|
||||||
@ -696,16 +657,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
|
|||||||
|
|
||||||
if ints.usbsusp() {
|
if ints.usbsusp() {
|
||||||
trace!("suspend");
|
trace!("suspend");
|
||||||
// SAFETY: atomic clear on rc_w1 register
|
r.gintsts().write(|w| w.set_usbsusp(true)); // clear
|
||||||
unsafe { r.gintsts().write(|w| w.set_usbsusp(true)) }; // clear
|
|
||||||
Self::restore_irqs();
|
Self::restore_irqs();
|
||||||
return Poll::Ready(Event::Suspend);
|
return Poll::Ready(Event::Suspend);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ints.wkupint() {
|
if ints.wkupint() {
|
||||||
trace!("resume");
|
trace!("resume");
|
||||||
// SAFETY: atomic clear on rc_w1 register
|
r.gintsts().write(|w| w.set_wkupint(true)); // clear
|
||||||
unsafe { r.gintsts().write(|w| w.set_wkupint(true)) }; // clear
|
|
||||||
Self::restore_irqs();
|
Self::restore_irqs();
|
||||||
return Poll::Ready(Event::Resume);
|
return Poll::Ready(Event::Resume);
|
||||||
}
|
}
|
||||||
@ -727,8 +686,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
|
|||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
match ep_addr.direction() {
|
match ep_addr.direction() {
|
||||||
Direction::Out => {
|
Direction::Out => {
|
||||||
// SAFETY: DOEPCTL is shared with `Endpoint` so critical section is needed for RMW
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
regs.doepctl(ep_addr.index()).modify(|w| {
|
regs.doepctl(ep_addr.index()).modify(|w| {
|
||||||
w.set_stall(stalled);
|
w.set_stall(stalled);
|
||||||
});
|
});
|
||||||
@ -737,8 +695,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
|
|||||||
T::state().ep_out_wakers[ep_addr.index()].wake();
|
T::state().ep_out_wakers[ep_addr.index()].wake();
|
||||||
}
|
}
|
||||||
Direction::In => {
|
Direction::In => {
|
||||||
// SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
regs.diepctl(ep_addr.index()).modify(|w| {
|
regs.diepctl(ep_addr.index()).modify(|w| {
|
||||||
w.set_stall(stalled);
|
w.set_stall(stalled);
|
||||||
});
|
});
|
||||||
@ -758,10 +715,9 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
|
|||||||
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
// SAFETY: atomic read with no side effects
|
|
||||||
match ep_addr.direction() {
|
match ep_addr.direction() {
|
||||||
Direction::Out => unsafe { regs.doepctl(ep_addr.index()).read().stall() },
|
Direction::Out => regs.doepctl(ep_addr.index()).read().stall(),
|
||||||
Direction::In => unsafe { regs.diepctl(ep_addr.index()).read().stall() },
|
Direction::In => regs.diepctl(ep_addr.index()).read().stall(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -777,8 +733,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
|
|||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
match ep_addr.direction() {
|
match ep_addr.direction() {
|
||||||
Direction::Out => {
|
Direction::Out => {
|
||||||
// SAFETY: DOEPCTL is shared with `Endpoint` so critical section is needed for RMW
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
// cancel transfer if active
|
// cancel transfer if active
|
||||||
if !enabled && r.doepctl(ep_addr.index()).read().epena() {
|
if !enabled && r.doepctl(ep_addr.index()).read().epena() {
|
||||||
r.doepctl(ep_addr.index()).modify(|w| {
|
r.doepctl(ep_addr.index()).modify(|w| {
|
||||||
@ -796,8 +751,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
|
|||||||
T::state().ep_out_wakers[ep_addr.index()].wake();
|
T::state().ep_out_wakers[ep_addr.index()].wake();
|
||||||
}
|
}
|
||||||
Direction::In => {
|
Direction::In => {
|
||||||
// SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
// cancel transfer if active
|
// cancel transfer if active
|
||||||
if !enabled && r.diepctl(ep_addr.index()).read().epena() {
|
if !enabled && r.diepctl(ep_addr.index()).read().epena() {
|
||||||
r.diepctl(ep_addr.index()).modify(|w| {
|
r.diepctl(ep_addr.index()).modify(|w| {
|
||||||
@ -820,8 +774,6 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
|
|||||||
async fn enable(&mut self) {
|
async fn enable(&mut self) {
|
||||||
trace!("enable");
|
trace!("enable");
|
||||||
|
|
||||||
// SAFETY: registers are only accessed by `Bus` under `&mut self`
|
|
||||||
unsafe {
|
|
||||||
#[cfg(stm32l4)]
|
#[cfg(stm32l4)]
|
||||||
{
|
{
|
||||||
crate::peripherals::PWR::enable();
|
crate::peripherals::PWR::enable();
|
||||||
@ -927,7 +879,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
|
|||||||
<T as RccPeripheral>::reset();
|
<T as RccPeripheral>::reset();
|
||||||
|
|
||||||
T::Interrupt::unpend();
|
T::Interrupt::unpend();
|
||||||
T::Interrupt::enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
let core_id = r.cid().read().0;
|
let core_id = r.cid().read().0;
|
||||||
@ -1008,7 +960,6 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
|
|||||||
|
|
||||||
// Connect
|
// Connect
|
||||||
r.dctl().write(|w| w.set_sdis(false));
|
r.dctl().write(|w| w.set_sdis(false));
|
||||||
}
|
|
||||||
|
|
||||||
self.enabled = true;
|
self.enabled = true;
|
||||||
}
|
}
|
||||||
@ -1066,8 +1017,7 @@ impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, In> {
|
|||||||
|
|
||||||
T::state().ep_in_wakers[ep_index].register(cx.waker());
|
T::state().ep_in_wakers[ep_index].register(cx.waker());
|
||||||
|
|
||||||
// SAFETY: atomic read without side effects
|
if T::regs().diepctl(ep_index).read().usbaep() {
|
||||||
if unsafe { T::regs().diepctl(ep_index).read().usbaep() } {
|
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
} else {
|
} else {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
@ -1088,8 +1038,7 @@ impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, Out> {
|
|||||||
|
|
||||||
T::state().ep_out_wakers[ep_index].register(cx.waker());
|
T::state().ep_out_wakers[ep_index].register(cx.waker());
|
||||||
|
|
||||||
// SAFETY: atomic read without side effects
|
if T::regs().doepctl(ep_index).read().usbaep() {
|
||||||
if unsafe { T::regs().doepctl(ep_index).read().usbaep() } {
|
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
} else {
|
} else {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
@ -1124,8 +1073,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointOut for Endpoint<'d, T, Out> {
|
|||||||
// Release buffer
|
// Release buffer
|
||||||
state.ep_out_size[index].store(EP_OUT_BUFFER_EMPTY, Ordering::Release);
|
state.ep_out_size[index].store(EP_OUT_BUFFER_EMPTY, Ordering::Release);
|
||||||
|
|
||||||
// SAFETY: DOEPCTL/DOEPTSIZ is shared with `Bus` so a critical section is needed for RMW
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
// Receive 1 packet
|
// Receive 1 packet
|
||||||
T::regs().doeptsiz(index).modify(|w| {
|
T::regs().doeptsiz(index).modify(|w| {
|
||||||
w.set_xfrsiz(self.info.max_packet_size as _);
|
w.set_xfrsiz(self.info.max_packet_size as _);
|
||||||
@ -1163,8 +1111,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
|
|||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
state.ep_in_wakers[index].register(cx.waker());
|
state.ep_in_wakers[index].register(cx.waker());
|
||||||
|
|
||||||
// SAFETY: atomic read with no side effects
|
let diepctl = r.diepctl(index).read();
|
||||||
let diepctl = unsafe { r.diepctl(index).read() };
|
|
||||||
if !diepctl.usbaep() {
|
if !diepctl.usbaep() {
|
||||||
Poll::Ready(Err(EndpointError::Disabled))
|
Poll::Ready(Err(EndpointError::Disabled))
|
||||||
} else if !diepctl.epena() {
|
} else if !diepctl.epena() {
|
||||||
@ -1181,12 +1128,10 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
|
|||||||
|
|
||||||
let size_words = (buf.len() + 3) / 4;
|
let size_words = (buf.len() + 3) / 4;
|
||||||
|
|
||||||
// SAFETY: atomic read with no side effects
|
let fifo_space = r.dtxfsts(index).read().ineptfsav() as usize;
|
||||||
let fifo_space = unsafe { r.dtxfsts(index).read().ineptfsav() as usize };
|
|
||||||
if size_words > fifo_space {
|
if size_words > fifo_space {
|
||||||
// Not enough space in fifo, enable tx fifo empty interrupt
|
// Not enough space in fifo, enable tx fifo empty interrupt
|
||||||
// SAFETY: DIEPEMPMSK is shared with IRQ so critical section is needed for RMW
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
r.diepempmsk().modify(|w| {
|
r.diepempmsk().modify(|w| {
|
||||||
w.set_ineptxfem(w.ineptxfem() | (1 << index));
|
w.set_ineptxfem(w.ineptxfem() | (1 << index));
|
||||||
});
|
});
|
||||||
@ -1202,18 +1147,14 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: DIEPTSIZ is exclusive to this endpoint under `&mut self`
|
|
||||||
unsafe {
|
|
||||||
// Setup transfer size
|
// Setup transfer size
|
||||||
r.dieptsiz(index).write(|w| {
|
r.dieptsiz(index).write(|w| {
|
||||||
w.set_mcnt(1);
|
w.set_mcnt(1);
|
||||||
w.set_pktcnt(1);
|
w.set_pktcnt(1);
|
||||||
w.set_xfrsiz(buf.len() as _);
|
w.set_xfrsiz(buf.len() as _);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// SAFETY: DIEPCTL is shared with `Bus` so a critical section is needed for RMW
|
critical_section::with(|_| {
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
// Enable endpoint
|
// Enable endpoint
|
||||||
r.diepctl(index).modify(|w| {
|
r.diepctl(index).modify(|w| {
|
||||||
w.set_cnak(true);
|
w.set_cnak(true);
|
||||||
@ -1225,8 +1166,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
|
|||||||
for chunk in buf.chunks(4) {
|
for chunk in buf.chunks(4) {
|
||||||
let mut tmp = [0u8; 4];
|
let mut tmp = [0u8; 4];
|
||||||
tmp[0..chunk.len()].copy_from_slice(chunk);
|
tmp[0..chunk.len()].copy_from_slice(chunk);
|
||||||
// SAFETY: FIFO is exclusive to this endpoint under `&mut self`
|
r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp)));
|
||||||
unsafe { r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("write done ep={:?}", self.info.addr);
|
trace!("write done ep={:?}", self.info.addr);
|
||||||
@ -1258,7 +1198,6 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
state.ep0_setup_ready.store(false, Ordering::Release);
|
state.ep0_setup_ready.store(false, Ordering::Release);
|
||||||
|
|
||||||
// EP0 should not be controlled by `Bus` so this RMW does not need a critical section
|
// EP0 should not be controlled by `Bus` so this RMW does not need a critical section
|
||||||
unsafe {
|
|
||||||
// Receive 1 SETUP packet
|
// Receive 1 SETUP packet
|
||||||
T::regs().doeptsiz(self.ep_out.info.addr.index()).modify(|w| {
|
T::regs().doeptsiz(self.ep_out.info.addr.index()).modify(|w| {
|
||||||
w.set_rxdpid_stupcnt(1);
|
w.set_rxdpid_stupcnt(1);
|
||||||
@ -1268,7 +1207,6 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
T::regs().doepctl(self.ep_out.info.addr.index()).modify(|w| {
|
T::regs().doepctl(self.ep_out.info.addr.index()).modify(|w| {
|
||||||
w.set_cnak(true);
|
w.set_cnak(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
trace!("SETUP received: {:?}", data);
|
trace!("SETUP received: {:?}", data);
|
||||||
Poll::Ready(data)
|
Poll::Ready(data)
|
||||||
@ -1313,7 +1251,6 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
trace!("control: reject");
|
trace!("control: reject");
|
||||||
|
|
||||||
// EP0 should not be controlled by `Bus` so this RMW does not need a critical section
|
// EP0 should not be controlled by `Bus` so this RMW does not need a critical section
|
||||||
unsafe {
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
regs.diepctl(self.ep_in.info.addr.index()).modify(|w| {
|
regs.diepctl(self.ep_in.info.addr.index()).modify(|w| {
|
||||||
w.set_stall(true);
|
w.set_stall(true);
|
||||||
@ -1322,11 +1259,10 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
w.set_stall(true);
|
w.set_stall(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
async fn accept_set_address(&mut self, addr: u8) {
|
async fn accept_set_address(&mut self, addr: u8) {
|
||||||
trace!("setting addr: {}", addr);
|
trace!("setting addr: {}", addr);
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
T::regs().dcfg().modify(|w| {
|
T::regs().dcfg().modify(|w| {
|
||||||
w.set_dad(addr);
|
w.set_dad(addr);
|
||||||
});
|
});
|
||||||
|
@ -48,11 +48,9 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
|
|||||||
let rl = reload_value(psc, timeout_us);
|
let rl = reload_value(psc, timeout_us);
|
||||||
|
|
||||||
let wdg = T::regs();
|
let wdg = T::regs();
|
||||||
unsafe {
|
|
||||||
wdg.kr().write(|w| w.set_key(Key::ENABLE));
|
wdg.kr().write(|w| w.set_key(Key::ENABLE));
|
||||||
wdg.pr().write(|w| w.set_pr(Pr(pr)));
|
wdg.pr().write(|w| w.set_pr(Pr(pr)));
|
||||||
wdg.rlr().write(|w| w.set_rl(rl));
|
wdg.rlr().write(|w| w.set_rl(rl));
|
||||||
}
|
|
||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
"Watchdog configured with {}us timeout, desired was {}us (PR={}, RL={})",
|
"Watchdog configured with {}us timeout, desired was {}us (PR={}, RL={})",
|
||||||
@ -67,11 +65,11 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn unleash(&mut self) {
|
pub fn unleash(&mut self) {
|
||||||
T::regs().kr().write(|w| w.set_key(Key::START));
|
T::regs().kr().write(|w| w.set_key(Key::START));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn pet(&mut self) {
|
pub fn pet(&mut self) {
|
||||||
T::regs().kr().write(|w| w.set_key(Key::RESET));
|
T::regs().kr().write(|w| w.set_key(Key::RESET));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,10 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut wdg = IndependentWatchdog::new(p.IWDG, 20_000_00);
|
let mut wdg = IndependentWatchdog::new(p.IWDG, 20_000_00);
|
||||||
|
|
||||||
info!("Watchdog start");
|
info!("Watchdog start");
|
||||||
unsafe { wdg.unleash() };
|
wdg.unleash();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
Timer::after(Duration::from_secs(1)).await;
|
Timer::after(Duration::from_secs(1)).await;
|
||||||
unsafe { wdg.pet() };
|
wdg.pet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut led = Output::new(p.PB7, Level::High, Speed::Low);
|
let mut led = Output::new(p.PB7, Level::High, Speed::Low);
|
||||||
|
|
||||||
let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000);
|
let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000);
|
||||||
unsafe {
|
|
||||||
wdt.unleash();
|
wdt.unleash();
|
||||||
}
|
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
||||||
@ -36,10 +34,8 @@ async fn main(_spawner: Spawner) {
|
|||||||
// MCU should restart in 1 second after the last pet.
|
// MCU should restart in 1 second after the last pet.
|
||||||
if i < 5 {
|
if i < 5 {
|
||||||
info!("Petting watchdog");
|
info!("Petting watchdog");
|
||||||
unsafe {
|
|
||||||
wdt.pet();
|
wdt.pet();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
@ -38,9 +38,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let p = embassy_stm32::init(config);
|
let p = embassy_stm32::init(config);
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
unsafe {
|
|
||||||
pac::RCC.ccipr().write(|w| w.set_clk48sel(0b10));
|
pac::RCC.ccipr().write(|w| w.set_clk48sel(0b10));
|
||||||
}
|
|
||||||
|
|
||||||
let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
|
let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
|
||||||
|
|
||||||
|
@ -45,11 +45,9 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
unsafe {
|
|
||||||
pac::RCC.ccipr4().write(|w| {
|
pac::RCC.ccipr4().write(|w| {
|
||||||
w.set_usbsel(pac::rcc::vals::Usbsel::HSI48);
|
w.set_usbsel(pac::rcc::vals::Usbsel::HSI48);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
|
let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
|
||||||
|
@ -62,7 +62,6 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
|
|||||||
T::enable();
|
T::enable();
|
||||||
<T as embassy_stm32::rcc::low_level::RccPeripheral>::reset();
|
<T as embassy_stm32::rcc::low_level::RccPeripheral>::reset();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
ch1.set_speed(Speed::VeryHigh);
|
ch1.set_speed(Speed::VeryHigh);
|
||||||
ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull);
|
ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull);
|
||||||
ch2.set_speed(Speed::VeryHigh);
|
ch2.set_speed(Speed::VeryHigh);
|
||||||
@ -71,52 +70,43 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
|
|||||||
ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull);
|
ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull);
|
||||||
ch4.set_speed(Speed::VeryHigh);
|
ch4.set_speed(Speed::VeryHigh);
|
||||||
ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull);
|
ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull);
|
||||||
}
|
|
||||||
|
|
||||||
let mut this = Self { inner: tim };
|
let mut this = Self { inner: tim };
|
||||||
|
|
||||||
this.set_freq(freq);
|
this.set_freq(freq);
|
||||||
this.inner.start();
|
this.inner.start();
|
||||||
|
|
||||||
unsafe {
|
let r = T::regs_gp32();
|
||||||
T::regs_gp32()
|
r.ccmr_output(0)
|
||||||
.ccmr_output(0)
|
|
||||||
.modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into()));
|
.modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into()));
|
||||||
T::regs_gp32()
|
r.ccmr_output(0)
|
||||||
.ccmr_output(0)
|
|
||||||
.modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into()));
|
.modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into()));
|
||||||
T::regs_gp32()
|
r.ccmr_output(1)
|
||||||
.ccmr_output(1)
|
|
||||||
.modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into()));
|
.modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into()));
|
||||||
T::regs_gp32()
|
r.ccmr_output(1)
|
||||||
.ccmr_output(1)
|
|
||||||
.modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into()));
|
.modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into()));
|
||||||
}
|
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable(&mut self, channel: Channel) {
|
pub fn enable(&mut self, channel: Channel) {
|
||||||
unsafe {
|
|
||||||
T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true));
|
T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn disable(&mut self, channel: Channel) {
|
pub fn disable(&mut self, channel: Channel) {
|
||||||
unsafe {
|
|
||||||
T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false));
|
T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_freq(&mut self, freq: Hertz) {
|
pub fn set_freq(&mut self, freq: Hertz) {
|
||||||
<T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq);
|
<T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_max_duty(&self) -> u32 {
|
pub fn get_max_duty(&self) -> u32 {
|
||||||
unsafe { T::regs_gp32().arr().read().arr() }
|
T::regs_gp32().arr().read().arr()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_duty(&mut self, channel: Channel, duty: u32) {
|
pub fn set_duty(&mut self, channel: Channel, duty: u32) {
|
||||||
defmt::assert!(duty < self.get_max_duty());
|
defmt::assert!(duty < self.get_max_duty());
|
||||||
unsafe { T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty)) }
|
T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,10 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
let mut wdg = IndependentWatchdog::new(p.IWDG1, 20_000_000);
|
let mut wdg = IndependentWatchdog::new(p.IWDG1, 20_000_000);
|
||||||
|
|
||||||
unsafe { wdg.unleash() };
|
wdg.unleash();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
Timer::after(Duration::from_secs(1)).await;
|
Timer::after(Duration::from_secs(1)).await;
|
||||||
unsafe { wdg.pet() };
|
wdg.pet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,12 +12,10 @@ use {defmt_rtt as _, panic_probe as _};
|
|||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
unsafe {
|
|
||||||
pac::RCC.ccipr().modify(|w| {
|
pac::RCC.ccipr().modify(|w| {
|
||||||
w.set_adcsel(0b11);
|
w.set_adcsel(0b11);
|
||||||
});
|
});
|
||||||
pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
|
pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
|
||||||
}
|
|
||||||
|
|
||||||
let p = embassy_stm32::init(Default::default());
|
let p = embassy_stm32::init(Default::default());
|
||||||
|
|
||||||
|
@ -11,11 +11,9 @@ use {defmt_rtt as _, panic_probe as _};
|
|||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
unsafe {
|
|
||||||
pac::RCC.apb1enr1().modify(|w| {
|
pac::RCC.apb1enr1().modify(|w| {
|
||||||
w.set_dac1en(true);
|
w.set_dac1en(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
let p = embassy_stm32::init(Default::default());
|
let p = embassy_stm32::init(Default::default());
|
||||||
|
|
||||||
|
@ -5,14 +5,14 @@
|
|||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::bind_interrupts;
|
use embassy_stm32::bind_interrupts;
|
||||||
use embassy_stm32::ipcc::Config;
|
use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
|
||||||
use embassy_stm32_wpan::TlMbox;
|
use embassy_stm32_wpan::TlMbox;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs{
|
bind_interrupts!(struct Irqs{
|
||||||
IPCC_C1_RX => embassy_stm32_wpan::ReceiveInterruptHandler;
|
IPCC_C1_RX => ReceiveInterruptHandler;
|
||||||
IPCC_C1_TX => embassy_stm32_wpan::TransmitInterruptHandler;
|
IPCC_C1_TX => TransmitInterruptHandler;
|
||||||
});
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
@ -48,7 +48,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mbox = TlMbox::init(p.IPCC, Irqs, config);
|
let mbox = TlMbox::init(p.IPCC, Irqs, config);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let wireless_fw_info = mbox.wireless_fw_info();
|
let wireless_fw_info = mbox.sys_subsystem.wireless_fw_info();
|
||||||
match wireless_fw_info {
|
match wireless_fw_info {
|
||||||
None => info!("not yet initialized"),
|
None => info!("not yet initialized"),
|
||||||
Some(fw_info) => {
|
Some(fw_info) => {
|
||||||
|
@ -5,14 +5,13 @@
|
|||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::bind_interrupts;
|
use embassy_stm32::bind_interrupts;
|
||||||
use embassy_stm32::ipcc::Config;
|
use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
|
||||||
use embassy_stm32_wpan::rc::RadioCoprocessor;
|
|
||||||
use embassy_stm32_wpan::TlMbox;
|
use embassy_stm32_wpan::TlMbox;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs{
|
bind_interrupts!(struct Irqs{
|
||||||
IPCC_C1_RX => embassy_stm32_wpan::ReceiveInterruptHandler;
|
IPCC_C1_RX => ReceiveInterruptHandler;
|
||||||
IPCC_C1_TX => embassy_stm32_wpan::TransmitInterruptHandler;
|
IPCC_C1_TX => TransmitInterruptHandler;
|
||||||
});
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
@ -47,14 +46,18 @@ async fn main(_spawner: Spawner) {
|
|||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let mbox = TlMbox::init(p.IPCC, Irqs, config);
|
let mbox = TlMbox::init(p.IPCC, Irqs, config);
|
||||||
|
|
||||||
let mut rc = RadioCoprocessor::new(mbox);
|
let sys_event = mbox.sys_subsystem.read().await;
|
||||||
|
info!("sys event: {}", sys_event.payload());
|
||||||
|
|
||||||
let response = rc.read().await;
|
mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
|
||||||
info!("coprocessor ready {}", response);
|
|
||||||
|
|
||||||
rc.write(&[0x01, 0x03, 0x0c, 0x00, 0x00]);
|
info!("starting ble...");
|
||||||
let response = rc.read().await;
|
mbox.ble_subsystem.write(0x0c, &[]).await;
|
||||||
info!("ble reset rsp {}", response);
|
|
||||||
|
info!("waiting for ble...");
|
||||||
|
let ble_event = mbox.ble_subsystem.read().await;
|
||||||
|
|
||||||
|
info!("ble event: {}", ble_event.payload());
|
||||||
|
|
||||||
info!("Test OK");
|
info!("Test OK");
|
||||||
cortex_m::asm::bkpt();
|
cortex_m::asm::bkpt();
|
||||||
|
@ -35,7 +35,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
config.rcc.enable_lsi = true; // enable RNG
|
config.rcc.enable_lsi = true; // enable RNG
|
||||||
let p = embassy_stm32::init(config);
|
let p = embassy_stm32::init(config);
|
||||||
|
|
||||||
unsafe { pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)) }
|
pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01));
|
||||||
|
|
||||||
let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2);
|
let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2);
|
||||||
|
|
||||||
|
@ -15,11 +15,9 @@ async fn main(_spawner: Spawner) {
|
|||||||
config.rcc.enable_lsi = true; //Needed for RNG to work
|
config.rcc.enable_lsi = true; //Needed for RNG to work
|
||||||
|
|
||||||
let p = embassy_stm32::init(config);
|
let p = embassy_stm32::init(config);
|
||||||
unsafe {
|
|
||||||
pac::RCC.ccipr().modify(|w| {
|
pac::RCC.ccipr().modify(|w| {
|
||||||
w.set_rngsel(0b01);
|
w.set_rngsel(0b01);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
|
@ -24,10 +24,8 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
info!("Starting LSI");
|
info!("Starting LSI");
|
||||||
|
|
||||||
unsafe {
|
|
||||||
pac::RCC.csr().modify(|w| w.set_lsion(true));
|
pac::RCC.csr().modify(|w| w.set_lsion(true));
|
||||||
while !pac::RCC.csr().read().lsirdy() {}
|
while !pac::RCC.csr().read().lsirdy() {}
|
||||||
}
|
|
||||||
|
|
||||||
info!("Started LSI");
|
info!("Started LSI");
|
||||||
|
|
||||||
|
@ -6,32 +6,45 @@
|
|||||||
#[path = "../common.rs"]
|
#[path = "../common.rs"]
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
|
use core::mem;
|
||||||
|
|
||||||
use common::*;
|
use common::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_futures::poll_once;
|
||||||
use embassy_stm32::bind_interrupts;
|
use embassy_stm32::bind_interrupts;
|
||||||
use embassy_stm32::ipcc::Config;
|
use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
|
||||||
use embassy_stm32_wpan::rc::RadioCoprocessor;
|
use embassy_stm32_wpan::{mm, TlMbox};
|
||||||
use embassy_stm32_wpan::TlMbox;
|
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs{
|
bind_interrupts!(struct Irqs{
|
||||||
IPCC_C1_RX => embassy_stm32_wpan::ReceiveInterruptHandler;
|
IPCC_C1_RX => ReceiveInterruptHandler;
|
||||||
IPCC_C1_TX => embassy_stm32_wpan::TransmitInterruptHandler;
|
IPCC_C1_TX => TransmitInterruptHandler;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn run_mm_queue(memory_manager: mm::MemoryManager) {
|
||||||
|
memory_manager.run_queue().await;
|
||||||
|
}
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(spawner: Spawner) {
|
||||||
let p = embassy_stm32::init(config());
|
let p = embassy_stm32::init(config());
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let mbox = TlMbox::init(p.IPCC, Irqs, config);
|
let mbox = TlMbox::init(p.IPCC, Irqs, config);
|
||||||
|
|
||||||
loop {
|
spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
|
||||||
let wireless_fw_info = mbox.wireless_fw_info();
|
|
||||||
match wireless_fw_info {
|
let ready_event = mbox.sys_subsystem.read().await;
|
||||||
None => {}
|
let _ = poll_once(mbox.sys_subsystem.read()); // clear rx not
|
||||||
Some(fw_info) => {
|
|
||||||
|
info!("coprocessor ready {}", ready_event.payload());
|
||||||
|
|
||||||
|
// test memory manager
|
||||||
|
mem::drop(ready_event);
|
||||||
|
|
||||||
|
let fw_info = mbox.sys_subsystem.wireless_fw_info().unwrap();
|
||||||
let version_major = fw_info.version_major();
|
let version_major = fw_info.version_major();
|
||||||
let version_minor = fw_info.version_minor();
|
let version_minor = fw_info.version_minor();
|
||||||
let subversion = fw_info.subversion();
|
let subversion = fw_info.subversion();
|
||||||
@ -44,22 +57,19 @@ async fn main(_spawner: Spawner) {
|
|||||||
version_major, version_minor, subversion, sram2a_size, sram2b_size
|
version_major, version_minor, subversion, sram2a_size, sram2b_size
|
||||||
);
|
);
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer::after(Duration::from_millis(50)).await;
|
Timer::after(Duration::from_millis(50)).await;
|
||||||
}
|
|
||||||
|
|
||||||
let mut rc = RadioCoprocessor::new(mbox);
|
mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
|
||||||
|
|
||||||
let response = rc.read().await;
|
info!("starting ble...");
|
||||||
info!("coprocessor ready {}", response);
|
mbox.ble_subsystem.write(0x0c, &[]).await;
|
||||||
|
|
||||||
rc.write(&[0x01, 0x03, 0x0c, 0x00, 0x00]);
|
info!("waiting for ble...");
|
||||||
let response = rc.read().await;
|
let ble_event = mbox.ble_subsystem.read().await;
|
||||||
info!("ble reset rsp {}", response);
|
|
||||||
|
|
||||||
|
info!("ble event: {}", ble_event.payload());
|
||||||
|
|
||||||
|
Timer::after(Duration::from_millis(150)).await;
|
||||||
info!("Test OK");
|
info!("Test OK");
|
||||||
cortex_m::asm::bkpt();
|
cortex_m::asm::bkpt();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user