commit
						ac74b922c1
					
				| @ -25,4 +25,4 @@ rustflags = [ | |||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [build] | [build] | ||||||
| target = "thumbv7em-none-eabi" | target = "thumbv7em-none-eabihf" | ||||||
|  | |||||||
| @ -31,3 +31,4 @@ panic-probe = "0.1.0" | |||||||
| stm32f4xx-hal  = { version = "0.8.3", features = ["rt", "stm32f405"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"} | stm32f4xx-hal  = { version = "0.8.3", features = ["rt", "stm32f405"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"} | ||||||
| futures = { version = "0.3.8", default-features = false, features = ["async-await"] } | futures = { version = "0.3.8", default-features = false, features = ["async-await"] } | ||||||
| rtt-target = { version = "0.3", features = ["cortex-m"] } | rtt-target = { version = "0.3", features = ["cortex-m"] } | ||||||
|  | bxcan = "0.5.0" | ||||||
							
								
								
									
										59
									
								
								embassy-stm32f4-examples/src/bin/can.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								embassy-stm32f4-examples/src/bin/can.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | #![feature(trait_alias)] | ||||||
|  | #![feature(type_alias_impl_trait)] | ||||||
|  | 
 | ||||||
|  | #[path = "../example_common.rs"] | ||||||
|  | mod example_common; | ||||||
|  | use example_common::{panic, *}; | ||||||
|  | 
 | ||||||
|  | use bxcan::filter::Mask32; | ||||||
|  | use cortex_m_rt::entry; | ||||||
|  | use embassy::executor::{task, Executor}; | ||||||
|  | use embassy::traits::gpio::*; | ||||||
|  | use embassy::util::Forever; | ||||||
|  | use embassy_stm32f4::{can, exti, interrupt}; | ||||||
|  | use futures::pin_mut; | ||||||
|  | use stm32f4xx_hal::prelude::*; | ||||||
|  | use stm32f4xx_hal::{can::Can, stm32}; | ||||||
|  | 
 | ||||||
|  | static EXTI: Forever<exti::ExtiManager> = Forever::new(); | ||||||
|  | 
 | ||||||
|  | #[task] | ||||||
|  | async fn run(dp: stm32::Peripherals, _cp: cortex_m::Peripherals) { | ||||||
|  |     let gpioa = dp.GPIOA.split(); | ||||||
|  | 
 | ||||||
|  |     let rx = gpioa.pa11.into_alternate_af9(); | ||||||
|  |     let tx = gpioa.pa12.into_alternate_af9(); | ||||||
|  |     let mut can = bxcan::Can::new(Can::new(dp.CAN1, (tx, rx))); | ||||||
|  | 
 | ||||||
|  |     // APB1 (PCLK1): 24MHz, Bit rate: 20kBit/s, Sample Point 87.5%
 | ||||||
|  |     // Value was calculated with http://www.bittiming.can-wiki.info/
 | ||||||
|  |     can.modify_config().set_bit_timing(0x001c_004a); | ||||||
|  |     // Configure filters so that can frames can be received.
 | ||||||
|  |     can.modify_filters().enable_bank(0, Mask32::accept_all()); | ||||||
|  | 
 | ||||||
|  |     let mut can = can::Can::new(can, interrupt::take!(CAN1_TX), interrupt::take!(CAN1_RX0)); | ||||||
|  | 
 | ||||||
|  |     let frame = can.receive().await; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static EXECUTOR: Forever<Executor> = Forever::new(); | ||||||
|  | 
 | ||||||
|  | #[entry] | ||||||
|  | fn main() -> ! { | ||||||
|  |     let dp = stm32::Peripherals::take().unwrap(); | ||||||
|  |     let cp = cortex_m::peripheral::Peripherals::take().unwrap(); | ||||||
|  | 
 | ||||||
|  |     dp.DBGMCU.cr.modify(|_, w| { | ||||||
|  |         w.dbg_sleep().set_bit(); | ||||||
|  |         w.dbg_standby().set_bit(); | ||||||
|  |         w.dbg_stop().set_bit() | ||||||
|  |     }); | ||||||
|  |     dp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); | ||||||
|  | 
 | ||||||
|  |     let executor = EXECUTOR.put(Executor::new()); | ||||||
|  |     executor.run(|spawner| { | ||||||
|  |         unwrap!(spawner.spawn(run(dp, cp))); | ||||||
|  |     }); | ||||||
|  | } | ||||||
| @ -38,4 +38,6 @@ cortex-m-rt = "0.6.13" | |||||||
| cortex-m = "0.7.1" | cortex-m = "0.7.1" | ||||||
| embedded-hal    = { version = "0.2.4" } | embedded-hal    = { version = "0.2.4" } | ||||||
| embedded-dma    = { version = "0.1.2" } | embedded-dma    = { version = "0.1.2" } | ||||||
| stm32f4xx-hal  = { version = "0.8.3", features = ["rt"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"} | stm32f4xx-hal  = { version = "0.8.3", features = ["rt", "can"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"} | ||||||
|  | bxcan = "0.5.0" | ||||||
|  | nb = "*" | ||||||
|  | |||||||
							
								
								
									
										103
									
								
								embassy-stm32f4/src/can.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								embassy-stm32f4/src/can.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | |||||||
|  | //! Async low power Serial.
 | ||||||
|  | //!
 | ||||||
|  | //! The peripheral is autmatically enabled and disabled as required to save power.
 | ||||||
|  | //! Lowest power consumption can only be guaranteed if the send receive futures
 | ||||||
|  | //! are dropped correctly (e.g. not using `mem::forget()`).
 | ||||||
|  | 
 | ||||||
|  | use bxcan; | ||||||
|  | use bxcan::Interrupts; | ||||||
|  | use core::future::Future; | ||||||
|  | use embassy::interrupt::Interrupt; | ||||||
|  | use embassy::util::InterruptFuture; | ||||||
|  | use embassy::util::Signal; | ||||||
|  | use nb; | ||||||
|  | use nb::block; | ||||||
|  | 
 | ||||||
|  | use crate::hal::prelude::*; | ||||||
|  | use crate::interrupt; | ||||||
|  | 
 | ||||||
|  | /// Interface to the Serial peripheral
 | ||||||
|  | pub struct Can<T: Instance> { | ||||||
|  |     can: bxcan::Can<T>, | ||||||
|  |     tx_int: T::TInterrupt, | ||||||
|  |     rx_int: T::RInterrupt, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: Instance> Can<T> { | ||||||
|  |     pub fn new(mut can: bxcan::Can<T>, tx_int: T::TInterrupt, rx_int: T::RInterrupt) -> Self { | ||||||
|  |         // Sync to the bus and start normal operation.
 | ||||||
|  |         can.enable_interrupts( | ||||||
|  |             Interrupts::TRANSMIT_MAILBOX_EMPTY | Interrupts::FIFO0_MESSAGE_PENDING, | ||||||
|  |         ); | ||||||
|  |         block!(can.enable()).unwrap(); | ||||||
|  | 
 | ||||||
|  |         Can { | ||||||
|  |             can: can, | ||||||
|  |             tx_int: tx_int, | ||||||
|  |             rx_int: rx_int, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Sends can frame.
 | ||||||
|  |     ///
 | ||||||
|  |     /// This method async-blocks until the frame is transmitted.
 | ||||||
|  |     pub fn transmit<'a>(&'a mut self, frame: &'a bxcan::Frame) -> impl Future<Output = ()> + 'a { | ||||||
|  |         async move { | ||||||
|  |             let fut = InterruptFuture::new(&mut self.tx_int); | ||||||
|  |             self.can.transmit(frame); | ||||||
|  | 
 | ||||||
|  |             fut.await; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Receive can frame.
 | ||||||
|  |     ///
 | ||||||
|  |     /// This method async-blocks until the frame is received.
 | ||||||
|  |     pub fn receive<'a>(&'a mut self) -> impl Future<Output = (bxcan::Frame)> + 'a { | ||||||
|  |         async move { | ||||||
|  |             let mut frame: Option<bxcan::Frame> = None; | ||||||
|  | 
 | ||||||
|  |             loop { | ||||||
|  |                 let fut = InterruptFuture::new(&mut self.rx_int); | ||||||
|  |                 frame = match self.can.receive() { | ||||||
|  |                     Ok(frame) => Some(frame), | ||||||
|  |                     Err(nb::Error::WouldBlock) => None, | ||||||
|  |                     Err(nb::Error::Other(_)) => None, // Ignore overrun errors.
 | ||||||
|  |                 }; | ||||||
|  |                 if frame.is_some() { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |                 fut.await; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             frame.unwrap() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | mod private { | ||||||
|  |     pub trait Sealed {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub trait Instance: bxcan::Instance + private::Sealed { | ||||||
|  |     type TInterrupt: Interrupt; | ||||||
|  |     type RInterrupt: Interrupt; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | macro_rules! can { | ||||||
|  |     ($($can:ident => ($tint:ident, $rint:ident),)+) => { | ||||||
|  |         $( | ||||||
|  |             impl private::Sealed for crate::hal::can::Can<crate::pac::$can> {} | ||||||
|  |             impl Instance for crate::hal::can::Can<crate::pac::$can> { | ||||||
|  |                 type TInterrupt = interrupt::$tint; | ||||||
|  |                 type RInterrupt = interrupt::$rint; | ||||||
|  |             } | ||||||
|  |         )+ | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[cfg(any(feature = "stm32f405",))] | ||||||
|  | can! { | ||||||
|  |     CAN1 => (CAN1_TX, CAN1_RX0), | ||||||
|  |     CAN2 => (CAN2_TX, CAN2_RX0), | ||||||
|  | } | ||||||
| @ -313,6 +313,7 @@ pub use stm32f4xx_hal::stm32 as pac; | |||||||
| // This mod MUST go first, so that the others see its macros.
 | // This mod MUST go first, so that the others see its macros.
 | ||||||
| pub(crate) mod fmt; | pub(crate) mod fmt; | ||||||
| 
 | 
 | ||||||
|  | pub mod can; | ||||||
| pub mod exti; | pub mod exti; | ||||||
| pub mod interrupt; | pub mod interrupt; | ||||||
| pub mod qei; | pub mod qei; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user