aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/can/fd/config.rs30
-rw-r--r--embassy-stm32/src/can/fd/peripheral.rs174
-rw-r--r--embassy-stm32/src/can/fdcan.rs92
3 files changed, 167 insertions, 129 deletions
diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs
index f2401d92f..adaffe9cc 100644
--- a/embassy-stm32/src/can/fd/config.rs
+++ b/embassy-stm32/src/can/fd/config.rs
@@ -287,6 +287,33 @@ impl Default for GlobalFilter {
287 } 287 }
288} 288}
289 289
290/// TX buffer operation mode
291#[derive(Clone, Copy, PartialEq, Eq, Debug)]
292pub enum TxBufferMode {
293 /// TX FIFO operation - In this mode CAN frames are trasmitted strictly in write order.
294 Fifo,
295 /// TX queue operation - In this mode CAN frames are transmitted according to CAN priority.
296 Queue,
297}
298
299impl From<TxBufferMode> for crate::pac::can::vals::Tfqm {
300 fn from(value: TxBufferMode) -> Self {
301 match value {
302 TxBufferMode::Queue => Self::QUEUE,
303 TxBufferMode::Fifo => Self::FIFO,
304 }
305 }
306}
307
308impl From<crate::pac::can::vals::Tfqm> for TxBufferMode {
309 fn from(value: crate::pac::can::vals::Tfqm) -> Self {
310 match value {
311 crate::pac::can::vals::Tfqm::QUEUE => Self::Queue,
312 crate::pac::can::vals::Tfqm::FIFO => Self::Fifo,
313 }
314 }
315}
316
290/// FdCan Config Struct 317/// FdCan Config Struct
291#[derive(Clone, Copy, Debug)] 318#[derive(Clone, Copy, Debug)]
292pub struct FdCanConfig { 319pub struct FdCanConfig {
@@ -327,6 +354,8 @@ pub struct FdCanConfig {
327 pub timestamp_source: TimestampSource, 354 pub timestamp_source: TimestampSource,
328 /// Configures the Global Filter 355 /// Configures the Global Filter
329 pub global_filter: GlobalFilter, 356 pub global_filter: GlobalFilter,
357 /// TX buffer mode (FIFO or queue)
358 pub tx_buffer_mode: TxBufferMode,
330} 359}
331 360
332impl FdCanConfig { 361impl FdCanConfig {
@@ -433,6 +462,7 @@ impl Default for FdCanConfig {
433 clock_divider: ClockDivider::_1, 462 clock_divider: ClockDivider::_1,
434 timestamp_source: TimestampSource::None, 463 timestamp_source: TimestampSource::None,
435 global_filter: GlobalFilter::default(), 464 global_filter: GlobalFilter::default(),
465 tx_buffer_mode: TxBufferMode::Queue,
436 } 466 }
437 } 467 }
438} 468}
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs
index e87a3c213..8ec09ac12 100644
--- a/embassy-stm32/src/can/fd/peripheral.rs
+++ b/embassy-stm32/src/can/fd/peripheral.rs
@@ -22,6 +22,7 @@ enum LoopbackMode {
22pub struct Registers { 22pub struct Registers {
23 pub regs: &'static crate::pac::can::Fdcan, 23 pub regs: &'static crate::pac::can::Fdcan,
24 pub msgram: &'static crate::pac::fdcanram::Fdcanram, 24 pub msgram: &'static crate::pac::fdcanram::Fdcanram,
25 pub msg_ram_offset: usize,
25} 26}
26 27
27impl Registers { 28impl Registers {
@@ -114,6 +115,12 @@ impl Registers {
114 self.regs.txfqs().read().tfqf() 115 self.regs.txfqs().read().tfqf()
115 } 116 }
116 117
118 /// Returns the current TX buffer operation mode (queue or FIFO)
119 #[inline]
120 pub fn tx_queue_mode(&self) -> TxBufferMode {
121 self.regs.txbc().read().tfqm().into()
122 }
123
117 #[inline] 124 #[inline]
118 pub fn has_pending_frame(&self, idx: usize) -> bool { 125 pub fn has_pending_frame(&self, idx: usize) -> bool {
119 self.regs.txbrp().read().trp(idx) 126 self.regs.txbrp().read().trp(idx)
@@ -164,7 +171,7 @@ impl Registers {
164 } 171 }
165 172
166 #[inline] 173 #[inline]
167 pub fn abort_pending_mailbox_generic<F: embedded_can::Frame>(&self, bufidx: usize) -> Option<F> { 174 fn abort_pending_mailbox<F: embedded_can::Frame>(&self, bufidx: usize) -> Option<F> {
168 if self.abort(bufidx) { 175 if self.abort(bufidx) {
169 let mailbox = self.tx_buffer_element(bufidx); 176 let mailbox = self.tx_buffer_element(bufidx);
170 177
@@ -197,19 +204,20 @@ impl Registers {
197 } 204 }
198 205
199 pub fn write<F: embedded_can::Frame + CanHeader>(&self, frame: &F) -> nb::Result<Option<F>, Infallible> { 206 pub fn write<F: embedded_can::Frame + CanHeader>(&self, frame: &F) -> nb::Result<Option<F>, Infallible> {
200 let queue_is_full = self.tx_queue_is_full(); 207 let (idx, pending_frame) = if self.tx_queue_is_full() {
201 208 if self.tx_queue_mode() == TxBufferMode::Fifo {
202 let id = frame.header().id(); 209 // Does not make sense to cancel a pending frame when using FIFO
203 210 return Err(nb::Error::WouldBlock);
204 // If the queue is full, 211 }
205 // Discard the first slot with a lower priority message 212 // If the queue is full,
206 let (idx, pending_frame) = if queue_is_full { 213 // Discard the first slot with a lower priority message
214 let id = frame.header().id();
207 if self.is_available(0, id) { 215 if self.is_available(0, id) {
208 (0, self.abort_pending_mailbox_generic(0)) 216 (0, self.abort_pending_mailbox(0))
209 } else if self.is_available(1, id) { 217 } else if self.is_available(1, id) {
210 (1, self.abort_pending_mailbox_generic(1)) 218 (1, self.abort_pending_mailbox(1))
211 } else if self.is_available(2, id) { 219 } else if self.is_available(2, id) {
212 (2, self.abort_pending_mailbox_generic(2)) 220 (2, self.abort_pending_mailbox(2))
213 } else { 221 } else {
214 // For now we bail when there is no lower priority slot available 222 // For now we bail when there is no lower priority slot available
215 // Can this lead to priority inversion? 223 // Can this lead to priority inversion?
@@ -287,7 +295,6 @@ impl Registers {
287 pub fn into_config_mode(mut self, _config: FdCanConfig) { 295 pub fn into_config_mode(mut self, _config: FdCanConfig) {
288 self.set_power_down_mode(false); 296 self.set_power_down_mode(false);
289 self.enter_init_mode(); 297 self.enter_init_mode();
290
291 self.reset_msg_ram(); 298 self.reset_msg_ram();
292 299
293 // check the FDCAN core matches our expections 300 // check the FDCAN core matches our expections
@@ -300,12 +307,31 @@ impl Registers {
300 "Error reading endianness test value from FDCAN core" 307 "Error reading endianness test value from FDCAN core"
301 ); 308 );
302 309
303 // Framework specific settings are set here 310 /*
311 for fid in 0..crate::can::message_ram::STANDARD_FILTER_MAX {
312 self.set_standard_filter((fid as u8).into(), StandardFilter::disable());
313 }
314 for fid in 0..Ecrate::can::message_ram::XTENDED_FILTER_MAX {
315 self.set_extended_filter(fid.into(), ExtendedFilter::disable());
316 }
317 */
318 }
304 319
305 // set TxBuffer to Queue Mode 320 /// Disables the CAN interface and returns back the raw peripheral it was created from.
306 self.regs 321 #[inline]
307 .txbc() 322 pub fn free(mut self) {
308 .write(|w| w.set_tfqm(crate::pac::can::vals::Tfqm::QUEUE)); 323 //self.disable_interrupts(Interrupts::all());
324
325 //TODO check this!
326 self.enter_init_mode();
327 self.set_power_down_mode(true);
328 //self.control.instance
329 }
330
331 /// Applies the settings of a new FdCanConfig See [`FdCanConfig`]
332 #[inline]
333 pub fn apply_config(&mut self, config: FdCanConfig) {
334 self.set_tx_buffer_mode(config.tx_buffer_mode);
309 335
310 // set standard filters list size to 28 336 // set standard filters list size to 28
311 // set extended filters list size to 8 337 // set extended filters list size to 8
@@ -328,30 +354,29 @@ impl Registers {
328 .modify(|w| w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX)); 354 .modify(|w| w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX));
329 } 355 }
330 356
331 /* 357 self.configure_msg_ram();
332 for fid in 0..crate::can::message_ram::STANDARD_FILTER_MAX {
333 self.set_standard_filter((fid as u8).into(), StandardFilter::disable());
334 }
335 for fid in 0..Ecrate::can::message_ram::XTENDED_FILTER_MAX {
336 self.set_extended_filter(fid.into(), ExtendedFilter::disable());
337 }
338 */
339 }
340
341 /// Disables the CAN interface and returns back the raw peripheral it was created from.
342 #[inline]
343 pub fn free(mut self) {
344 //self.disable_interrupts(Interrupts::all());
345 358
346 //TODO check this! 359 // Enable timestamping
347 self.enter_init_mode(); 360 #[cfg(not(stm32h7))]
348 self.set_power_down_mode(true); 361 self.regs
349 //self.control.instance 362 .tscc()
350 } 363 .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT));
364 #[cfg(stm32h7)]
365 self.regs.tscc().write(|w| w.set_tss(0x01));
366
367 // this isn't really documented in the reference manual
368 // but corresponding txbtie bit has to be set for the TC (TxComplete) interrupt to fire
369 self.regs.txbtie().write(|w| w.0 = 0xffff_ffff);
370 self.regs.ie().modify(|w| {
371 w.set_rfne(0, true); // Rx Fifo 0 New Msg
372 w.set_rfne(1, true); // Rx Fifo 1 New Msg
373 w.set_tce(true); // Tx Complete
374 });
375 self.regs.ile().modify(|w| {
376 w.set_eint0(true); // Interrupt Line 0
377 w.set_eint1(true); // Interrupt Line 1
378 });
351 379
352 /// Applies the settings of a new FdCanConfig See [`FdCanConfig`]
353 #[inline]
354 pub fn apply_config(&mut self, config: FdCanConfig) {
355 self.set_data_bit_timing(config.dbtr); 380 self.set_data_bit_timing(config.dbtr);
356 self.set_nominal_bit_timing(config.nbtr); 381 self.set_nominal_bit_timing(config.nbtr);
357 self.set_automatic_retransmit(config.automatic_retransmit); 382 self.set_automatic_retransmit(config.automatic_retransmit);
@@ -499,6 +524,12 @@ impl Registers {
499 self.regs.cccr().modify(|w| w.set_efbi(enabled)); 524 self.regs.cccr().modify(|w| w.set_efbi(enabled));
500 } 525 }
501 526
527 /// Configures TX Buffer Mode
528 #[inline]
529 pub fn set_tx_buffer_mode(&mut self, tbm: TxBufferMode) {
530 self.regs.txbc().write(|w| w.set_tfqm(tbm.into()));
531 }
532
502 /// Configures frame transmission mode. See 533 /// Configures frame transmission mode. See
503 /// [`FdCanConfig::set_frame_transmit`] 534 /// [`FdCanConfig::set_frame_transmit`]
504 #[inline] 535 #[inline]
@@ -593,6 +624,71 @@ impl Registers {
593 w.set_rrfe(filter.reject_remote_extended_frames); 624 w.set_rrfe(filter.reject_remote_extended_frames);
594 }); 625 });
595 } 626 }
627
628 #[cfg(not(stm32h7))]
629 fn configure_msg_ram(&mut self) {}
630
631 #[cfg(stm32h7)]
632 fn configure_msg_ram(&mut self) {
633 let r = self.regs;
634
635 use crate::can::fd::message_ram::*;
636 //use fdcan::message_ram::*;
637 let mut offset_words = self.msg_ram_offset as u16;
638
639 // 11-bit filter
640 r.sidfc().modify(|w| w.set_flssa(offset_words));
641 offset_words += STANDARD_FILTER_MAX as u16;
642
643 // 29-bit filter
644 r.xidfc().modify(|w| w.set_flesa(offset_words));
645 offset_words += 2 * EXTENDED_FILTER_MAX as u16;
646
647 // Rx FIFO 0 and 1
648 for i in 0..=1 {
649 r.rxfc(i).modify(|w| {
650 w.set_fsa(offset_words);
651 w.set_fs(RX_FIFO_MAX);
652 w.set_fwm(RX_FIFO_MAX);
653 });
654 offset_words += 18 * RX_FIFO_MAX as u16;
655 }
656
657 // Rx buffer - see below
658 // Tx event FIFO
659 r.txefc().modify(|w| {
660 w.set_efsa(offset_words);
661 w.set_efs(TX_EVENT_MAX);
662 w.set_efwm(TX_EVENT_MAX);
663 });
664 offset_words += 2 * TX_EVENT_MAX as u16;
665
666 // Tx buffers
667 r.txbc().modify(|w| {
668 w.set_tbsa(offset_words);
669 w.set_tfqs(TX_FIFO_MAX);
670 });
671 offset_words += 18 * TX_FIFO_MAX as u16;
672
673 // Rx Buffer - not used
674 r.rxbc().modify(|w| {
675 w.set_rbsa(offset_words);
676 });
677
678 // TX event FIFO?
679 // Trigger memory?
680
681 // Set the element sizes to 16 bytes
682 r.rxesc().modify(|w| {
683 w.set_rbds(0b111);
684 for i in 0..=1 {
685 w.set_fds(i, 0b111);
686 }
687 });
688 r.txesc().modify(|w| {
689 w.set_tbds(0b111);
690 })
691 }
596} 692}
597 693
598fn make_id(id: u32, extended: bool) -> embedded_can::Id { 694fn make_id(id: u32, extended: bool) -> embedded_can::Id {
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index 77db774fc..20d00ccb5 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -184,43 +184,20 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> {
184 T::enable_and_reset(); 184 T::enable_and_reset();
185 185
186 let mut config = crate::can::fd::config::FdCanConfig::default(); 186 let mut config = crate::can::fd::config::FdCanConfig::default();
187 config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1);
187 T::registers().into_config_mode(config); 188 T::registers().into_config_mode(config);
188 189
189 rx.set_as_af(rx.af_num(), AFType::Input); 190 rx.set_as_af(rx.af_num(), AFType::Input);
190 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 191 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
191 192
192 T::configure_msg_ram();
193 unsafe { 193 unsafe {
194 // Enable timestamping
195 #[cfg(not(stm32h7))]
196 T::regs()
197 .tscc()
198 .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT));
199 #[cfg(stm32h7)]
200 T::regs().tscc().write(|w| w.set_tss(0x01));
201 config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1);
202
203 T::IT0Interrupt::unpend(); // Not unsafe 194 T::IT0Interrupt::unpend(); // Not unsafe
204 T::IT0Interrupt::enable(); 195 T::IT0Interrupt::enable();
205 196
206 T::IT1Interrupt::unpend(); // Not unsafe 197 T::IT1Interrupt::unpend(); // Not unsafe
207 T::IT1Interrupt::enable(); 198 T::IT1Interrupt::enable();
208
209 // this isn't really documented in the reference manual
210 // but corresponding txbtie bit has to be set for the TC (TxComplete) interrupt to fire
211 T::regs().txbtie().write(|w| w.0 = 0xffff_ffff);
212 } 199 }
213 200
214 T::regs().ie().modify(|w| {
215 w.set_rfne(0, true); // Rx Fifo 0 New Msg
216 w.set_rfne(1, true); // Rx Fifo 1 New Msg
217 w.set_tce(true); // Tx Complete
218 });
219 T::regs().ile().modify(|w| {
220 w.set_eint0(true); // Interrupt Line 0
221 w.set_eint1(true); // Interrupt Line 1
222 });
223
224 Self { 201 Self {
225 config, 202 config,
226 instance: FdcanInstance(peri), 203 instance: FdcanInstance(peri),
@@ -869,71 +846,6 @@ pub(crate) mod sealed {
869 fn state() -> &'static State; 846 fn state() -> &'static State;
870 unsafe fn mut_state() -> &'static mut State; 847 unsafe fn mut_state() -> &'static mut State;
871 fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp; 848 fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp;
872
873 #[cfg(not(stm32h7))]
874 fn configure_msg_ram() {}
875
876 #[cfg(stm32h7)]
877 fn configure_msg_ram() {
878 let r = Self::regs();
879
880 use crate::can::fd::message_ram::*;
881 //use fdcan::message_ram::*;
882 let mut offset_words = Self::MSG_RAM_OFFSET as u16;
883
884 // 11-bit filter
885 r.sidfc().modify(|w| w.set_flssa(offset_words));
886 offset_words += STANDARD_FILTER_MAX as u16;
887
888 // 29-bit filter
889 r.xidfc().modify(|w| w.set_flesa(offset_words));
890 offset_words += 2 * EXTENDED_FILTER_MAX as u16;
891
892 // Rx FIFO 0 and 1
893 for i in 0..=1 {
894 r.rxfc(i).modify(|w| {
895 w.set_fsa(offset_words);
896 w.set_fs(RX_FIFO_MAX);
897 w.set_fwm(RX_FIFO_MAX);
898 });
899 offset_words += 18 * RX_FIFO_MAX as u16;
900 }
901
902 // Rx buffer - see below
903 // Tx event FIFO
904 r.txefc().modify(|w| {
905 w.set_efsa(offset_words);
906 w.set_efs(TX_EVENT_MAX);
907 w.set_efwm(TX_EVENT_MAX);
908 });
909 offset_words += 2 * TX_EVENT_MAX as u16;
910
911 // Tx buffers
912 r.txbc().modify(|w| {
913 w.set_tbsa(offset_words);
914 w.set_tfqs(TX_FIFO_MAX);
915 });
916 offset_words += 18 * TX_FIFO_MAX as u16;
917
918 // Rx Buffer - not used
919 r.rxbc().modify(|w| {
920 w.set_rbsa(offset_words);
921 });
922
923 // TX event FIFO?
924 // Trigger memory?
925
926 // Set the element sizes to 16 bytes
927 r.rxesc().modify(|w| {
928 w.set_rbds(0b111);
929 for i in 0..=1 {
930 w.set_fds(i, 0b111);
931 }
932 });
933 r.txesc().modify(|w| {
934 w.set_tbds(0b111);
935 })
936 }
937 } 849 }
938} 850}
939 851
@@ -957,7 +869,7 @@ macro_rules! impl_fdcan {
957 &crate::pac::$inst 869 &crate::pac::$inst
958 } 870 }
959 fn registers() -> Registers { 871 fn registers() -> Registers {
960 Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst} 872 Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET}
961 } 873 }
962 fn ram() -> &'static crate::pac::fdcanram::Fdcanram { 874 fn ram() -> &'static crate::pac::fdcanram::Fdcanram {
963 &crate::pac::$msg_ram_inst 875 &crate::pac::$msg_ram_inst