diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-02-23 01:45:10 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-02-23 01:45:10 +0100 |
| commit | a6a5d9913cda2ecfe89b63fa0bcf7afaebc2dac0 (patch) | |
| tree | 14124a6f34d351a979cb110a0ce566b588f5d272 /embassy-stm32/src | |
| parent | 5b7e2d88265b5633fa53047961598fbc38bffed0 (diff) | |
| parent | 2855bb69680a42a721fe88168657ea1e634e8766 (diff) | |
Merge branch 'main' into stm32l0-reset-rtc
Diffstat (limited to 'embassy-stm32/src')
25 files changed, 4781 insertions, 807 deletions
diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs new file mode 100644 index 000000000..38b409121 --- /dev/null +++ b/embassy-stm32/src/can/fd/config.rs | |||
| @@ -0,0 +1,438 @@ | |||
| 1 | //! Configuration for FDCAN Module | ||
| 2 | //! Note: This file is copied and modified from fdcan crate by Richard Meadows | ||
| 3 | |||
| 4 | use core::num::{NonZeroU16, NonZeroU8}; | ||
| 5 | |||
| 6 | /// Configures the bit timings. | ||
| 7 | /// | ||
| 8 | /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter | ||
| 9 | /// parameters as follows: | ||
| 10 | /// | ||
| 11 | /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). | ||
| 12 | /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). | ||
| 13 | /// - *Sample Point*: Should normally be left at the default value of 87.5%. | ||
| 14 | /// - *SJW*: Should normally be left at the default value of 1. | ||
| 15 | /// | ||
| 16 | /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` | ||
| 17 | /// parameter to this method. | ||
| 18 | #[derive(Clone, Copy, Debug)] | ||
| 19 | pub struct NominalBitTiming { | ||
| 20 | /// Value by which the oscillator frequency is divided for generating the bit time quanta. The bit | ||
| 21 | /// time is built up from a multiple of this quanta. Valid values are 1 to 512. | ||
| 22 | pub prescaler: NonZeroU16, | ||
| 23 | /// Valid values are 1 to 128. | ||
| 24 | pub seg1: NonZeroU8, | ||
| 25 | /// Valid values are 1 to 255. | ||
| 26 | pub seg2: NonZeroU8, | ||
| 27 | /// Valid values are 1 to 128. | ||
| 28 | pub sync_jump_width: NonZeroU8, | ||
| 29 | } | ||
| 30 | impl NominalBitTiming { | ||
| 31 | #[inline] | ||
| 32 | pub(crate) fn nbrp(&self) -> u16 { | ||
| 33 | u16::from(self.prescaler) & 0x1FF | ||
| 34 | } | ||
| 35 | #[inline] | ||
| 36 | pub(crate) fn ntseg1(&self) -> u8 { | ||
| 37 | u8::from(self.seg1) | ||
| 38 | } | ||
| 39 | #[inline] | ||
| 40 | pub(crate) fn ntseg2(&self) -> u8 { | ||
| 41 | u8::from(self.seg2) & 0x7F | ||
| 42 | } | ||
| 43 | #[inline] | ||
| 44 | pub(crate) fn nsjw(&self) -> u8 { | ||
| 45 | u8::from(self.sync_jump_width) & 0x7F | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | impl Default for NominalBitTiming { | ||
| 50 | #[inline] | ||
| 51 | fn default() -> Self { | ||
| 52 | // Kernel Clock 8MHz, Bit rate: 500kbit/s. Corresponds to a NBTP | ||
| 53 | // register value of 0x0600_0A03 | ||
| 54 | Self { | ||
| 55 | prescaler: NonZeroU16::new(1).unwrap(), | ||
| 56 | seg1: NonZeroU8::new(11).unwrap(), | ||
| 57 | seg2: NonZeroU8::new(4).unwrap(), | ||
| 58 | sync_jump_width: NonZeroU8::new(4).unwrap(), | ||
| 59 | } | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | /// Configures the data bit timings for the FdCan Variable Bitrates. | ||
| 64 | /// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS. | ||
| 65 | #[derive(Clone, Copy, Debug)] | ||
| 66 | pub struct DataBitTiming { | ||
| 67 | /// Tranceiver Delay Compensation | ||
| 68 | pub transceiver_delay_compensation: bool, | ||
| 69 | /// The value by which the oscillator frequency is divided to generate the bit time quanta. The bit | ||
| 70 | /// time is built up from a multiple of this quanta. Valid values for the Baud Rate Prescaler are 1 | ||
| 71 | /// to 31. | ||
| 72 | pub prescaler: NonZeroU16, | ||
| 73 | /// Valid values are 1 to 31. | ||
| 74 | pub seg1: NonZeroU8, | ||
| 75 | /// Valid values are 1 to 15. | ||
| 76 | pub seg2: NonZeroU8, | ||
| 77 | /// Must always be smaller than DTSEG2, valid values are 1 to 15. | ||
| 78 | pub sync_jump_width: NonZeroU8, | ||
| 79 | } | ||
| 80 | impl DataBitTiming { | ||
| 81 | // #[inline] | ||
| 82 | // fn tdc(&self) -> u8 { | ||
| 83 | // let tsd = self.transceiver_delay_compensation as u8; | ||
| 84 | // //TODO: stm32g4 does not export the TDC field | ||
| 85 | // todo!() | ||
| 86 | // } | ||
| 87 | #[inline] | ||
| 88 | pub(crate) fn dbrp(&self) -> u8 { | ||
| 89 | (u16::from(self.prescaler) & 0x001F) as u8 | ||
| 90 | } | ||
| 91 | #[inline] | ||
| 92 | pub(crate) fn dtseg1(&self) -> u8 { | ||
| 93 | u8::from(self.seg1) & 0x1F | ||
| 94 | } | ||
| 95 | #[inline] | ||
| 96 | pub(crate) fn dtseg2(&self) -> u8 { | ||
| 97 | u8::from(self.seg2) & 0x0F | ||
| 98 | } | ||
| 99 | #[inline] | ||
| 100 | pub(crate) fn dsjw(&self) -> u8 { | ||
| 101 | u8::from(self.sync_jump_width) & 0x0F | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | impl Default for DataBitTiming { | ||
| 106 | #[inline] | ||
| 107 | fn default() -> Self { | ||
| 108 | // Kernel Clock 8MHz, Bit rate: 500kbit/s. Corresponds to a DBTP | ||
| 109 | // register value of 0x0000_0A33 | ||
| 110 | Self { | ||
| 111 | transceiver_delay_compensation: false, | ||
| 112 | prescaler: NonZeroU16::new(1).unwrap(), | ||
| 113 | seg1: NonZeroU8::new(11).unwrap(), | ||
| 114 | seg2: NonZeroU8::new(4).unwrap(), | ||
| 115 | sync_jump_width: NonZeroU8::new(4).unwrap(), | ||
| 116 | } | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | /// Configures which modes to use | ||
| 121 | /// Individual headers can contain a desire to be send via FdCan | ||
| 122 | /// or use Bit rate switching. But if this general setting does not allow | ||
| 123 | /// that, only classic CAN is used instead. | ||
| 124 | #[derive(Clone, Copy, Debug)] | ||
| 125 | pub enum FrameTransmissionConfig { | ||
| 126 | /// Only allow Classic CAN message Frames | ||
| 127 | ClassicCanOnly, | ||
| 128 | /// Allow (non-brs) FdCAN Message Frames | ||
| 129 | AllowFdCan, | ||
| 130 | /// Allow FdCAN Message Frames and allow Bit Rate Switching | ||
| 131 | AllowFdCanAndBRS, | ||
| 132 | } | ||
| 133 | |||
| 134 | /// | ||
| 135 | #[derive(Clone, Copy, Debug)] | ||
| 136 | pub enum ClockDivider { | ||
| 137 | /// Divide by 1 | ||
| 138 | _1 = 0b0000, | ||
| 139 | /// Divide by 2 | ||
| 140 | _2 = 0b0001, | ||
| 141 | /// Divide by 4 | ||
| 142 | _4 = 0b0010, | ||
| 143 | /// Divide by 6 | ||
| 144 | _6 = 0b0011, | ||
| 145 | /// Divide by 8 | ||
| 146 | _8 = 0b0100, | ||
| 147 | /// Divide by 10 | ||
| 148 | _10 = 0b0101, | ||
| 149 | /// Divide by 12 | ||
| 150 | _12 = 0b0110, | ||
| 151 | /// Divide by 14 | ||
| 152 | _14 = 0b0111, | ||
| 153 | /// Divide by 16 | ||
| 154 | _16 = 0b1000, | ||
| 155 | /// Divide by 18 | ||
| 156 | _18 = 0b1001, | ||
| 157 | /// Divide by 20 | ||
| 158 | _20 = 0b1010, | ||
| 159 | /// Divide by 22 | ||
| 160 | _22 = 0b1011, | ||
| 161 | /// Divide by 24 | ||
| 162 | _24 = 0b1100, | ||
| 163 | /// Divide by 26 | ||
| 164 | _26 = 0b1101, | ||
| 165 | /// Divide by 28 | ||
| 166 | _28 = 0b1110, | ||
| 167 | /// Divide by 30 | ||
| 168 | _30 = 0b1111, | ||
| 169 | } | ||
| 170 | |||
| 171 | /// Prescaler of the Timestamp counter | ||
| 172 | #[derive(Clone, Copy, Debug)] | ||
| 173 | pub enum TimestampPrescaler { | ||
| 174 | /// 1 | ||
| 175 | _1 = 1, | ||
| 176 | /// 2 | ||
| 177 | _2 = 2, | ||
| 178 | /// 3 | ||
| 179 | _3 = 3, | ||
| 180 | /// 4 | ||
| 181 | _4 = 4, | ||
| 182 | /// 5 | ||
| 183 | _5 = 5, | ||
| 184 | /// 6 | ||
| 185 | _6 = 6, | ||
| 186 | /// 7 | ||
| 187 | _7 = 7, | ||
| 188 | /// 8 | ||
| 189 | _8 = 8, | ||
| 190 | /// 9 | ||
| 191 | _9 = 9, | ||
| 192 | /// 10 | ||
| 193 | _10 = 10, | ||
| 194 | /// 11 | ||
| 195 | _11 = 11, | ||
| 196 | /// 12 | ||
| 197 | _12 = 12, | ||
| 198 | /// 13 | ||
| 199 | _13 = 13, | ||
| 200 | /// 14 | ||
| 201 | _14 = 14, | ||
| 202 | /// 15 | ||
| 203 | _15 = 15, | ||
| 204 | /// 16 | ||
| 205 | _16 = 16, | ||
| 206 | } | ||
| 207 | |||
| 208 | /// Selects the source of the Timestamp counter | ||
| 209 | #[derive(Clone, Copy, Debug)] | ||
| 210 | pub enum TimestampSource { | ||
| 211 | /// The Timestamp counter is disabled | ||
| 212 | None, | ||
| 213 | /// Using the FdCan input clock as the Timstamp counter's source, | ||
| 214 | /// and using a specific prescaler | ||
| 215 | Prescaler(TimestampPrescaler), | ||
| 216 | /// Using TIM3 as a source | ||
| 217 | FromTIM3, | ||
| 218 | } | ||
| 219 | |||
| 220 | /// How to handle frames in the global filter | ||
| 221 | #[derive(Clone, Copy, Debug)] | ||
| 222 | pub enum NonMatchingFilter { | ||
| 223 | /// Frames will go to Fifo0 when they do no match any specific filter | ||
| 224 | IntoRxFifo0 = 0b00, | ||
| 225 | /// Frames will go to Fifo1 when they do no match any specific filter | ||
| 226 | IntoRxFifo1 = 0b01, | ||
| 227 | /// Frames will be rejected when they do not match any specific filter | ||
| 228 | Reject = 0b11, | ||
| 229 | } | ||
| 230 | |||
| 231 | /// How to handle frames which do not match a specific filter | ||
| 232 | #[derive(Clone, Copy, Debug)] | ||
| 233 | pub struct GlobalFilter { | ||
| 234 | /// How to handle non-matching standard frames | ||
| 235 | pub handle_standard_frames: NonMatchingFilter, | ||
| 236 | |||
| 237 | /// How to handle non-matching extended frames | ||
| 238 | pub handle_extended_frames: NonMatchingFilter, | ||
| 239 | |||
| 240 | /// How to handle remote standard frames | ||
| 241 | pub reject_remote_standard_frames: bool, | ||
| 242 | |||
| 243 | /// How to handle remote extended frames | ||
| 244 | pub reject_remote_extended_frames: bool, | ||
| 245 | } | ||
| 246 | impl GlobalFilter { | ||
| 247 | /// Reject all non-matching and remote frames | ||
| 248 | pub const fn reject_all() -> Self { | ||
| 249 | Self { | ||
| 250 | handle_standard_frames: NonMatchingFilter::Reject, | ||
| 251 | handle_extended_frames: NonMatchingFilter::Reject, | ||
| 252 | reject_remote_standard_frames: true, | ||
| 253 | reject_remote_extended_frames: true, | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | /// How to handle non-matching standard frames | ||
| 258 | pub const fn set_handle_standard_frames(mut self, filter: NonMatchingFilter) -> Self { | ||
| 259 | self.handle_standard_frames = filter; | ||
| 260 | self | ||
| 261 | } | ||
| 262 | /// How to handle non-matching exteded frames | ||
| 263 | pub const fn set_handle_extended_frames(mut self, filter: NonMatchingFilter) -> Self { | ||
| 264 | self.handle_extended_frames = filter; | ||
| 265 | self | ||
| 266 | } | ||
| 267 | /// How to handle remote standard frames | ||
| 268 | pub const fn set_reject_remote_standard_frames(mut self, filter: bool) -> Self { | ||
| 269 | self.reject_remote_standard_frames = filter; | ||
| 270 | self | ||
| 271 | } | ||
| 272 | /// How to handle remote extended frames | ||
| 273 | pub const fn set_reject_remote_extended_frames(mut self, filter: bool) -> Self { | ||
| 274 | self.reject_remote_extended_frames = filter; | ||
| 275 | self | ||
| 276 | } | ||
| 277 | } | ||
| 278 | impl Default for GlobalFilter { | ||
| 279 | #[inline] | ||
| 280 | fn default() -> Self { | ||
| 281 | Self { | ||
| 282 | handle_standard_frames: NonMatchingFilter::IntoRxFifo0, | ||
| 283 | handle_extended_frames: NonMatchingFilter::IntoRxFifo0, | ||
| 284 | reject_remote_standard_frames: false, | ||
| 285 | reject_remote_extended_frames: false, | ||
| 286 | } | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | /// FdCan Config Struct | ||
| 291 | #[derive(Clone, Copy, Debug)] | ||
| 292 | pub struct FdCanConfig { | ||
| 293 | /// Nominal Bit Timings | ||
| 294 | pub nbtr: NominalBitTiming, | ||
| 295 | /// (Variable) Data Bit Timings | ||
| 296 | pub dbtr: DataBitTiming, | ||
| 297 | /// Enables or disables automatic retransmission of messages | ||
| 298 | /// | ||
| 299 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame | ||
| 300 | /// util it can be sent. Otherwise, it will try only once to send each frame. | ||
| 301 | /// | ||
| 302 | /// Automatic retransmission is enabled by default. | ||
| 303 | pub automatic_retransmit: bool, | ||
| 304 | /// Enabled or disables the pausing between transmissions | ||
| 305 | /// | ||
| 306 | /// This feature looses up burst transmissions coming from a single node and it protects against | ||
| 307 | /// "babbling idiot" scenarios where the application program erroneously requests too many | ||
| 308 | /// transmissions. | ||
| 309 | pub transmit_pause: bool, | ||
| 310 | /// Enabled or disables the pausing between transmissions | ||
| 311 | /// | ||
| 312 | /// This feature looses up burst transmissions coming from a single node and it protects against | ||
| 313 | /// "babbling idiot" scenarios where the application program erroneously requests too many | ||
| 314 | /// transmissions. | ||
| 315 | pub frame_transmit: FrameTransmissionConfig, | ||
| 316 | /// Non Isoe Mode | ||
| 317 | /// If this is set, the FDCAN uses the CAN FD frame format as specified by the Bosch CAN | ||
| 318 | /// FD Specification V1.0. | ||
| 319 | pub non_iso_mode: bool, | ||
| 320 | /// Edge Filtering: Two consecutive dominant tq required to detect an edge for hard synchronization | ||
| 321 | pub edge_filtering: bool, | ||
| 322 | /// Enables protocol exception handling | ||
| 323 | pub protocol_exception_handling: bool, | ||
| 324 | /// Sets the general clock divider for this FdCAN instance | ||
| 325 | pub clock_divider: ClockDivider, | ||
| 326 | /// Sets the timestamp source | ||
| 327 | pub timestamp_source: TimestampSource, | ||
| 328 | /// Configures the Global Filter | ||
| 329 | pub global_filter: GlobalFilter, | ||
| 330 | } | ||
| 331 | |||
| 332 | impl FdCanConfig { | ||
| 333 | /// Configures the bit timings. | ||
| 334 | #[inline] | ||
| 335 | pub const fn set_nominal_bit_timing(mut self, btr: NominalBitTiming) -> Self { | ||
| 336 | self.nbtr = btr; | ||
| 337 | self | ||
| 338 | } | ||
| 339 | |||
| 340 | /// Configures the bit timings. | ||
| 341 | #[inline] | ||
| 342 | pub const fn set_data_bit_timing(mut self, btr: DataBitTiming) -> Self { | ||
| 343 | self.dbtr = btr; | ||
| 344 | self | ||
| 345 | } | ||
| 346 | |||
| 347 | /// Enables or disables automatic retransmission of messages | ||
| 348 | /// | ||
| 349 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame | ||
| 350 | /// util it can be sent. Otherwise, it will try only once to send each frame. | ||
| 351 | /// | ||
| 352 | /// Automatic retransmission is enabled by default. | ||
| 353 | #[inline] | ||
| 354 | pub const fn set_automatic_retransmit(mut self, enabled: bool) -> Self { | ||
| 355 | self.automatic_retransmit = enabled; | ||
| 356 | self | ||
| 357 | } | ||
| 358 | |||
| 359 | /// Enabled or disables the pausing between transmissions | ||
| 360 | /// | ||
| 361 | /// This feature looses up burst transmissions coming from a single node and it protects against | ||
| 362 | /// "babbling idiot" scenarios where the application program erroneously requests too many | ||
| 363 | /// transmissions. | ||
| 364 | #[inline] | ||
| 365 | pub const fn set_transmit_pause(mut self, enabled: bool) -> Self { | ||
| 366 | self.transmit_pause = enabled; | ||
| 367 | self | ||
| 368 | } | ||
| 369 | |||
| 370 | /// If this is set, the FDCAN uses the CAN FD frame format as specified by the Bosch CAN | ||
| 371 | /// FD Specification V1.0. | ||
| 372 | #[inline] | ||
| 373 | pub const fn set_non_iso_mode(mut self, enabled: bool) -> Self { | ||
| 374 | self.non_iso_mode = enabled; | ||
| 375 | self | ||
| 376 | } | ||
| 377 | |||
| 378 | /// Two consecutive dominant tq required to detect an edge for hard synchronization | ||
| 379 | #[inline] | ||
| 380 | pub const fn set_edge_filtering(mut self, enabled: bool) -> Self { | ||
| 381 | self.edge_filtering = enabled; | ||
| 382 | self | ||
| 383 | } | ||
| 384 | |||
| 385 | /// Sets the allowed transmission types for messages. | ||
| 386 | #[inline] | ||
| 387 | pub const fn set_frame_transmit(mut self, fts: FrameTransmissionConfig) -> Self { | ||
| 388 | self.frame_transmit = fts; | ||
| 389 | self | ||
| 390 | } | ||
| 391 | |||
| 392 | /// Enables protocol exception handling | ||
| 393 | #[inline] | ||
| 394 | pub const fn set_protocol_exception_handling(mut self, peh: bool) -> Self { | ||
| 395 | self.protocol_exception_handling = peh; | ||
| 396 | self | ||
| 397 | } | ||
| 398 | |||
| 399 | /// Sets the general clock divider for this FdCAN instance | ||
| 400 | #[inline] | ||
| 401 | pub const fn set_clock_divider(mut self, div: ClockDivider) -> Self { | ||
| 402 | self.clock_divider = div; | ||
| 403 | self | ||
| 404 | } | ||
| 405 | |||
| 406 | /// Sets the timestamp source | ||
| 407 | #[inline] | ||
| 408 | pub const fn set_timestamp_source(mut self, tss: TimestampSource) -> Self { | ||
| 409 | self.timestamp_source = tss; | ||
| 410 | self | ||
| 411 | } | ||
| 412 | |||
| 413 | /// Sets the global filter settings | ||
| 414 | #[inline] | ||
| 415 | pub const fn set_global_filter(mut self, filter: GlobalFilter) -> Self { | ||
| 416 | self.global_filter = filter; | ||
| 417 | self | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | impl Default for FdCanConfig { | ||
| 422 | #[inline] | ||
| 423 | fn default() -> Self { | ||
| 424 | Self { | ||
| 425 | nbtr: NominalBitTiming::default(), | ||
| 426 | dbtr: DataBitTiming::default(), | ||
| 427 | automatic_retransmit: true, | ||
| 428 | transmit_pause: false, | ||
| 429 | frame_transmit: FrameTransmissionConfig::ClassicCanOnly, | ||
| 430 | non_iso_mode: false, | ||
| 431 | edge_filtering: false, | ||
| 432 | protocol_exception_handling: true, | ||
| 433 | clock_divider: ClockDivider::_1, | ||
| 434 | timestamp_source: TimestampSource::None, | ||
| 435 | global_filter: GlobalFilter::default(), | ||
| 436 | } | ||
| 437 | } | ||
| 438 | } | ||
diff --git a/embassy-stm32/src/can/fd/filter.rs b/embassy-stm32/src/can/fd/filter.rs new file mode 100644 index 000000000..3e2129e6e --- /dev/null +++ b/embassy-stm32/src/can/fd/filter.rs | |||
| @@ -0,0 +1,379 @@ | |||
| 1 | //! Definition of Filter structs for FDCAN Module | ||
| 2 | //! Note: This file is copied and modified from fdcan crate by Richard Meadows | ||
| 3 | |||
| 4 | use embedded_can::{ExtendedId, StandardId}; | ||
| 5 | |||
| 6 | use crate::can::fd::message_ram; | ||
| 7 | pub use crate::can::fd::message_ram::{EXTENDED_FILTER_MAX, STANDARD_FILTER_MAX}; | ||
| 8 | |||
| 9 | /// A Standard Filter | ||
| 10 | pub type StandardFilter = Filter<StandardId, u16>; | ||
| 11 | /// An Extended Filter | ||
| 12 | pub type ExtendedFilter = Filter<ExtendedId, u32>; | ||
| 13 | |||
| 14 | impl Default for StandardFilter { | ||
| 15 | fn default() -> Self { | ||
| 16 | StandardFilter::disable() | ||
| 17 | } | ||
| 18 | } | ||
| 19 | impl Default for ExtendedFilter { | ||
| 20 | fn default() -> Self { | ||
| 21 | ExtendedFilter::disable() | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | impl StandardFilter { | ||
| 26 | /// Accept all messages in FIFO 0 | ||
| 27 | pub fn accept_all_into_fifo0() -> StandardFilter { | ||
| 28 | StandardFilter { | ||
| 29 | filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, | ||
| 30 | action: Action::StoreInFifo0, | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | /// Accept all messages in FIFO 1 | ||
| 35 | pub fn accept_all_into_fifo1() -> StandardFilter { | ||
| 36 | StandardFilter { | ||
| 37 | filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, | ||
| 38 | action: Action::StoreInFifo1, | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | /// Reject all messages | ||
| 43 | pub fn reject_all() -> StandardFilter { | ||
| 44 | StandardFilter { | ||
| 45 | filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, | ||
| 46 | action: Action::Reject, | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | /// Disable the filter | ||
| 51 | pub fn disable() -> StandardFilter { | ||
| 52 | StandardFilter { | ||
| 53 | filter: FilterType::Disabled, | ||
| 54 | action: Action::Disable, | ||
| 55 | } | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | impl ExtendedFilter { | ||
| 60 | /// Accept all messages in FIFO 0 | ||
| 61 | pub fn accept_all_into_fifo0() -> ExtendedFilter { | ||
| 62 | ExtendedFilter { | ||
| 63 | filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, | ||
| 64 | action: Action::StoreInFifo0, | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | /// Accept all messages in FIFO 1 | ||
| 69 | pub fn accept_all_into_fifo1() -> ExtendedFilter { | ||
| 70 | ExtendedFilter { | ||
| 71 | filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, | ||
| 72 | action: Action::StoreInFifo1, | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | /// Reject all messages | ||
| 77 | pub fn reject_all() -> ExtendedFilter { | ||
| 78 | ExtendedFilter { | ||
| 79 | filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, | ||
| 80 | action: Action::Reject, | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | /// Disable the filter | ||
| 85 | pub fn disable() -> ExtendedFilter { | ||
| 86 | ExtendedFilter { | ||
| 87 | filter: FilterType::Disabled, | ||
| 88 | action: Action::Disable, | ||
| 89 | } | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | /// Filter Type | ||
| 94 | #[derive(Clone, Copy, Debug)] | ||
| 95 | pub enum FilterType<ID, UNIT> | ||
| 96 | where | ||
| 97 | ID: Copy + Clone + core::fmt::Debug, | ||
| 98 | UNIT: Copy + Clone + core::fmt::Debug, | ||
| 99 | { | ||
| 100 | /// Match with a range between two messages | ||
| 101 | Range { | ||
| 102 | /// First Id of the range | ||
| 103 | from: ID, | ||
| 104 | /// Last Id of the range | ||
| 105 | to: ID, | ||
| 106 | }, | ||
| 107 | /// Match with a bitmask | ||
| 108 | BitMask { | ||
| 109 | /// Filter of the bitmask | ||
| 110 | filter: UNIT, | ||
| 111 | /// Mask of the bitmask | ||
| 112 | mask: UNIT, | ||
| 113 | }, | ||
| 114 | /// Match with a single ID | ||
| 115 | DedicatedSingle(ID), | ||
| 116 | /// Match with one of two ID's | ||
| 117 | DedicatedDual(ID, ID), | ||
| 118 | /// Filter is disabled | ||
| 119 | Disabled, | ||
| 120 | } | ||
| 121 | impl<ID, UNIT> From<FilterType<ID, UNIT>> for message_ram::enums::FilterType | ||
| 122 | where | ||
| 123 | ID: Copy + Clone + core::fmt::Debug, | ||
| 124 | UNIT: Copy + Clone + core::fmt::Debug, | ||
| 125 | { | ||
| 126 | fn from(f: FilterType<ID, UNIT>) -> Self { | ||
| 127 | match f { | ||
| 128 | FilterType::Range { to: _, from: _ } => Self::RangeFilter, | ||
| 129 | FilterType::BitMask { filter: _, mask: _ } => Self::ClassicFilter, | ||
| 130 | FilterType::DedicatedSingle(_) => Self::DualIdFilter, | ||
| 131 | FilterType::DedicatedDual(_, _) => Self::DualIdFilter, | ||
| 132 | FilterType::Disabled => Self::FilterDisabled, | ||
| 133 | } | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | /// Filter Action | ||
| 138 | #[derive(Clone, Copy, Debug)] | ||
| 139 | pub enum Action { | ||
| 140 | /// No Action | ||
| 141 | Disable = 0b000, | ||
| 142 | /// Store an matching message in FIFO 0 | ||
| 143 | StoreInFifo0 = 0b001, | ||
| 144 | /// Store an matching message in FIFO 1 | ||
| 145 | StoreInFifo1 = 0b010, | ||
| 146 | /// Reject an matching message | ||
| 147 | Reject = 0b011, | ||
| 148 | /// Flag a matching message (But not store?!?) | ||
| 149 | FlagHighPrio = 0b100, | ||
| 150 | /// Flag a matching message as a High Priority message and store it in FIFO 0 | ||
| 151 | FlagHighPrioAndStoreInFifo0 = 0b101, | ||
| 152 | /// Flag a matching message as a High Priority message and store it in FIFO 1 | ||
| 153 | FlagHighPrioAndStoreInFifo1 = 0b110, | ||
| 154 | } | ||
| 155 | impl From<Action> for message_ram::enums::FilterElementConfig { | ||
| 156 | fn from(a: Action) -> Self { | ||
| 157 | match a { | ||
| 158 | Action::Disable => Self::DisableFilterElement, | ||
| 159 | Action::StoreInFifo0 => Self::StoreInFifo0, | ||
| 160 | Action::StoreInFifo1 => Self::StoreInFifo1, | ||
| 161 | Action::Reject => Self::Reject, | ||
| 162 | Action::FlagHighPrio => Self::SetPriority, | ||
| 163 | Action::FlagHighPrioAndStoreInFifo0 => Self::SetPriorityAndStoreInFifo0, | ||
| 164 | Action::FlagHighPrioAndStoreInFifo1 => Self::SetPriorityAndStoreInFifo1, | ||
| 165 | } | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | /// Filter | ||
| 170 | #[derive(Clone, Copy, Debug)] | ||
| 171 | pub struct Filter<ID, UNIT> | ||
| 172 | where | ||
| 173 | ID: Copy + Clone + core::fmt::Debug, | ||
| 174 | UNIT: Copy + Clone + core::fmt::Debug, | ||
| 175 | { | ||
| 176 | /// How to match an incoming message | ||
| 177 | pub filter: FilterType<ID, UNIT>, | ||
| 178 | /// What to do with a matching message | ||
| 179 | pub action: Action, | ||
| 180 | } | ||
| 181 | |||
| 182 | /// Standard Filter Slot | ||
| 183 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 184 | pub enum StandardFilterSlot { | ||
| 185 | /// 0 | ||
| 186 | _0 = 0, | ||
| 187 | /// 1 | ||
| 188 | _1 = 1, | ||
| 189 | /// 2 | ||
| 190 | _2 = 2, | ||
| 191 | /// 3 | ||
| 192 | _3 = 3, | ||
| 193 | /// 4 | ||
| 194 | _4 = 4, | ||
| 195 | /// 5 | ||
| 196 | _5 = 5, | ||
| 197 | /// 6 | ||
| 198 | _6 = 6, | ||
| 199 | /// 7 | ||
| 200 | _7 = 7, | ||
| 201 | /// 8 | ||
| 202 | _8 = 8, | ||
| 203 | /// 9 | ||
| 204 | _9 = 9, | ||
| 205 | /// 10 | ||
| 206 | _10 = 10, | ||
| 207 | /// 11 | ||
| 208 | _11 = 11, | ||
| 209 | /// 12 | ||
| 210 | _12 = 12, | ||
| 211 | /// 13 | ||
| 212 | _13 = 13, | ||
| 213 | /// 14 | ||
| 214 | _14 = 14, | ||
| 215 | /// 15 | ||
| 216 | _15 = 15, | ||
| 217 | /// 16 | ||
| 218 | _16 = 16, | ||
| 219 | /// 17 | ||
| 220 | _17 = 17, | ||
| 221 | /// 18 | ||
| 222 | _18 = 18, | ||
| 223 | /// 19 | ||
| 224 | _19 = 19, | ||
| 225 | /// 20 | ||
| 226 | _20 = 20, | ||
| 227 | /// 21 | ||
| 228 | _21 = 21, | ||
| 229 | /// 22 | ||
| 230 | _22 = 22, | ||
| 231 | /// 23 | ||
| 232 | _23 = 23, | ||
| 233 | /// 24 | ||
| 234 | _24 = 24, | ||
| 235 | /// 25 | ||
| 236 | _25 = 25, | ||
| 237 | /// 26 | ||
| 238 | _26 = 26, | ||
| 239 | /// 27 | ||
| 240 | _27 = 27, | ||
| 241 | } | ||
| 242 | impl From<u8> for StandardFilterSlot { | ||
| 243 | fn from(u: u8) -> Self { | ||
| 244 | match u { | ||
| 245 | 0 => StandardFilterSlot::_0, | ||
| 246 | 1 => StandardFilterSlot::_1, | ||
| 247 | 2 => StandardFilterSlot::_2, | ||
| 248 | 3 => StandardFilterSlot::_3, | ||
| 249 | 4 => StandardFilterSlot::_4, | ||
| 250 | 5 => StandardFilterSlot::_5, | ||
| 251 | 6 => StandardFilterSlot::_6, | ||
| 252 | 7 => StandardFilterSlot::_7, | ||
| 253 | 8 => StandardFilterSlot::_8, | ||
| 254 | 9 => StandardFilterSlot::_9, | ||
| 255 | 10 => StandardFilterSlot::_10, | ||
| 256 | 11 => StandardFilterSlot::_11, | ||
| 257 | 12 => StandardFilterSlot::_12, | ||
| 258 | 13 => StandardFilterSlot::_13, | ||
| 259 | 14 => StandardFilterSlot::_14, | ||
| 260 | 15 => StandardFilterSlot::_15, | ||
| 261 | 16 => StandardFilterSlot::_16, | ||
| 262 | 17 => StandardFilterSlot::_17, | ||
| 263 | 18 => StandardFilterSlot::_18, | ||
| 264 | 19 => StandardFilterSlot::_19, | ||
| 265 | 20 => StandardFilterSlot::_20, | ||
| 266 | 21 => StandardFilterSlot::_21, | ||
| 267 | 22 => StandardFilterSlot::_22, | ||
| 268 | 23 => StandardFilterSlot::_23, | ||
| 269 | 24 => StandardFilterSlot::_24, | ||
| 270 | 25 => StandardFilterSlot::_25, | ||
| 271 | 26 => StandardFilterSlot::_26, | ||
| 272 | 27 => StandardFilterSlot::_27, | ||
| 273 | _ => panic!("Standard Filter Slot Too High!"), | ||
| 274 | } | ||
| 275 | } | ||
| 276 | } | ||
| 277 | |||
| 278 | /// Extended Filter Slot | ||
| 279 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 280 | pub enum ExtendedFilterSlot { | ||
| 281 | /// 0 | ||
| 282 | _0 = 0, | ||
| 283 | /// 1 | ||
| 284 | _1 = 1, | ||
| 285 | /// 2 | ||
| 286 | _2 = 2, | ||
| 287 | /// 3 | ||
| 288 | _3 = 3, | ||
| 289 | /// 4 | ||
| 290 | _4 = 4, | ||
| 291 | /// 5 | ||
| 292 | _5 = 5, | ||
| 293 | /// 6 | ||
| 294 | _6 = 6, | ||
| 295 | /// 7 | ||
| 296 | _7 = 7, | ||
| 297 | } | ||
| 298 | impl From<u8> for ExtendedFilterSlot { | ||
| 299 | fn from(u: u8) -> Self { | ||
| 300 | match u { | ||
| 301 | 0 => ExtendedFilterSlot::_0, | ||
| 302 | 1 => ExtendedFilterSlot::_1, | ||
| 303 | 2 => ExtendedFilterSlot::_2, | ||
| 304 | 3 => ExtendedFilterSlot::_3, | ||
| 305 | 4 => ExtendedFilterSlot::_4, | ||
| 306 | 5 => ExtendedFilterSlot::_5, | ||
| 307 | 6 => ExtendedFilterSlot::_6, | ||
| 308 | 7 => ExtendedFilterSlot::_7, | ||
| 309 | _ => panic!("Extended Filter Slot Too High!"), // Should be unreachable | ||
| 310 | } | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 314 | /// Enum over both Standard and Extended Filter ID's | ||
| 315 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 316 | pub enum FilterId { | ||
| 317 | /// Standard Filter Slots | ||
| 318 | Standard(StandardFilterSlot), | ||
| 319 | /// Extended Filter Slots | ||
| 320 | Extended(ExtendedFilterSlot), | ||
| 321 | } | ||
| 322 | |||
| 323 | pub(crate) trait ActivateFilter<ID, UNIT> | ||
| 324 | where | ||
| 325 | ID: Copy + Clone + core::fmt::Debug, | ||
| 326 | UNIT: Copy + Clone + core::fmt::Debug, | ||
| 327 | { | ||
| 328 | fn activate(&mut self, f: Filter<ID, UNIT>); | ||
| 329 | // fn read(&self) -> Filter<ID, UNIT>; | ||
| 330 | } | ||
| 331 | |||
| 332 | impl ActivateFilter<StandardId, u16> for message_ram::StandardFilter { | ||
| 333 | fn activate(&mut self, f: Filter<StandardId, u16>) { | ||
| 334 | let sft = f.filter.into(); | ||
| 335 | |||
| 336 | let (sfid1, sfid2) = match f.filter { | ||
| 337 | FilterType::Range { to, from } => (to.as_raw(), from.as_raw()), | ||
| 338 | FilterType::DedicatedSingle(id) => (id.as_raw(), id.as_raw()), | ||
| 339 | FilterType::DedicatedDual(id1, id2) => (id1.as_raw(), id2.as_raw()), | ||
| 340 | FilterType::BitMask { filter, mask } => (filter, mask), | ||
| 341 | FilterType::Disabled => (0x0, 0x0), | ||
| 342 | }; | ||
| 343 | let sfec = f.action.into(); | ||
| 344 | self.write(|w| { | ||
| 345 | unsafe { w.sfid1().bits(sfid1).sfid2().bits(sfid2) } | ||
| 346 | .sft() | ||
| 347 | .set_filter_type(sft) | ||
| 348 | .sfec() | ||
| 349 | .set_filter_element_config(sfec) | ||
| 350 | }); | ||
| 351 | } | ||
| 352 | // fn read(&self) -> Filter<StandardId, u16> { | ||
| 353 | // todo!() | ||
| 354 | // } | ||
| 355 | } | ||
| 356 | impl ActivateFilter<ExtendedId, u32> for message_ram::ExtendedFilter { | ||
| 357 | fn activate(&mut self, f: Filter<ExtendedId, u32>) { | ||
| 358 | let eft = f.filter.into(); | ||
| 359 | |||
| 360 | let (efid1, efid2) = match f.filter { | ||
| 361 | FilterType::Range { to, from } => (to.as_raw(), from.as_raw()), | ||
| 362 | FilterType::DedicatedSingle(id) => (id.as_raw(), id.as_raw()), | ||
| 363 | FilterType::DedicatedDual(id1, id2) => (id1.as_raw(), id2.as_raw()), | ||
| 364 | FilterType::BitMask { filter, mask } => (filter, mask), | ||
| 365 | FilterType::Disabled => (0x0, 0x0), | ||
| 366 | }; | ||
| 367 | let efec = f.action.into(); | ||
| 368 | self.write(|w| { | ||
| 369 | unsafe { w.efid1().bits(efid1).efid2().bits(efid2) } | ||
| 370 | .eft() | ||
| 371 | .set_filter_type(eft) | ||
| 372 | .efec() | ||
| 373 | .set_filter_element_config(efec) | ||
| 374 | }); | ||
| 375 | } | ||
| 376 | // fn read(&self) -> Filter<ExtendedId, u32> { | ||
| 377 | // todo!() | ||
| 378 | // } | ||
| 379 | } | ||
diff --git a/embassy-stm32/src/can/fd/message_ram/common.rs b/embassy-stm32/src/can/fd/message_ram/common.rs new file mode 100644 index 000000000..108c1a428 --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/common.rs | |||
| @@ -0,0 +1,134 @@ | |||
| 1 | // Note: This file is copied and modified from fdcan crate by Richard Meadows | ||
| 2 | #![allow(non_camel_case_types)] | ||
| 3 | #![allow(non_snake_case)] | ||
| 4 | #![allow(unused)] | ||
| 5 | |||
| 6 | use super::enums::{ | ||
| 7 | BitRateSwitching, ErrorStateIndicator, FilterElementConfig, FilterType, FrameFormat, IdType, | ||
| 8 | RemoteTransmissionRequest, | ||
| 9 | }; | ||
| 10 | use super::generic; | ||
| 11 | |||
| 12 | #[doc = "Reader of field `ID`"] | ||
| 13 | pub type ID_R = generic::R<u32, u32>; | ||
| 14 | |||
| 15 | #[doc = "Reader of field `RTR`"] | ||
| 16 | pub type RTR_R = generic::R<bool, RemoteTransmissionRequest>; | ||
| 17 | impl RTR_R { | ||
| 18 | pub fn rtr(&self) -> RemoteTransmissionRequest { | ||
| 19 | match self.bits { | ||
| 20 | false => RemoteTransmissionRequest::TransmitDataFrame, | ||
| 21 | true => RemoteTransmissionRequest::TransmitRemoteFrame, | ||
| 22 | } | ||
| 23 | } | ||
| 24 | pub fn is_transmit_remote_frame(&self) -> bool { | ||
| 25 | *self == RemoteTransmissionRequest::TransmitRemoteFrame | ||
| 26 | } | ||
| 27 | pub fn is_transmit_data_frame(&self) -> bool { | ||
| 28 | *self == RemoteTransmissionRequest::TransmitDataFrame | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | #[doc = "Reader of field `XTD`"] | ||
| 33 | pub type XTD_R = generic::R<bool, IdType>; | ||
| 34 | impl XTD_R { | ||
| 35 | pub fn id_type(&self) -> IdType { | ||
| 36 | match self.bits() { | ||
| 37 | false => IdType::StandardId, | ||
| 38 | true => IdType::ExtendedId, | ||
| 39 | } | ||
| 40 | } | ||
| 41 | pub fn is_standard_id(&self) -> bool { | ||
| 42 | *self == IdType::StandardId | ||
| 43 | } | ||
| 44 | pub fn is_exteded_id(&self) -> bool { | ||
| 45 | *self == IdType::ExtendedId | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | #[doc = "Reader of field `ESI`"] | ||
| 50 | pub type ESI_R = generic::R<bool, ErrorStateIndicator>; | ||
| 51 | impl ESI_R { | ||
| 52 | pub fn error_state(&self) -> ErrorStateIndicator { | ||
| 53 | match self.bits() { | ||
| 54 | false => ErrorStateIndicator::ErrorActive, | ||
| 55 | true => ErrorStateIndicator::ErrorPassive, | ||
| 56 | } | ||
| 57 | } | ||
| 58 | pub fn is_error_active(&self) -> bool { | ||
| 59 | *self == ErrorStateIndicator::ErrorActive | ||
| 60 | } | ||
| 61 | pub fn is_error_passive(&self) -> bool { | ||
| 62 | *self == ErrorStateIndicator::ErrorPassive | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | #[doc = "Reader of field `DLC`"] | ||
| 67 | pub type DLC_R = generic::R<u8, u8>; | ||
| 68 | |||
| 69 | #[doc = "Reader of field `BRS`"] | ||
| 70 | pub type BRS_R = generic::R<bool, BitRateSwitching>; | ||
| 71 | impl BRS_R { | ||
| 72 | pub fn bit_rate_switching(&self) -> BitRateSwitching { | ||
| 73 | match self.bits() { | ||
| 74 | true => BitRateSwitching::WithBRS, | ||
| 75 | false => BitRateSwitching::WithoutBRS, | ||
| 76 | } | ||
| 77 | } | ||
| 78 | pub fn is_with_brs(&self) -> bool { | ||
| 79 | *self == BitRateSwitching::WithBRS | ||
| 80 | } | ||
| 81 | pub fn is_without_brs(&self) -> bool { | ||
| 82 | *self == BitRateSwitching::WithoutBRS | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | #[doc = "Reader of field `FDF`"] | ||
| 87 | pub type FDF_R = generic::R<bool, FrameFormat>; | ||
| 88 | impl FDF_R { | ||
| 89 | pub fn frame_format(&self) -> FrameFormat { | ||
| 90 | match self.bits() { | ||
| 91 | false => FrameFormat::Classic, | ||
| 92 | true => FrameFormat::Fdcan, | ||
| 93 | } | ||
| 94 | } | ||
| 95 | pub fn is_classic_format(&self) -> bool { | ||
| 96 | *self == FrameFormat::Classic | ||
| 97 | } | ||
| 98 | pub fn is_fdcan_format(&self) -> bool { | ||
| 99 | *self == FrameFormat::Fdcan | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | #[doc = "Reader of field `(X|S)FT`"] | ||
| 104 | pub type ESFT_R = generic::R<u8, FilterType>; | ||
| 105 | impl ESFT_R { | ||
| 106 | #[doc = r"Gets the Filtertype"] | ||
| 107 | #[inline(always)] | ||
| 108 | pub fn to_filter_type(&self) -> FilterType { | ||
| 109 | match self.bits() { | ||
| 110 | 0b00 => FilterType::RangeFilter, | ||
| 111 | 0b01 => FilterType::DualIdFilter, | ||
| 112 | 0b10 => FilterType::ClassicFilter, | ||
| 113 | 0b11 => FilterType::FilterDisabled, | ||
| 114 | _ => unreachable!(), | ||
| 115 | } | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | #[doc = "Reader of field `(E|S)FEC`"] | ||
| 120 | pub type ESFEC_R = generic::R<u8, FilterElementConfig>; | ||
| 121 | impl ESFEC_R { | ||
| 122 | pub fn to_filter_element_config(&self) -> FilterElementConfig { | ||
| 123 | match self.bits() { | ||
| 124 | 0b000 => FilterElementConfig::DisableFilterElement, | ||
| 125 | 0b001 => FilterElementConfig::StoreInFifo0, | ||
| 126 | 0b010 => FilterElementConfig::StoreInFifo1, | ||
| 127 | 0b011 => FilterElementConfig::Reject, | ||
| 128 | 0b100 => FilterElementConfig::SetPriority, | ||
| 129 | 0b101 => FilterElementConfig::SetPriorityAndStoreInFifo0, | ||
| 130 | 0b110 => FilterElementConfig::SetPriorityAndStoreInFifo1, | ||
| 131 | _ => unimplemented!(), | ||
| 132 | } | ||
| 133 | } | ||
| 134 | } | ||
diff --git a/embassy-stm32/src/can/fd/message_ram/enums.rs b/embassy-stm32/src/can/fd/message_ram/enums.rs new file mode 100644 index 000000000..0ec5e0f34 --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/enums.rs | |||
| @@ -0,0 +1,233 @@ | |||
| 1 | // Note: This file is copied and modified from fdcan crate by Richard Meadows | ||
| 2 | |||
| 3 | /// Datalength is the message length generalised over | ||
| 4 | /// the Standard (Classic) and FDCAN message types | ||
| 5 | |||
| 6 | #[derive(Clone, Copy, Debug, PartialEq)] | ||
| 7 | pub enum DataLength { | ||
| 8 | Classic(u8), | ||
| 9 | Fdcan(u8), | ||
| 10 | } | ||
| 11 | impl DataLength { | ||
| 12 | /// Creates a DataLength type | ||
| 13 | /// | ||
| 14 | /// Uses the byte length and Type of frame as input | ||
| 15 | pub fn new(len: u8, ff: FrameFormat) -> DataLength { | ||
| 16 | match ff { | ||
| 17 | FrameFormat::Classic => match len { | ||
| 18 | 0..=8 => DataLength::Classic(len), | ||
| 19 | _ => panic!("DataLength > 8"), | ||
| 20 | }, | ||
| 21 | FrameFormat::Fdcan => match len { | ||
| 22 | 0..=64 => DataLength::Fdcan(len), | ||
| 23 | _ => panic!("DataLength > 64"), | ||
| 24 | }, | ||
| 25 | } | ||
| 26 | } | ||
| 27 | /// Specialised function to create classic frames | ||
| 28 | pub fn new_classic(len: u8) -> DataLength { | ||
| 29 | Self::new(len, FrameFormat::Classic) | ||
| 30 | } | ||
| 31 | /// Specialised function to create FDCAN frames | ||
| 32 | pub fn new_fdcan(len: u8) -> DataLength { | ||
| 33 | Self::new(len, FrameFormat::Fdcan) | ||
| 34 | } | ||
| 35 | |||
| 36 | /// returns the length in bytes | ||
| 37 | pub fn len(&self) -> u8 { | ||
| 38 | match self { | ||
| 39 | DataLength::Classic(l) | DataLength::Fdcan(l) => *l, | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | pub(crate) fn dlc(&self) -> u8 { | ||
| 44 | match self { | ||
| 45 | DataLength::Classic(l) => *l, | ||
| 46 | // See RM0433 Rev 7 Table 475. DLC coding | ||
| 47 | DataLength::Fdcan(l) => match l { | ||
| 48 | 0..=8 => *l, | ||
| 49 | 9..=12 => 9, | ||
| 50 | 13..=16 => 10, | ||
| 51 | 17..=20 => 11, | ||
| 52 | 21..=24 => 12, | ||
| 53 | 25..=32 => 13, | ||
| 54 | 33..=48 => 14, | ||
| 55 | 49..=64 => 15, | ||
| 56 | _ => panic!("DataLength > 64"), | ||
| 57 | }, | ||
| 58 | } | ||
| 59 | } | ||
| 60 | } | ||
| 61 | impl From<DataLength> for FrameFormat { | ||
| 62 | fn from(dl: DataLength) -> FrameFormat { | ||
| 63 | match dl { | ||
| 64 | DataLength::Classic(_) => FrameFormat::Classic, | ||
| 65 | DataLength::Fdcan(_) => FrameFormat::Fdcan, | ||
| 66 | } | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | /// Wheter or not to generate an Tx Event | ||
| 71 | #[derive(Clone, Copy, Debug, PartialEq)] | ||
| 72 | pub enum Event { | ||
| 73 | /// Do not generate an Tx Event | ||
| 74 | NoEvent, | ||
| 75 | /// Generate an Tx Event with a specified ID | ||
| 76 | Event(u8), | ||
| 77 | } | ||
| 78 | |||
| 79 | impl From<Event> for EventControl { | ||
| 80 | fn from(e: Event) -> Self { | ||
| 81 | match e { | ||
| 82 | Event::NoEvent => EventControl::DoNotStore, | ||
| 83 | Event::Event(_) => EventControl::Store, | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | impl From<Option<u8>> for Event { | ||
| 89 | fn from(mm: Option<u8>) -> Self { | ||
| 90 | match mm { | ||
| 91 | None => Event::NoEvent, | ||
| 92 | Some(mm) => Event::Event(mm), | ||
| 93 | } | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | impl From<Event> for Option<u8> { | ||
| 98 | fn from(e: Event) -> Option<u8> { | ||
| 99 | match e { | ||
| 100 | Event::NoEvent => None, | ||
| 101 | Event::Event(mm) => Some(mm), | ||
| 102 | } | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | /// TODO | ||
| 107 | #[derive(Clone, Copy, Debug, PartialEq)] | ||
| 108 | pub enum ErrorStateIndicator { | ||
| 109 | /// TODO | ||
| 110 | ErrorActive = 0, | ||
| 111 | /// TODO | ||
| 112 | ErrorPassive = 1, | ||
| 113 | } | ||
| 114 | impl From<ErrorStateIndicator> for bool { | ||
| 115 | #[inline(always)] | ||
| 116 | fn from(e: ErrorStateIndicator) -> Self { | ||
| 117 | e as u8 != 0 | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | /// Type of frame, standard (classic) or FdCAN | ||
| 122 | #[derive(Clone, Copy, Debug, PartialEq)] | ||
| 123 | pub enum FrameFormat { | ||
| 124 | Classic = 0, | ||
| 125 | Fdcan = 1, | ||
| 126 | } | ||
| 127 | impl From<FrameFormat> for bool { | ||
| 128 | #[inline(always)] | ||
| 129 | fn from(e: FrameFormat) -> Self { | ||
| 130 | e as u8 != 0 | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | /// Type of Id, Standard or Extended | ||
| 135 | #[derive(Clone, Copy, Debug, PartialEq)] | ||
| 136 | pub enum IdType { | ||
| 137 | /// Standard ID | ||
| 138 | StandardId = 0, | ||
| 139 | /// Extended ID | ||
| 140 | ExtendedId = 1, | ||
| 141 | } | ||
| 142 | impl From<IdType> for bool { | ||
| 143 | #[inline(always)] | ||
| 144 | fn from(e: IdType) -> Self { | ||
| 145 | e as u8 != 0 | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | /// Whether the frame contains data or requests data | ||
| 150 | #[derive(Clone, Copy, Debug, PartialEq)] | ||
| 151 | pub enum RemoteTransmissionRequest { | ||
| 152 | /// Frame contains data | ||
| 153 | TransmitDataFrame = 0, | ||
| 154 | /// frame does not contain data | ||
| 155 | TransmitRemoteFrame = 1, | ||
| 156 | } | ||
| 157 | impl From<RemoteTransmissionRequest> for bool { | ||
| 158 | #[inline(always)] | ||
| 159 | fn from(e: RemoteTransmissionRequest) -> Self { | ||
| 160 | e as u8 != 0 | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | /// Whether BitRateSwitching should be or was enabled | ||
| 165 | #[derive(Clone, Copy, Debug, PartialEq)] | ||
| 166 | pub enum BitRateSwitching { | ||
| 167 | /// disable bit rate switching | ||
| 168 | WithoutBRS = 0, | ||
| 169 | /// enable bit rate switching | ||
| 170 | WithBRS = 1, | ||
| 171 | } | ||
| 172 | impl From<BitRateSwitching> for bool { | ||
| 173 | #[inline(always)] | ||
| 174 | fn from(e: BitRateSwitching) -> Self { | ||
| 175 | e as u8 != 0 | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | /// Whether to store transmit Events | ||
| 180 | #[derive(Clone, Copy, Debug, PartialEq)] | ||
| 181 | pub enum EventControl { | ||
| 182 | /// do not store an tx event | ||
| 183 | DoNotStore, | ||
| 184 | /// store transmit events | ||
| 185 | Store, | ||
| 186 | } | ||
| 187 | impl From<EventControl> for bool { | ||
| 188 | #[inline(always)] | ||
| 189 | fn from(e: EventControl) -> Self { | ||
| 190 | e as u8 != 0 | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | /// If an received message matched any filters | ||
| 195 | #[derive(Clone, Copy, Debug, PartialEq)] | ||
| 196 | pub enum FilterFrameMatch { | ||
| 197 | /// This did match filter <id> | ||
| 198 | DidMatch(u8), | ||
| 199 | /// This received frame did not match any specific filters | ||
| 200 | DidNotMatch, | ||
| 201 | } | ||
| 202 | |||
| 203 | /// Type of filter to be used | ||
| 204 | #[derive(Clone, Copy, Debug, PartialEq)] | ||
| 205 | pub enum FilterType { | ||
| 206 | /// Filter uses the range between two id's | ||
| 207 | RangeFilter = 0b00, | ||
| 208 | /// The filter matches on two specific id's (or one ID checked twice) | ||
| 209 | DualIdFilter = 0b01, | ||
| 210 | /// Filter is using a bitmask | ||
| 211 | ClassicFilter = 0b10, | ||
| 212 | /// Filter is disabled | ||
| 213 | FilterDisabled = 0b11, | ||
| 214 | } | ||
| 215 | |||
| 216 | #[derive(Clone, Copy, Debug, PartialEq)] | ||
| 217 | pub enum FilterElementConfig { | ||
| 218 | /// Filter is disabled | ||
| 219 | DisableFilterElement = 0b000, | ||
| 220 | /// Store a matching message in FIFO 0 | ||
| 221 | StoreInFifo0 = 0b001, | ||
| 222 | /// Store a matching message in FIFO 1 | ||
| 223 | StoreInFifo1 = 0b010, | ||
| 224 | /// Reject a matching message | ||
| 225 | Reject = 0b011, | ||
| 226 | /// Flag that a priority message has been received, *But do note store!*?? | ||
| 227 | SetPriority = 0b100, | ||
| 228 | /// Flag and store message in FIFO 0 | ||
| 229 | SetPriorityAndStoreInFifo0 = 0b101, | ||
| 230 | /// Flag and store message in FIFO 1 | ||
| 231 | SetPriorityAndStoreInFifo1 = 0b110, | ||
| 232 | //_Unused = 0b111, | ||
| 233 | } | ||
diff --git a/embassy-stm32/src/can/fd/message_ram/extended_filter.rs b/embassy-stm32/src/can/fd/message_ram/extended_filter.rs new file mode 100644 index 000000000..453e9056e --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/extended_filter.rs | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | // Note: This file is copied and modified from fdcan crate by Richard Meadows | ||
| 2 | |||
| 3 | #![allow(non_camel_case_types)] | ||
| 4 | #![allow(non_snake_case)] | ||
| 5 | #![allow(unused)] | ||
| 6 | |||
| 7 | use super::common::{ESFEC_R, ESFT_R}; | ||
| 8 | use super::enums::{FilterElementConfig, FilterType}; | ||
| 9 | use super::generic; | ||
| 10 | |||
| 11 | #[doc = "Reader of register ExtendedFilter"] | ||
| 12 | pub(crate) type R = generic::R<super::ExtendedFilterType, super::ExtendedFilter>; | ||
| 13 | #[doc = "Writer for register ExtendedFilter"] | ||
| 14 | pub(crate) type W = generic::W<super::ExtendedFilterType, super::ExtendedFilter>; | ||
| 15 | #[doc = "Register ExtendedFilter `reset()`'s"] | ||
| 16 | impl generic::ResetValue for super::ExtendedFilter { | ||
| 17 | type Type = super::ExtendedFilterType; | ||
| 18 | #[inline(always)] | ||
| 19 | fn reset_value() -> Self::Type { | ||
| 20 | // Sets filter element to Disabled | ||
| 21 | [0x0, 0x0] | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | #[doc = "Reader of field `EFID2`"] | ||
| 26 | pub(crate) type EFID2_R = generic::R<u32, u32>; | ||
| 27 | #[doc = "Write proxy for field `EFID2`"] | ||
| 28 | pub(crate) struct EFID2_W<'a> { | ||
| 29 | w: &'a mut W, | ||
| 30 | } | ||
| 31 | impl<'a> EFID2_W<'a> { | ||
| 32 | #[doc = r"Writes raw bits to the field"] | ||
| 33 | #[inline(always)] | ||
| 34 | pub unsafe fn bits(self, value: u32) -> &'a mut W { | ||
| 35 | self.w.bits[1] = (self.w.bits[1] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF); | ||
| 36 | self.w | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | #[doc = "Reader of field `EFID1`"] | ||
| 41 | pub(crate) type EFID1_R = generic::R<u32, u32>; | ||
| 42 | #[doc = "Write proxy for field `EFID1`"] | ||
| 43 | pub(crate) struct EFID1_W<'a> { | ||
| 44 | w: &'a mut W, | ||
| 45 | } | ||
| 46 | impl<'a> EFID1_W<'a> { | ||
| 47 | #[doc = r"Writes raw bits to the field"] | ||
| 48 | #[inline(always)] | ||
| 49 | pub unsafe fn bits(self, value: u32) -> &'a mut W { | ||
| 50 | self.w.bits[0] = (self.w.bits[0] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF); | ||
| 51 | self.w | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | #[doc = "Write proxy for field `EFEC`"] | ||
| 56 | pub(crate) struct EFEC_W<'a> { | ||
| 57 | w: &'a mut W, | ||
| 58 | } | ||
| 59 | impl<'a> EFEC_W<'a> { | ||
| 60 | #[doc = r"Writes raw bits to the field"] | ||
| 61 | #[inline(always)] | ||
| 62 | pub unsafe fn bits(self, value: u8) -> &'a mut W { | ||
| 63 | self.w.bits[0] = (self.w.bits[0] & !(0x07 << 29)) | (((value as u32) & 0x07) << 29); | ||
| 64 | self.w | ||
| 65 | } | ||
| 66 | #[doc = r"Sets the field according to FilterElementConfig"] | ||
| 67 | #[inline(always)] | ||
| 68 | pub fn set_filter_element_config(self, fec: FilterElementConfig) -> &'a mut W { | ||
| 69 | //SAFETY: FilterElementConfig only be valid options | ||
| 70 | unsafe { self.bits(fec as u8) } | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | #[doc = "Write proxy for field `EFT`"] | ||
| 75 | pub(crate) struct EFT_W<'a> { | ||
| 76 | w: &'a mut W, | ||
| 77 | } | ||
| 78 | impl<'a> EFT_W<'a> { | ||
| 79 | #[doc = r"Sets the field according the FilterType"] | ||
| 80 | #[inline(always)] | ||
| 81 | pub fn set_filter_type(self, filter: FilterType) -> &'a mut W { | ||
| 82 | //SAFETY: FilterType only be valid options | ||
| 83 | unsafe { self.bits(filter as u8) } | ||
| 84 | } | ||
| 85 | #[doc = r"Writes raw bits to the field"] | ||
| 86 | #[inline(always)] | ||
| 87 | pub unsafe fn bits(self, value: u8) -> &'a mut W { | ||
| 88 | self.w.bits[1] = (self.w.bits[1] & !(0x03 << 30)) | (((value as u32) & 0x03) << 30); | ||
| 89 | self.w | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | impl R { | ||
| 94 | #[doc = "Byte 0 - Bits 0:28 - EFID1"] | ||
| 95 | #[inline(always)] | ||
| 96 | pub fn sfid1(&self) -> EFID1_R { | ||
| 97 | EFID1_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32) | ||
| 98 | } | ||
| 99 | #[doc = "Byte 0 - Bits 29:31 - EFEC"] | ||
| 100 | #[inline(always)] | ||
| 101 | pub fn efec(&self) -> ESFEC_R { | ||
| 102 | ESFEC_R::new(((self.bits[0] >> 29) & 0x07) as u8) | ||
| 103 | } | ||
| 104 | #[doc = "Byte 1 - Bits 0:28 - EFID2"] | ||
| 105 | #[inline(always)] | ||
| 106 | pub fn sfid2(&self) -> EFID2_R { | ||
| 107 | EFID2_R::new(((self.bits[1]) & 0x1FFFFFFF) as u32) | ||
| 108 | } | ||
| 109 | #[doc = "Byte 1 - Bits 30:31 - EFT"] | ||
| 110 | #[inline(always)] | ||
| 111 | pub fn eft(&self) -> ESFT_R { | ||
| 112 | ESFT_R::new(((self.bits[1] >> 30) & 0x03) as u8) | ||
| 113 | } | ||
| 114 | } | ||
| 115 | impl W { | ||
| 116 | #[doc = "Byte 0 - Bits 0:28 - EFID1"] | ||
| 117 | #[inline(always)] | ||
| 118 | pub fn efid1(&mut self) -> EFID1_W { | ||
| 119 | EFID1_W { w: self } | ||
| 120 | } | ||
| 121 | #[doc = "Byte 0 - Bits 29:31 - EFEC"] | ||
| 122 | #[inline(always)] | ||
| 123 | pub fn efec(&mut self) -> EFEC_W { | ||
| 124 | EFEC_W { w: self } | ||
| 125 | } | ||
| 126 | #[doc = "Byte 1 - Bits 0:28 - EFID2"] | ||
| 127 | #[inline(always)] | ||
| 128 | pub fn efid2(&mut self) -> EFID2_W { | ||
| 129 | EFID2_W { w: self } | ||
| 130 | } | ||
| 131 | #[doc = "Byte 1 - Bits 30:31 - EFT"] | ||
| 132 | #[inline(always)] | ||
| 133 | pub fn eft(&mut self) -> EFT_W { | ||
| 134 | EFT_W { w: self } | ||
| 135 | } | ||
| 136 | } | ||
diff --git a/embassy-stm32/src/can/fd/message_ram/generic.rs b/embassy-stm32/src/can/fd/message_ram/generic.rs new file mode 100644 index 000000000..1a5e121b4 --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/generic.rs | |||
| @@ -0,0 +1,168 @@ | |||
| 1 | // Note: This file is copied and modified from fdcan crate by Richard Meadows | ||
| 2 | |||
| 3 | use core::marker; | ||
| 4 | |||
| 5 | ///This trait shows that register has `read` method | ||
| 6 | /// | ||
| 7 | ///Registers marked with `Writable` can be also `modify`'ed | ||
| 8 | pub trait Readable {} | ||
| 9 | |||
| 10 | ///This trait shows that register has `write`, `write_with_zero` and `reset` method | ||
| 11 | /// | ||
| 12 | ///Registers marked with `Readable` can be also `modify`'ed | ||
| 13 | pub trait Writable {} | ||
| 14 | |||
| 15 | ///Reset value of the register | ||
| 16 | /// | ||
| 17 | ///This value is initial value for `write` method. | ||
| 18 | ///It can be also directly writed to register by `reset` method. | ||
| 19 | pub trait ResetValue { | ||
| 20 | ///Register size | ||
| 21 | type Type; | ||
| 22 | ///Reset value of the register | ||
| 23 | fn reset_value() -> Self::Type; | ||
| 24 | } | ||
| 25 | |||
| 26 | ///This structure provides volatile access to register | ||
| 27 | pub struct Reg<U, REG> { | ||
| 28 | register: vcell::VolatileCell<U>, | ||
| 29 | _marker: marker::PhantomData<REG>, | ||
| 30 | } | ||
| 31 | |||
| 32 | unsafe impl<U: Send, REG> Send for Reg<U, REG> {} | ||
| 33 | |||
| 34 | impl<U, REG> Reg<U, REG> | ||
| 35 | where | ||
| 36 | Self: Readable, | ||
| 37 | U: Copy, | ||
| 38 | { | ||
| 39 | ///Reads the contents of `Readable` register | ||
| 40 | /// | ||
| 41 | ///You can read the contents of a register in such way: | ||
| 42 | ///```ignore | ||
| 43 | ///let bits = periph.reg.read().bits(); | ||
| 44 | ///``` | ||
| 45 | ///or get the content of a particular field of a register. | ||
| 46 | ///```ignore | ||
| 47 | ///let reader = periph.reg.read(); | ||
| 48 | ///let bits = reader.field1().bits(); | ||
| 49 | ///let flag = reader.field2().bit_is_set(); | ||
| 50 | ///``` | ||
| 51 | #[inline(always)] | ||
| 52 | pub fn read(&self) -> R<U, Self> { | ||
| 53 | R { | ||
| 54 | bits: self.register.get(), | ||
| 55 | _reg: marker::PhantomData, | ||
| 56 | } | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | impl<U, REG> Reg<U, REG> | ||
| 61 | where | ||
| 62 | Self: ResetValue<Type = U> + Writable, | ||
| 63 | U: Copy, | ||
| 64 | { | ||
| 65 | ///Writes the reset value to `Writable` register | ||
| 66 | /// | ||
| 67 | ///Resets the register to its initial state | ||
| 68 | #[inline(always)] | ||
| 69 | pub fn reset(&self) { | ||
| 70 | self.register.set(Self::reset_value()) | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | impl<U, REG> Reg<U, REG> | ||
| 75 | where | ||
| 76 | Self: ResetValue<Type = U> + Writable, | ||
| 77 | U: Copy, | ||
| 78 | { | ||
| 79 | ///Writes bits to `Writable` register | ||
| 80 | /// | ||
| 81 | ///You can write raw bits into a register: | ||
| 82 | ///```ignore | ||
| 83 | ///periph.reg.write(|w| unsafe { w.bits(rawbits) }); | ||
| 84 | ///``` | ||
| 85 | ///or write only the fields you need: | ||
| 86 | ///```ignore | ||
| 87 | ///periph.reg.write(|w| w | ||
| 88 | /// .field1().bits(newfield1bits) | ||
| 89 | /// .field2().set_bit() | ||
| 90 | /// .field3().variant(VARIANT) | ||
| 91 | ///); | ||
| 92 | ///``` | ||
| 93 | ///Other fields will have reset value. | ||
| 94 | #[inline(always)] | ||
| 95 | pub fn write<F>(&self, f: F) | ||
| 96 | where | ||
| 97 | F: FnOnce(&mut W<U, Self>) -> &mut W<U, Self>, | ||
| 98 | { | ||
| 99 | self.register.set( | ||
| 100 | f(&mut W { | ||
| 101 | bits: Self::reset_value(), | ||
| 102 | _reg: marker::PhantomData, | ||
| 103 | }) | ||
| 104 | .bits, | ||
| 105 | ); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | ///Register/field reader | ||
| 110 | /// | ||
| 111 | ///Result of the [`read`](Reg::read) method of a register. | ||
| 112 | ///Also it can be used in the [`modify`](Reg::read) method | ||
| 113 | pub struct R<U, T> { | ||
| 114 | pub(crate) bits: U, | ||
| 115 | _reg: marker::PhantomData<T>, | ||
| 116 | } | ||
| 117 | |||
| 118 | impl<U, T> R<U, T> | ||
| 119 | where | ||
| 120 | U: Copy, | ||
| 121 | { | ||
| 122 | ///Create new instance of reader | ||
| 123 | #[inline(always)] | ||
| 124 | pub(crate) fn new(bits: U) -> Self { | ||
| 125 | Self { | ||
| 126 | bits, | ||
| 127 | _reg: marker::PhantomData, | ||
| 128 | } | ||
| 129 | } | ||
| 130 | ///Read raw bits from register/field | ||
| 131 | #[inline(always)] | ||
| 132 | pub fn bits(&self) -> U { | ||
| 133 | self.bits | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | impl<U, T, FI> PartialEq<FI> for R<U, T> | ||
| 138 | where | ||
| 139 | U: PartialEq, | ||
| 140 | FI: Copy + Into<U>, | ||
| 141 | { | ||
| 142 | #[inline(always)] | ||
| 143 | fn eq(&self, other: &FI) -> bool { | ||
| 144 | self.bits.eq(&(*other).into()) | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | impl<FI> R<bool, FI> { | ||
| 149 | ///Value of the field as raw bits | ||
| 150 | #[inline(always)] | ||
| 151 | pub fn bit(&self) -> bool { | ||
| 152 | self.bits | ||
| 153 | } | ||
| 154 | ///Returns `true` if the bit is clear (0) | ||
| 155 | #[inline(always)] | ||
| 156 | pub fn bit_is_clear(&self) -> bool { | ||
| 157 | !self.bit() | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | ///Register writer | ||
| 162 | /// | ||
| 163 | ///Used as an argument to the closures in the [`write`](Reg::write) and [`modify`](Reg::modify) methods of the register | ||
| 164 | pub struct W<U, REG> { | ||
| 165 | ///Writable bits | ||
| 166 | pub(crate) bits: U, | ||
| 167 | _reg: marker::PhantomData<REG>, | ||
| 168 | } | ||
diff --git a/embassy-stm32/src/can/fd/message_ram/mod.rs b/embassy-stm32/src/can/fd/message_ram/mod.rs new file mode 100644 index 000000000..830edf3bb --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/mod.rs | |||
| @@ -0,0 +1,170 @@ | |||
| 1 | // Note: This file is copied and modified from fdcan crate by Richard Meadows | ||
| 2 | |||
| 3 | use volatile_register::RW; | ||
| 4 | |||
| 5 | pub(crate) mod common; | ||
| 6 | pub(crate) mod enums; | ||
| 7 | pub(crate) mod generic; | ||
| 8 | |||
| 9 | /// Number of Receive Fifos configured by this module | ||
| 10 | pub const RX_FIFOS_MAX: u8 = 2; | ||
| 11 | /// Number of Receive Messages per RxFifo configured by this module | ||
| 12 | pub const RX_FIFO_MAX: u8 = 3; | ||
| 13 | /// Number of Transmit Messages configured by this module | ||
| 14 | pub const TX_FIFO_MAX: u8 = 3; | ||
| 15 | /// Number of Transmit Events configured by this module | ||
| 16 | pub const TX_EVENT_MAX: u8 = 3; | ||
| 17 | /// Number of Standard Filters configured by this module | ||
| 18 | pub const STANDARD_FILTER_MAX: u8 = 28; | ||
| 19 | /// Number of Extended Filters configured by this module | ||
| 20 | pub const EXTENDED_FILTER_MAX: u8 = 8; | ||
| 21 | |||
| 22 | /// MessageRam Overlay | ||
| 23 | #[repr(C)] | ||
| 24 | pub struct RegisterBlock { | ||
| 25 | pub(crate) filters: Filters, | ||
| 26 | pub(crate) receive: [Receive; RX_FIFOS_MAX as usize], | ||
| 27 | pub(crate) transmit: Transmit, | ||
| 28 | } | ||
| 29 | impl RegisterBlock { | ||
| 30 | pub fn reset(&mut self) { | ||
| 31 | self.filters.reset(); | ||
| 32 | self.receive[0].reset(); | ||
| 33 | self.receive[1].reset(); | ||
| 34 | self.transmit.reset(); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | #[repr(C)] | ||
| 39 | pub(crate) struct Filters { | ||
| 40 | pub(crate) flssa: [StandardFilter; STANDARD_FILTER_MAX as usize], | ||
| 41 | pub(crate) flesa: [ExtendedFilter; EXTENDED_FILTER_MAX as usize], | ||
| 42 | } | ||
| 43 | impl Filters { | ||
| 44 | pub fn reset(&mut self) { | ||
| 45 | for sf in &mut self.flssa { | ||
| 46 | sf.reset(); | ||
| 47 | } | ||
| 48 | for ef in &mut self.flesa { | ||
| 49 | ef.reset(); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | #[repr(C)] | ||
| 55 | pub(crate) struct Receive { | ||
| 56 | pub(crate) fxsa: [RxFifoElement; RX_FIFO_MAX as usize], | ||
| 57 | } | ||
| 58 | impl Receive { | ||
| 59 | pub fn reset(&mut self) { | ||
| 60 | for fe in &mut self.fxsa { | ||
| 61 | fe.reset(); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | #[repr(C)] | ||
| 67 | pub(crate) struct Transmit { | ||
| 68 | pub(crate) efsa: [TxEventElement; TX_EVENT_MAX as usize], | ||
| 69 | pub(crate) tbsa: [TxBufferElement; TX_FIFO_MAX as usize], | ||
| 70 | } | ||
| 71 | impl Transmit { | ||
| 72 | pub fn reset(&mut self) { | ||
| 73 | for ee in &mut self.efsa { | ||
| 74 | ee.reset(); | ||
| 75 | } | ||
| 76 | for be in &mut self.tbsa { | ||
| 77 | be.reset(); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | pub(crate) mod standard_filter; | ||
| 83 | pub(crate) type StandardFilterType = u32; | ||
| 84 | pub(crate) type StandardFilter = generic::Reg<StandardFilterType, _StandardFilter>; | ||
| 85 | pub(crate) struct _StandardFilter; | ||
| 86 | impl generic::Readable for StandardFilter {} | ||
| 87 | impl generic::Writable for StandardFilter {} | ||
| 88 | |||
| 89 | pub(crate) mod extended_filter; | ||
| 90 | pub(crate) type ExtendedFilterType = [u32; 2]; | ||
| 91 | pub(crate) type ExtendedFilter = generic::Reg<ExtendedFilterType, _ExtendedFilter>; | ||
| 92 | pub(crate) struct _ExtendedFilter; | ||
| 93 | impl generic::Readable for ExtendedFilter {} | ||
| 94 | impl generic::Writable for ExtendedFilter {} | ||
| 95 | |||
| 96 | pub(crate) mod txevent_element; | ||
| 97 | pub(crate) type TxEventElementType = [u32; 2]; | ||
| 98 | pub(crate) type TxEventElement = generic::Reg<TxEventElementType, _TxEventElement>; | ||
| 99 | pub(crate) struct _TxEventElement; | ||
| 100 | impl generic::Readable for TxEventElement {} | ||
| 101 | impl generic::Writable for TxEventElement {} | ||
| 102 | |||
| 103 | pub(crate) mod rxfifo_element; | ||
| 104 | #[repr(C)] | ||
| 105 | pub(crate) struct RxFifoElement { | ||
| 106 | pub(crate) header: RxFifoElementHeader, | ||
| 107 | pub(crate) data: [RW<u32>; 16], | ||
| 108 | } | ||
| 109 | impl RxFifoElement { | ||
| 110 | pub(crate) fn reset(&mut self) { | ||
| 111 | self.header.reset(); | ||
| 112 | for byte in self.data.iter_mut() { | ||
| 113 | unsafe { byte.write(0) }; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | } | ||
| 117 | pub(crate) type RxFifoElementHeaderType = [u32; 2]; | ||
| 118 | pub(crate) type RxFifoElementHeader = generic::Reg<RxFifoElementHeaderType, _RxFifoElement>; | ||
| 119 | pub(crate) struct _RxFifoElement; | ||
| 120 | impl generic::Readable for RxFifoElementHeader {} | ||
| 121 | impl generic::Writable for RxFifoElementHeader {} | ||
| 122 | |||
| 123 | pub(crate) mod txbuffer_element; | ||
| 124 | #[repr(C)] | ||
| 125 | pub(crate) struct TxBufferElement { | ||
| 126 | pub(crate) header: TxBufferElementHeader, | ||
| 127 | pub(crate) data: [RW<u32>; 16], | ||
| 128 | } | ||
| 129 | impl TxBufferElement { | ||
| 130 | pub(crate) fn reset(&mut self) { | ||
| 131 | self.header.reset(); | ||
| 132 | for byte in self.data.iter_mut() { | ||
| 133 | unsafe { byte.write(0) }; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | } | ||
| 137 | pub(crate) type TxBufferElementHeader = generic::Reg<TxBufferElementHeaderType, _TxBufferElement>; | ||
| 138 | pub(crate) type TxBufferElementHeaderType = [u32; 2]; | ||
| 139 | pub(crate) struct _TxBufferElement; | ||
| 140 | impl generic::Readable for TxBufferElementHeader {} | ||
| 141 | impl generic::Writable for TxBufferElementHeader {} | ||
| 142 | |||
| 143 | /// FdCan Message RAM instance. | ||
| 144 | /// | ||
| 145 | /// # Safety | ||
| 146 | /// | ||
| 147 | /// It is only safe to implement this trait, when: | ||
| 148 | /// | ||
| 149 | /// * The implementing type has ownership of the Message RAM, preventing any | ||
| 150 | /// other accesses to the register block. | ||
| 151 | /// * `MSG_RAM` is a pointer to the Message RAM block and can be safely accessed | ||
| 152 | /// for as long as ownership or a borrow of the implementing type is present. | ||
| 153 | pub unsafe trait Instance { | ||
| 154 | const MSG_RAM: *mut RegisterBlock; | ||
| 155 | fn msg_ram(&self) -> &RegisterBlock { | ||
| 156 | unsafe { &*Self::MSG_RAM } | ||
| 157 | } | ||
| 158 | fn msg_ram_mut(&mut self) -> &mut RegisterBlock { | ||
| 159 | unsafe { &mut *Self::MSG_RAM } | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | // Ensure the RegisterBlock is the same size as on pg 1957 of RM0440. | ||
| 164 | static_assertions::assert_eq_size!(Filters, [u32; 28 + 16]); | ||
| 165 | static_assertions::assert_eq_size!(Receive, [u32; 54]); | ||
| 166 | static_assertions::assert_eq_size!(Transmit, [u32; 6 + 54]); | ||
| 167 | static_assertions::assert_eq_size!( | ||
| 168 | RegisterBlock, | ||
| 169 | [u32; 28 /*Standard Filters*/ +16 /*Extended Filters*/ +54 /*RxFifo0*/ +54 /*RxFifo1*/ +6 /*TxEvent*/ +54 /*TxFifo */] | ||
| 170 | ); | ||
diff --git a/embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs b/embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs new file mode 100644 index 000000000..48fc3a091 --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs | |||
| @@ -0,0 +1,122 @@ | |||
| 1 | // Note: This file is copied and modified from fdcan crate by Richard Meadows | ||
| 2 | |||
| 3 | #![allow(non_camel_case_types)] | ||
| 4 | #![allow(non_snake_case)] | ||
| 5 | #![allow(unused)] | ||
| 6 | |||
| 7 | use super::common::{BRS_R, DLC_R, ESI_R, FDF_R, ID_R, RTR_R, XTD_R}; | ||
| 8 | use super::enums::{DataLength, FilterFrameMatch, FrameFormat}; | ||
| 9 | use super::generic; | ||
| 10 | |||
| 11 | #[doc = "Reader of register RxFifoElement"] | ||
| 12 | pub(crate) type R = generic::R<super::RxFifoElementHeaderType, super::RxFifoElementHeader>; | ||
| 13 | // #[doc = "Writer for register ExtendedFilter"] | ||
| 14 | // pub(crate) type W = generic::W<super::RxFifoElementHeaderType, super::RxFifoElementHeader>; | ||
| 15 | #[doc = "Register ExtendedFilter `reset()`'s"] | ||
| 16 | impl generic::ResetValue for super::RxFifoElementHeader { | ||
| 17 | type Type = super::RxFifoElementHeaderType; | ||
| 18 | #[inline(always)] | ||
| 19 | fn reset_value() -> Self::Type { | ||
| 20 | [0x0, 0x0] | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | #[doc = "Reader of field `RXTS`"] | ||
| 25 | pub(crate) type RXTS_R = generic::R<u16, u16>; | ||
| 26 | |||
| 27 | #[doc = "Reader of field `FIDX`"] | ||
| 28 | pub(crate) type FIDX_R = generic::R<u8, u8>; | ||
| 29 | |||
| 30 | pub(crate) struct _ANMF; | ||
| 31 | #[doc = "Reader of field `ANMF`"] | ||
| 32 | pub(crate) type ANMF_R = generic::R<bool, _ANMF>; | ||
| 33 | impl ANMF_R { | ||
| 34 | pub fn is_matching_frame(&self) -> bool { | ||
| 35 | self.bit_is_clear() | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | impl R { | ||
| 40 | #[doc = "Byte 0 - Bits 0:28 - ID"] | ||
| 41 | #[inline(always)] | ||
| 42 | pub fn id(&self) -> ID_R { | ||
| 43 | ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32) | ||
| 44 | } | ||
| 45 | #[doc = "Byte 0 - Bit 29 - RTR"] | ||
| 46 | #[inline(always)] | ||
| 47 | pub fn rtr(&self) -> RTR_R { | ||
| 48 | RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0) | ||
| 49 | } | ||
| 50 | #[doc = "Byte 0 - Bit 30 - XTD"] | ||
| 51 | #[inline(always)] | ||
| 52 | pub fn xtd(&self) -> XTD_R { | ||
| 53 | XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0) | ||
| 54 | } | ||
| 55 | #[doc = "Byte 0 - Bit 30 - ESI"] | ||
| 56 | #[inline(always)] | ||
| 57 | pub fn esi(&self) -> ESI_R { | ||
| 58 | ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0) | ||
| 59 | } | ||
| 60 | #[doc = "Byte 1 - Bits 0:15 - RXTS"] | ||
| 61 | #[inline(always)] | ||
| 62 | pub fn txts(&self) -> RXTS_R { | ||
| 63 | RXTS_R::new(((self.bits[1]) & 0xFFFF) as u16) | ||
| 64 | } | ||
| 65 | #[doc = "Byte 1 - Bits 16:19 - DLC"] | ||
| 66 | #[inline(always)] | ||
| 67 | pub fn dlc(&self) -> DLC_R { | ||
| 68 | DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8) | ||
| 69 | } | ||
| 70 | #[doc = "Byte 1 - Bits 20 - BRS"] | ||
| 71 | #[inline(always)] | ||
| 72 | pub fn brs(&self) -> BRS_R { | ||
| 73 | BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0) | ||
| 74 | } | ||
| 75 | #[doc = "Byte 1 - Bits 20 - FDF"] | ||
| 76 | #[inline(always)] | ||
| 77 | pub fn fdf(&self) -> FDF_R { | ||
| 78 | FDF_R::new(((self.bits[1] >> 21) & 0x01) != 0) | ||
| 79 | } | ||
| 80 | #[doc = "Byte 1 - Bits 24:30 - FIDX"] | ||
| 81 | #[inline(always)] | ||
| 82 | pub fn fidx(&self) -> FIDX_R { | ||
| 83 | FIDX_R::new(((self.bits[1] >> 24) & 0xFF) as u8) | ||
| 84 | } | ||
| 85 | #[doc = "Byte 1 - Bits 31 - ANMF"] | ||
| 86 | #[inline(always)] | ||
| 87 | pub fn anmf(&self) -> ANMF_R { | ||
| 88 | ANMF_R::new(((self.bits[1] >> 31) & 0x01) != 0) | ||
| 89 | } | ||
| 90 | pub fn to_data_length(&self) -> DataLength { | ||
| 91 | let dlc = self.dlc().bits(); | ||
| 92 | let ff = self.fdf().frame_format(); | ||
| 93 | let len = if ff == FrameFormat::Fdcan { | ||
| 94 | // See RM0433 Rev 7 Table 475. DLC coding | ||
| 95 | match dlc { | ||
| 96 | 0..=8 => dlc, | ||
| 97 | 9 => 12, | ||
| 98 | 10 => 16, | ||
| 99 | 11 => 20, | ||
| 100 | 12 => 24, | ||
| 101 | 13 => 32, | ||
| 102 | 14 => 48, | ||
| 103 | 15 => 64, | ||
| 104 | _ => panic!("DLC > 15"), | ||
| 105 | } | ||
| 106 | } else { | ||
| 107 | match dlc { | ||
| 108 | 0..=8 => dlc, | ||
| 109 | 9..=15 => 8, | ||
| 110 | _ => panic!("DLC > 15"), | ||
| 111 | } | ||
| 112 | }; | ||
| 113 | DataLength::new(len, ff) | ||
| 114 | } | ||
| 115 | pub fn to_filter_match(&self) -> FilterFrameMatch { | ||
| 116 | if self.anmf().is_matching_frame() { | ||
| 117 | FilterFrameMatch::DidMatch(self.fidx().bits()) | ||
| 118 | } else { | ||
| 119 | FilterFrameMatch::DidNotMatch | ||
| 120 | } | ||
| 121 | } | ||
| 122 | } | ||
diff --git a/embassy-stm32/src/can/fd/message_ram/standard_filter.rs b/embassy-stm32/src/can/fd/message_ram/standard_filter.rs new file mode 100644 index 000000000..3a3bbcf12 --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/standard_filter.rs | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | // Note: This file is copied and modified from fdcan crate by Richard Meadows | ||
| 2 | |||
| 3 | #![allow(non_camel_case_types)] | ||
| 4 | #![allow(non_snake_case)] | ||
| 5 | #![allow(unused)] | ||
| 6 | |||
| 7 | use super::common::{ESFEC_R, ESFT_R}; | ||
| 8 | use super::enums::{FilterElementConfig, FilterType}; | ||
| 9 | use super::generic; | ||
| 10 | |||
| 11 | #[doc = "Reader of register StandardFilter"] | ||
| 12 | pub(crate) type R = generic::R<super::StandardFilterType, super::StandardFilter>; | ||
| 13 | #[doc = "Writer for register StandardFilter"] | ||
| 14 | pub(crate) type W = generic::W<super::StandardFilterType, super::StandardFilter>; | ||
| 15 | #[doc = "Register StandardFilter `reset()`'s with value 0xC0000"] | ||
| 16 | impl generic::ResetValue for super::StandardFilter { | ||
| 17 | type Type = super::StandardFilterType; | ||
| 18 | #[inline(always)] | ||
| 19 | fn reset_value() -> Self::Type { | ||
| 20 | // Sets filter element to Disabled | ||
| 21 | 0xC000 | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | #[doc = "Reader of field `SFID2`"] | ||
| 26 | pub(crate) type SFID2_R = generic::R<u16, u16>; | ||
| 27 | #[doc = "Write proxy for field `SFID2`"] | ||
| 28 | pub(crate) struct SFID2_W<'a> { | ||
| 29 | w: &'a mut W, | ||
| 30 | } | ||
| 31 | impl<'a> SFID2_W<'a> { | ||
| 32 | #[doc = r"Writes raw bits to the field"] | ||
| 33 | #[inline(always)] | ||
| 34 | pub unsafe fn bits(self, value: u16) -> &'a mut W { | ||
| 35 | self.w.bits = (self.w.bits & !(0x07ff)) | ((value as u32) & 0x07ff); | ||
| 36 | self.w | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | #[doc = "Reader of field `SFID1`"] | ||
| 41 | pub(crate) type SFID1_R = generic::R<u16, u16>; | ||
| 42 | #[doc = "Write proxy for field `SFID1`"] | ||
| 43 | pub(crate) struct SFID1_W<'a> { | ||
| 44 | w: &'a mut W, | ||
| 45 | } | ||
| 46 | impl<'a> SFID1_W<'a> { | ||
| 47 | #[doc = r"Writes raw bits to the field"] | ||
| 48 | #[inline(always)] | ||
| 49 | pub unsafe fn bits(self, value: u16) -> &'a mut W { | ||
| 50 | self.w.bits = (self.w.bits & !(0x07ff << 16)) | (((value as u32) & 0x07ff) << 16); | ||
| 51 | self.w | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | #[doc = "Write proxy for field `SFEC`"] | ||
| 56 | pub(crate) struct SFEC_W<'a> { | ||
| 57 | w: &'a mut W, | ||
| 58 | } | ||
| 59 | impl<'a> SFEC_W<'a> { | ||
| 60 | #[doc = r"Writes raw bits to the field"] | ||
| 61 | #[inline(always)] | ||
| 62 | pub unsafe fn bits(self, value: u8) -> &'a mut W { | ||
| 63 | self.w.bits = (self.w.bits & !(0x07 << 27)) | (((value as u32) & 0x07) << 27); | ||
| 64 | self.w | ||
| 65 | } | ||
| 66 | #[doc = r"Sets the field according to FilterElementConfig"] | ||
| 67 | #[inline(always)] | ||
| 68 | pub fn set_filter_element_config(self, fec: FilterElementConfig) -> &'a mut W { | ||
| 69 | //SAFETY: FilterElementConfig only be valid options | ||
| 70 | unsafe { self.bits(fec as u8) } | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | #[doc = "Write proxy for field `SFT`"] | ||
| 75 | pub(crate) struct SFT_W<'a> { | ||
| 76 | w: &'a mut W, | ||
| 77 | } | ||
| 78 | impl<'a> SFT_W<'a> { | ||
| 79 | #[doc = r"Sets the field according the FilterType"] | ||
| 80 | #[inline(always)] | ||
| 81 | pub fn set_filter_type(self, filter: FilterType) -> &'a mut W { | ||
| 82 | //SAFETY: FilterType only be valid options | ||
| 83 | unsafe { self.bits(filter as u8) } | ||
| 84 | } | ||
| 85 | #[doc = r"Writes raw bits to the field"] | ||
| 86 | #[inline(always)] | ||
| 87 | pub unsafe fn bits(self, value: u8) -> &'a mut W { | ||
| 88 | self.w.bits = (self.w.bits & !(0x03 << 30)) | (((value as u32) & 0x03) << 30); | ||
| 89 | self.w | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | impl R { | ||
| 94 | #[doc = "Bits 0:10 - SFID2"] | ||
| 95 | #[inline(always)] | ||
| 96 | pub fn sfid2(&self) -> SFID2_R { | ||
| 97 | SFID2_R::new((self.bits & 0x07ff) as u16) | ||
| 98 | } | ||
| 99 | #[doc = "Bits 16:26 - SFID1"] | ||
| 100 | #[inline(always)] | ||
| 101 | pub fn sfid1(&self) -> SFID1_R { | ||
| 102 | SFID1_R::new(((self.bits >> 16) & 0x07ff) as u16) | ||
| 103 | } | ||
| 104 | #[doc = "Bits 27:29 - SFEC"] | ||
| 105 | #[inline(always)] | ||
| 106 | pub fn sfec(&self) -> ESFEC_R { | ||
| 107 | ESFEC_R::new(((self.bits >> 27) & 0x07) as u8) | ||
| 108 | } | ||
| 109 | #[doc = "Bits 30:31 - SFT"] | ||
| 110 | #[inline(always)] | ||
| 111 | pub fn sft(&self) -> ESFT_R { | ||
| 112 | ESFT_R::new(((self.bits >> 30) & 0x03) as u8) | ||
| 113 | } | ||
| 114 | } | ||
| 115 | impl W { | ||
| 116 | #[doc = "Bits 0:10 - SFID2"] | ||
| 117 | #[inline(always)] | ||
| 118 | pub fn sfid2(&mut self) -> SFID2_W { | ||
| 119 | SFID2_W { w: self } | ||
| 120 | } | ||
| 121 | #[doc = "Bits 16:26 - SFID1"] | ||
| 122 | #[inline(always)] | ||
| 123 | pub fn sfid1(&mut self) -> SFID1_W { | ||
| 124 | SFID1_W { w: self } | ||
| 125 | } | ||
| 126 | #[doc = "Bits 27:29 - SFEC"] | ||
| 127 | #[inline(always)] | ||
| 128 | pub fn sfec(&mut self) -> SFEC_W { | ||
| 129 | SFEC_W { w: self } | ||
| 130 | } | ||
| 131 | #[doc = "Bits 30:31 - SFT"] | ||
| 132 | #[inline(always)] | ||
| 133 | pub fn sft(&mut self) -> SFT_W { | ||
| 134 | SFT_W { w: self } | ||
| 135 | } | ||
| 136 | } | ||
diff --git a/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs b/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs new file mode 100644 index 000000000..455406a1c --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs | |||
| @@ -0,0 +1,433 @@ | |||
| 1 | // Note: This file is copied and modified from fdcan crate by Richard Meadows | ||
| 2 | |||
| 3 | #![allow(non_camel_case_types)] | ||
| 4 | #![allow(non_snake_case)] | ||
| 5 | #![allow(unused)] | ||
| 6 | |||
| 7 | use super::common::{BRS_R, DLC_R, ESI_R, FDF_R, ID_R, RTR_R, XTD_R}; | ||
| 8 | use super::enums::{ | ||
| 9 | BitRateSwitching, DataLength, ErrorStateIndicator, Event, EventControl, FrameFormat, IdType, | ||
| 10 | RemoteTransmissionRequest, | ||
| 11 | }; | ||
| 12 | use super::generic; | ||
| 13 | |||
| 14 | #[doc = "Reader of register TxBufferElement"] | ||
| 15 | pub(crate) type R = generic::R<super::TxBufferElementHeaderType, super::TxBufferElementHeader>; | ||
| 16 | #[doc = "Writer for register TxBufferElement"] | ||
| 17 | pub(crate) type W = generic::W<super::TxBufferElementHeaderType, super::TxBufferElementHeader>; | ||
| 18 | impl generic::ResetValue for super::TxBufferElementHeader { | ||
| 19 | type Type = super::TxBufferElementHeaderType; | ||
| 20 | |||
| 21 | #[allow(dead_code)] | ||
| 22 | #[inline(always)] | ||
| 23 | fn reset_value() -> Self::Type { | ||
| 24 | [0; 2] | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | #[doc = "Write proxy for field `ESI`"] | ||
| 29 | pub(crate) struct ESI_W<'a> { | ||
| 30 | w: &'a mut W, | ||
| 31 | } | ||
| 32 | impl<'a> ESI_W<'a> { | ||
| 33 | #[doc = r"Writes `variant` to the field"] | ||
| 34 | #[inline(always)] | ||
| 35 | #[allow(dead_code)] | ||
| 36 | pub fn set_error_indicator(self, esi: ErrorStateIndicator) -> &'a mut W { | ||
| 37 | self.bit(esi as u8 != 0) | ||
| 38 | } | ||
| 39 | |||
| 40 | #[doc = r"Sets the field bit"] | ||
| 41 | #[inline(always)] | ||
| 42 | #[allow(dead_code)] | ||
| 43 | pub fn set_bit(self) -> &'a mut W { | ||
| 44 | self.bit(true) | ||
| 45 | } | ||
| 46 | #[doc = r"Clears the field bit"] | ||
| 47 | #[inline(always)] | ||
| 48 | #[allow(dead_code)] | ||
| 49 | pub fn clear_bit(self) -> &'a mut W { | ||
| 50 | self.bit(false) | ||
| 51 | } | ||
| 52 | #[doc = r"Writes raw bits to the field"] | ||
| 53 | #[inline(always)] | ||
| 54 | #[allow(dead_code)] | ||
| 55 | pub fn bit(self, value: bool) -> &'a mut W { | ||
| 56 | self.w.bits[0] = (self.w.bits[0] & !(0x01 << 31)) | (((value as u32) & 0x01) << 31); | ||
| 57 | self.w | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | #[doc = "Write proxy for field `XTD`"] | ||
| 62 | pub(crate) struct XTD_W<'a> { | ||
| 63 | w: &'a mut W, | ||
| 64 | } | ||
| 65 | impl<'a> XTD_W<'a> { | ||
| 66 | #[doc = r"Writes `variant` to the field"] | ||
| 67 | #[inline(always)] | ||
| 68 | #[allow(dead_code)] | ||
| 69 | pub fn set_id_type(self, idt: IdType) -> &'a mut W { | ||
| 70 | self.bit(idt as u8 != 0) | ||
| 71 | } | ||
| 72 | |||
| 73 | #[doc = r"Sets the field bit"] | ||
| 74 | #[inline(always)] | ||
| 75 | #[allow(dead_code)] | ||
| 76 | pub fn set_bit(self) -> &'a mut W { | ||
| 77 | self.bit(true) | ||
| 78 | } | ||
| 79 | #[doc = r"Clears the field bit"] | ||
| 80 | #[inline(always)] | ||
| 81 | #[allow(dead_code)] | ||
| 82 | pub fn clear_bit(self) -> &'a mut W { | ||
| 83 | self.bit(false) | ||
| 84 | } | ||
| 85 | #[doc = r"Writes raw bits to the field"] | ||
| 86 | #[inline(always)] | ||
| 87 | #[allow(dead_code)] | ||
| 88 | pub fn bit(self, value: bool) -> &'a mut W { | ||
| 89 | self.w.bits[0] = (self.w.bits[0] & !(0x01 << 30)) | (((value as u32) & 0x01) << 30); | ||
| 90 | self.w | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | #[doc = "Write proxy for field `RTR`"] | ||
| 95 | pub(crate) struct RTR_W<'a> { | ||
| 96 | w: &'a mut W, | ||
| 97 | } | ||
| 98 | impl<'a> RTR_W<'a> { | ||
| 99 | #[doc = r"Writes `variant` to the field"] | ||
| 100 | #[inline(always)] | ||
| 101 | #[allow(dead_code)] | ||
| 102 | pub fn set_rtr(self, rtr: RemoteTransmissionRequest) -> &'a mut W { | ||
| 103 | self.bit(rtr as u8 != 0) | ||
| 104 | } | ||
| 105 | |||
| 106 | #[doc = r"Sets the field bit"] | ||
| 107 | #[inline(always)] | ||
| 108 | #[allow(dead_code)] | ||
| 109 | pub fn set_bit(self) -> &'a mut W { | ||
| 110 | self.bit(true) | ||
| 111 | } | ||
| 112 | #[doc = r"Clears the field bit"] | ||
| 113 | #[inline(always)] | ||
| 114 | #[allow(dead_code)] | ||
| 115 | pub fn clear_bit(self) -> &'a mut W { | ||
| 116 | self.bit(false) | ||
| 117 | } | ||
| 118 | #[doc = r"Writes raw bits to the field"] | ||
| 119 | #[inline(always)] | ||
| 120 | #[allow(dead_code)] | ||
| 121 | pub fn bit(self, value: bool) -> &'a mut W { | ||
| 122 | self.w.bits[0] = (self.w.bits[0] & !(0x01 << 29)) | (((value as u32) & 0x01) << 29); | ||
| 123 | self.w | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | #[doc = "Write proxy for field `ID`"] | ||
| 128 | pub(crate) struct ID_W<'a> { | ||
| 129 | w: &'a mut W, | ||
| 130 | } | ||
| 131 | impl<'a> ID_W<'a> { | ||
| 132 | #[doc = r"Writes raw bits to the field"] | ||
| 133 | #[inline(always)] | ||
| 134 | #[allow(dead_code)] | ||
| 135 | pub unsafe fn bits(self, value: u32) -> &'a mut W { | ||
| 136 | self.w.bits[0] = (self.w.bits[0] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF); | ||
| 137 | self.w | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | #[doc = "Write proxy for field `DLC`"] | ||
| 142 | pub(crate) struct DLC_W<'a> { | ||
| 143 | w: &'a mut W, | ||
| 144 | } | ||
| 145 | impl<'a> DLC_W<'a> { | ||
| 146 | #[doc = r"Writes raw bits to the field"] | ||
| 147 | #[inline(always)] | ||
| 148 | #[allow(dead_code)] | ||
| 149 | pub unsafe fn bits(self, value: u8) -> &'a mut W { | ||
| 150 | self.w.bits[1] = (self.w.bits[1] & !(0x0F << 16)) | (((value as u32) & 0x0F) << 16); | ||
| 151 | self.w | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | #[doc = "Write proxy for field `BRS`"] | ||
| 156 | pub(crate) struct BRS_W<'a> { | ||
| 157 | w: &'a mut W, | ||
| 158 | } | ||
| 159 | impl<'a> BRS_W<'a> { | ||
| 160 | #[doc = r"Writes `variant` to the field"] | ||
| 161 | #[inline(always)] | ||
| 162 | #[allow(dead_code)] | ||
| 163 | pub fn set_brs(self, brs: BitRateSwitching) -> &'a mut W { | ||
| 164 | self.bit(brs as u8 != 0) | ||
| 165 | } | ||
| 166 | |||
| 167 | #[doc = r"Sets the field bit"] | ||
| 168 | #[inline(always)] | ||
| 169 | #[allow(dead_code)] | ||
| 170 | pub fn set_bit(self) -> &'a mut W { | ||
| 171 | self.bit(true) | ||
| 172 | } | ||
| 173 | #[doc = r"Clears the field bit"] | ||
| 174 | #[inline(always)] | ||
| 175 | #[allow(dead_code)] | ||
| 176 | pub fn clear_bit(self) -> &'a mut W { | ||
| 177 | self.bit(false) | ||
| 178 | } | ||
| 179 | #[doc = r"Writes raw bits to the field"] | ||
| 180 | #[inline(always)] | ||
| 181 | #[allow(dead_code)] | ||
| 182 | pub fn bit(self, value: bool) -> &'a mut W { | ||
| 183 | self.w.bits[1] = (self.w.bits[1] & !(0x01 << 20)) | (((value as u32) & 0x01) << 20); | ||
| 184 | self.w | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | #[doc = "Write proxy for field `FDF`"] | ||
| 189 | pub(crate) struct FDF_W<'a> { | ||
| 190 | w: &'a mut W, | ||
| 191 | } | ||
| 192 | impl<'a> FDF_W<'a> { | ||
| 193 | #[doc = r"Writes `variant` to the field"] | ||
| 194 | #[inline(always)] | ||
| 195 | #[allow(dead_code)] | ||
| 196 | pub fn set_format(self, fdf: FrameFormat) -> &'a mut W { | ||
| 197 | self.bit(fdf as u8 != 0) | ||
| 198 | } | ||
| 199 | |||
| 200 | #[doc = r"Sets the field bit"] | ||
| 201 | #[inline(always)] | ||
| 202 | #[allow(dead_code)] | ||
| 203 | pub fn set_bit(self) -> &'a mut W { | ||
| 204 | self.bit(true) | ||
| 205 | } | ||
| 206 | #[doc = r"Clears the field bit"] | ||
| 207 | #[inline(always)] | ||
| 208 | #[allow(dead_code)] | ||
| 209 | pub fn clear_bit(self) -> &'a mut W { | ||
| 210 | self.bit(false) | ||
| 211 | } | ||
| 212 | #[doc = r"Writes raw bits to the field"] | ||
| 213 | #[inline(always)] | ||
| 214 | #[allow(dead_code)] | ||
| 215 | pub fn bit(self, value: bool) -> &'a mut W { | ||
| 216 | self.w.bits[1] = (self.w.bits[1] & !(0x01 << 21)) | (((value as u32) & 0x01) << 21); | ||
| 217 | self.w | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | #[doc = "Reader of field `EFC`"] | ||
| 222 | pub(crate) type EFC_R = generic::R<bool, EventControl>; | ||
| 223 | impl EFC_R { | ||
| 224 | pub fn to_event_control(&self) -> EventControl { | ||
| 225 | match self.bit() { | ||
| 226 | false => EventControl::DoNotStore, | ||
| 227 | true => EventControl::Store, | ||
| 228 | } | ||
| 229 | } | ||
| 230 | } | ||
| 231 | #[doc = "Write proxy for field `EFC`"] | ||
| 232 | pub(crate) struct EFC_W<'a> { | ||
| 233 | w: &'a mut W, | ||
| 234 | } | ||
| 235 | impl<'a> EFC_W<'a> { | ||
| 236 | #[doc = r"Writes `variant` to the field"] | ||
| 237 | #[inline(always)] | ||
| 238 | #[allow(dead_code)] | ||
| 239 | pub fn set_event_control(self, efc: EventControl) -> &'a mut W { | ||
| 240 | self.bit(match efc { | ||
| 241 | EventControl::DoNotStore => false, | ||
| 242 | EventControl::Store => true, | ||
| 243 | }) | ||
| 244 | } | ||
| 245 | |||
| 246 | #[doc = r"Sets the field bit"] | ||
| 247 | #[inline(always)] | ||
| 248 | #[allow(dead_code)] | ||
| 249 | pub fn set_bit(self) -> &'a mut W { | ||
| 250 | self.bit(true) | ||
| 251 | } | ||
| 252 | #[doc = r"Clears the field bit"] | ||
| 253 | #[inline(always)] | ||
| 254 | #[allow(dead_code)] | ||
| 255 | pub fn clear_bit(self) -> &'a mut W { | ||
| 256 | self.bit(false) | ||
| 257 | } | ||
| 258 | #[doc = r"Writes raw bits to the field"] | ||
| 259 | #[inline(always)] | ||
| 260 | #[allow(dead_code)] | ||
| 261 | pub fn bit(self, value: bool) -> &'a mut W { | ||
| 262 | self.w.bits[1] = (self.w.bits[1] & !(0x01 << 23)) | (((value as u32) & 0x01) << 23); | ||
| 263 | self.w | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | struct Marker(u8); | ||
| 268 | impl From<Event> for Marker { | ||
| 269 | fn from(e: Event) -> Marker { | ||
| 270 | match e { | ||
| 271 | Event::NoEvent => Marker(0), | ||
| 272 | Event::Event(mm) => Marker(mm), | ||
| 273 | } | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | #[doc = "Reader of field `MM`"] | ||
| 278 | pub(crate) type MM_R = generic::R<u8, u8>; | ||
| 279 | #[doc = "Write proxy for field `MM`"] | ||
| 280 | pub(crate) struct MM_W<'a> { | ||
| 281 | w: &'a mut W, | ||
| 282 | } | ||
| 283 | impl<'a> MM_W<'a> { | ||
| 284 | #[doc = r"Writes raw bits to the field"] | ||
| 285 | #[inline(always)] | ||
| 286 | pub unsafe fn bits(self, value: u8) -> &'a mut W { | ||
| 287 | self.w.bits[1] = (self.w.bits[1] & !(0x7F << 24)) | (((value as u32) & 0x7F) << 24); | ||
| 288 | self.w | ||
| 289 | } | ||
| 290 | |||
| 291 | fn set_message_marker(self, mm: Marker) -> &'a mut W { | ||
| 292 | unsafe { self.bits(mm.0) } | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | impl R { | ||
| 297 | #[doc = "Byte 0 - Bits 0:28 - ID"] | ||
| 298 | #[inline(always)] | ||
| 299 | pub fn id(&self) -> ID_R { | ||
| 300 | ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32) | ||
| 301 | } | ||
| 302 | #[doc = "Byte 0 - Bit 29 - RTR"] | ||
| 303 | #[inline(always)] | ||
| 304 | pub fn rtr(&self) -> RTR_R { | ||
| 305 | RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0) | ||
| 306 | } | ||
| 307 | #[doc = "Byte 0 - Bit 30 - XTD"] | ||
| 308 | #[inline(always)] | ||
| 309 | pub fn xtd(&self) -> XTD_R { | ||
| 310 | XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0) | ||
| 311 | } | ||
| 312 | #[doc = "Byte 0 - Bit 30 - ESI"] | ||
| 313 | #[inline(always)] | ||
| 314 | pub fn esi(&self) -> ESI_R { | ||
| 315 | ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0) | ||
| 316 | } | ||
| 317 | #[doc = "Byte 1 - Bits 16:19 - DLC"] | ||
| 318 | #[inline(always)] | ||
| 319 | pub fn dlc(&self) -> DLC_R { | ||
| 320 | DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8) | ||
| 321 | } | ||
| 322 | #[doc = "Byte 1 - Bits 20 - BRS"] | ||
| 323 | #[inline(always)] | ||
| 324 | pub fn brs(&self) -> BRS_R { | ||
| 325 | BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0) | ||
| 326 | } | ||
| 327 | #[doc = "Byte 1 - Bits 20 - FDF"] | ||
| 328 | #[inline(always)] | ||
| 329 | pub fn fdf(&self) -> FDF_R { | ||
| 330 | FDF_R::new(((self.bits[1] >> 21) & 0x01) != 0) | ||
| 331 | } | ||
| 332 | #[doc = "Byte 1 - Bits 23 - EFC"] | ||
| 333 | #[inline(always)] | ||
| 334 | pub fn efc(&self) -> EFC_R { | ||
| 335 | EFC_R::new(((self.bits[1] >> 23) & 0x01) != 0) | ||
| 336 | } | ||
| 337 | #[doc = "Byte 1 - Bits 24:31 - MM"] | ||
| 338 | #[inline(always)] | ||
| 339 | pub fn mm(&self) -> MM_R { | ||
| 340 | MM_R::new(((self.bits[1] >> 24) & 0xFF) as u8) | ||
| 341 | } | ||
| 342 | pub fn to_data_length(&self) -> DataLength { | ||
| 343 | let dlc = self.dlc().bits(); | ||
| 344 | let ff = self.fdf().frame_format(); | ||
| 345 | let len = if ff == FrameFormat::Fdcan { | ||
| 346 | // See RM0433 Rev 7 Table 475. DLC coding | ||
| 347 | match dlc { | ||
| 348 | 0..=8 => dlc, | ||
| 349 | 9 => 12, | ||
| 350 | 10 => 16, | ||
| 351 | 11 => 20, | ||
| 352 | 12 => 24, | ||
| 353 | 13 => 32, | ||
| 354 | 14 => 48, | ||
| 355 | 15 => 64, | ||
| 356 | _ => panic!("DLC > 15"), | ||
| 357 | } | ||
| 358 | } else { | ||
| 359 | match dlc { | ||
| 360 | 0..=8 => dlc, | ||
| 361 | 9..=15 => 8, | ||
| 362 | _ => panic!("DLC > 15"), | ||
| 363 | } | ||
| 364 | }; | ||
| 365 | DataLength::new(len, ff) | ||
| 366 | } | ||
| 367 | pub fn to_event(&self) -> Event { | ||
| 368 | let mm = self.mm().bits(); | ||
| 369 | let efc = self.efc().to_event_control(); | ||
| 370 | match efc { | ||
| 371 | EventControl::DoNotStore => Event::NoEvent, | ||
| 372 | EventControl::Store => Event::Event(mm), | ||
| 373 | } | ||
| 374 | } | ||
| 375 | } | ||
| 376 | impl W { | ||
| 377 | #[doc = "Byte 0 - Bits 0:28 - ID"] | ||
| 378 | #[inline(always)] | ||
| 379 | pub fn id(&mut self) -> ID_W { | ||
| 380 | ID_W { w: self } | ||
| 381 | } | ||
| 382 | #[doc = "Byte 0 - Bit 29 - RTR"] | ||
| 383 | #[inline(always)] | ||
| 384 | pub fn rtr(&mut self) -> RTR_W { | ||
| 385 | RTR_W { w: self } | ||
| 386 | } | ||
| 387 | #[doc = "Byte 0 - Bit 30 - XTD"] | ||
| 388 | #[inline(always)] | ||
| 389 | pub fn xtd(&mut self) -> XTD_W { | ||
| 390 | XTD_W { w: self } | ||
| 391 | } | ||
| 392 | #[doc = "Byte 0 - Bit 31 - ESI"] | ||
| 393 | #[inline(always)] | ||
| 394 | pub fn esi(&mut self) -> ESI_W { | ||
| 395 | ESI_W { w: self } | ||
| 396 | } | ||
| 397 | #[doc = "Byte 1 - Bit 16:19 - DLC"] | ||
| 398 | #[inline(always)] | ||
| 399 | pub fn dlc(&mut self) -> DLC_W { | ||
| 400 | DLC_W { w: self } | ||
| 401 | } | ||
| 402 | #[doc = "Byte 1 - Bit 20 - BRS"] | ||
| 403 | #[inline(always)] | ||
| 404 | pub fn brs(&mut self) -> BRS_W { | ||
| 405 | BRS_W { w: self } | ||
| 406 | } | ||
| 407 | #[doc = "Byte 1 - Bit 21 - FDF"] | ||
| 408 | #[inline(always)] | ||
| 409 | pub fn fdf(&mut self) -> FDF_W { | ||
| 410 | FDF_W { w: self } | ||
| 411 | } | ||
| 412 | #[doc = "Byte 1 - Bit 23 - EFC"] | ||
| 413 | #[inline(always)] | ||
| 414 | pub fn efc(&mut self) -> EFC_W { | ||
| 415 | EFC_W { w: self } | ||
| 416 | } | ||
| 417 | #[doc = "Byte 1 - Bit 24:31 - MM"] | ||
| 418 | #[inline(always)] | ||
| 419 | pub fn mm(&mut self) -> MM_W { | ||
| 420 | MM_W { w: self } | ||
| 421 | } | ||
| 422 | #[doc = "Convenience function for setting the data length and frame format"] | ||
| 423 | #[inline(always)] | ||
| 424 | pub fn set_len(&mut self, dl: impl Into<DataLength>) -> &mut Self { | ||
| 425 | let dl: DataLength = dl.into(); | ||
| 426 | self.fdf().set_format(dl.into()); | ||
| 427 | unsafe { self.dlc().bits(dl.dlc()) } | ||
| 428 | } | ||
| 429 | pub fn set_event(&mut self, event: Event) -> &mut Self { | ||
| 430 | self.mm().set_message_marker(event.into()); | ||
| 431 | self.efc().set_event_control(event.into()) | ||
| 432 | } | ||
| 433 | } | ||
diff --git a/embassy-stm32/src/can/fd/message_ram/txevent_element.rs b/embassy-stm32/src/can/fd/message_ram/txevent_element.rs new file mode 100644 index 000000000..817a4449f --- /dev/null +++ b/embassy-stm32/src/can/fd/message_ram/txevent_element.rs | |||
| @@ -0,0 +1,138 @@ | |||
| 1 | // Note: This file is copied and modified from fdcan crate by Richard Meadows | ||
| 2 | |||
| 3 | #![allow(non_camel_case_types)] | ||
| 4 | #![allow(non_snake_case)] | ||
| 5 | #![allow(unused)] | ||
| 6 | |||
| 7 | use super::common::{BRS_R, DLC_R, ESI_R, RTR_R, XTD_R}; | ||
| 8 | use super::generic; | ||
| 9 | |||
| 10 | #[doc = "Reader of register TxEventElement"] | ||
| 11 | pub(crate) type R = generic::R<super::TxEventElementType, super::TxEventElement>; | ||
| 12 | // #[doc = "Writer for register TxEventElement"] | ||
| 13 | // pub(crate) type W = generic::W<super::TxEventElementType, super::TxEventElement>; | ||
| 14 | #[doc = "Register TxEventElement `reset()`'s"] | ||
| 15 | impl generic::ResetValue for super::TxEventElement { | ||
| 16 | type Type = super::TxEventElementType; | ||
| 17 | #[inline(always)] | ||
| 18 | fn reset_value() -> Self::Type { | ||
| 19 | [0, 0] | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | #[doc = "Reader of field `ID`"] | ||
| 24 | pub(crate) type ID_R = generic::R<u32, u32>; | ||
| 25 | |||
| 26 | #[doc = "Reader of field `TXTS`"] | ||
| 27 | pub(crate) type TXTS_R = generic::R<u16, u16>; | ||
| 28 | |||
| 29 | #[derive(Clone, Copy, Debug, PartialEq)] | ||
| 30 | pub(crate) enum DataLengthFormat { | ||
| 31 | StandardLength = 0, | ||
| 32 | FDCANLength = 1, | ||
| 33 | } | ||
| 34 | impl From<DataLengthFormat> for bool { | ||
| 35 | #[inline(always)] | ||
| 36 | fn from(dlf: DataLengthFormat) -> Self { | ||
| 37 | dlf as u8 != 0 | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | #[doc = "Reader of field `EDL`"] | ||
| 42 | pub(crate) type EDL_R = generic::R<bool, DataLengthFormat>; | ||
| 43 | impl EDL_R { | ||
| 44 | pub fn data_length_format(&self) -> DataLengthFormat { | ||
| 45 | match self.bits() { | ||
| 46 | false => DataLengthFormat::StandardLength, | ||
| 47 | true => DataLengthFormat::FDCANLength, | ||
| 48 | } | ||
| 49 | } | ||
| 50 | pub fn is_standard_length(&self) -> bool { | ||
| 51 | *self == DataLengthFormat::StandardLength | ||
| 52 | } | ||
| 53 | pub fn is_fdcan_length(&self) -> bool { | ||
| 54 | *self == DataLengthFormat::FDCANLength | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | #[derive(Clone, Copy, Debug, PartialEq)] | ||
| 59 | pub(crate) enum EventType { | ||
| 60 | //_Reserved = 0b00, | ||
| 61 | TxEvent = 0b01, | ||
| 62 | TxDespiteAbort = 0b10, | ||
| 63 | //_Reserved = 0b10, | ||
| 64 | } | ||
| 65 | |||
| 66 | #[doc = "Reader of field `EFC`"] | ||
| 67 | pub(crate) type EFC_R = generic::R<u8, EventType>; | ||
| 68 | impl EFC_R { | ||
| 69 | pub fn event_type(&self) -> EventType { | ||
| 70 | match self.bits() { | ||
| 71 | 0b01 => EventType::TxEvent, | ||
| 72 | 0b10 => EventType::TxDespiteAbort, | ||
| 73 | _ => unimplemented!(), | ||
| 74 | } | ||
| 75 | } | ||
| 76 | pub fn is_tx_event(&self) -> bool { | ||
| 77 | self.event_type() == EventType::TxEvent | ||
| 78 | } | ||
| 79 | pub fn is_despite_abort(&self) -> bool { | ||
| 80 | self.event_type() == EventType::TxDespiteAbort | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | #[doc = "Reader of field `MM`"] | ||
| 85 | pub(crate) type MM_R = generic::R<u8, u8>; | ||
| 86 | |||
| 87 | impl R { | ||
| 88 | #[doc = "Byte 0 - Bits 0:28 - ID"] | ||
| 89 | #[inline(always)] | ||
| 90 | pub fn id(&self) -> ID_R { | ||
| 91 | ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32) | ||
| 92 | } | ||
| 93 | #[doc = "Byte 0 - Bit 29 - RTR"] | ||
| 94 | #[inline(always)] | ||
| 95 | pub fn rtr(&self) -> RTR_R { | ||
| 96 | RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0) | ||
| 97 | } | ||
| 98 | #[doc = "Byte 0 - Bit 30 - XTD"] | ||
| 99 | #[inline(always)] | ||
| 100 | pub fn xtd(&self) -> XTD_R { | ||
| 101 | XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0) | ||
| 102 | } | ||
| 103 | #[doc = "Byte 0 - Bit 30 - ESI"] | ||
| 104 | #[inline(always)] | ||
| 105 | pub fn esi(&self) -> ESI_R { | ||
| 106 | ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0) | ||
| 107 | } | ||
| 108 | #[doc = "Byte 1 - Bits 0:15 - TXTS"] | ||
| 109 | #[inline(always)] | ||
| 110 | pub fn txts(&self) -> TXTS_R { | ||
| 111 | TXTS_R::new(((self.bits[1]) & 0xFFFF) as u16) | ||
| 112 | } | ||
| 113 | #[doc = "Byte 1 - Bits 16:19 - DLC"] | ||
| 114 | #[inline(always)] | ||
| 115 | pub fn dlc(&self) -> DLC_R { | ||
| 116 | DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8) | ||
| 117 | } | ||
| 118 | #[doc = "Byte 1 - Bits 20 - BRS"] | ||
| 119 | #[inline(always)] | ||
| 120 | pub fn brs(&self) -> BRS_R { | ||
| 121 | BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0) | ||
| 122 | } | ||
| 123 | #[doc = "Byte 1 - Bits 21 - EDL"] | ||
| 124 | #[inline(always)] | ||
| 125 | pub fn edl(&self) -> EDL_R { | ||
| 126 | EDL_R::new(((self.bits[1] >> 21) & 0x01) != 0) | ||
| 127 | } | ||
| 128 | #[doc = "Byte 1 - Bits 22:23 - EFC"] | ||
| 129 | #[inline(always)] | ||
| 130 | pub fn efc(&self) -> EFC_R { | ||
| 131 | EFC_R::new(((self.bits[1] >> 22) & 0x03) as u8) | ||
| 132 | } | ||
| 133 | #[doc = "Byte 1 - Bits 24:31 - MM"] | ||
| 134 | #[inline(always)] | ||
| 135 | pub fn mm(&self) -> MM_R { | ||
| 136 | MM_R::new(((self.bits[1] >> 24) & 0xFF) as u8) | ||
| 137 | } | ||
| 138 | } | ||
diff --git a/embassy-stm32/src/can/fd/mod.rs b/embassy-stm32/src/can/fd/mod.rs new file mode 100644 index 000000000..271ca0b3c --- /dev/null +++ b/embassy-stm32/src/can/fd/mod.rs | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | //! Module containing that which is specific to fdcan hardware variant | ||
| 2 | |||
| 3 | pub mod config; | ||
| 4 | pub mod filter; | ||
| 5 | pub(crate) mod message_ram; | ||
| 6 | pub(crate) mod peripheral; | ||
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs new file mode 100644 index 000000000..0771d6fbb --- /dev/null +++ b/embassy-stm32/src/can/fd/peripheral.rs | |||
| @@ -0,0 +1,828 @@ | |||
| 1 | // Note: This file is copied and modified from fdcan crate by Richard Meadows | ||
| 2 | |||
| 3 | use core::convert::Infallible; | ||
| 4 | use core::slice; | ||
| 5 | |||
| 6 | use cfg_if::cfg_if; | ||
| 7 | |||
| 8 | use crate::can::enums::*; | ||
| 9 | use crate::can::fd::config::*; | ||
| 10 | use crate::can::fd::message_ram::enums::*; | ||
| 11 | use crate::can::fd::message_ram::{RegisterBlock, RxFifoElement, TxBufferElement}; | ||
| 12 | use crate::can::frame::*; | ||
| 13 | |||
| 14 | /// Loopback Mode | ||
| 15 | #[derive(Clone, Copy, Debug)] | ||
| 16 | enum LoopbackMode { | ||
| 17 | None, | ||
| 18 | Internal, | ||
| 19 | External, | ||
| 20 | } | ||
| 21 | |||
| 22 | pub struct Registers { | ||
| 23 | pub regs: &'static crate::pac::can::Fdcan, | ||
| 24 | pub msgram: &'static crate::pac::fdcanram::Fdcanram, | ||
| 25 | } | ||
| 26 | |||
| 27 | impl Registers { | ||
| 28 | fn tx_buffer_element(&self, bufidx: usize) -> &mut TxBufferElement { | ||
| 29 | &mut self.msg_ram_mut().transmit.tbsa[bufidx] | ||
| 30 | } | ||
| 31 | pub fn msg_ram_mut(&self) -> &mut RegisterBlock { | ||
| 32 | let ptr = self.msgram.as_ptr() as *mut RegisterBlock; | ||
| 33 | unsafe { &mut (*ptr) } | ||
| 34 | } | ||
| 35 | |||
| 36 | fn rx_fifo_element(&self, fifonr: usize, bufnum: usize) -> &mut RxFifoElement { | ||
| 37 | &mut self.msg_ram_mut().receive[fifonr].fxsa[bufnum] | ||
| 38 | } | ||
| 39 | |||
| 40 | pub fn read_classic(&self, fifonr: usize) -> Option<(ClassicFrame, u16)> { | ||
| 41 | // Fill level - do we have a msg? | ||
| 42 | if self.regs.rxfs(fifonr).read().ffl() < 1 { | ||
| 43 | return None; | ||
| 44 | } | ||
| 45 | |||
| 46 | let read_idx = self.regs.rxfs(fifonr).read().fgi(); | ||
| 47 | let mailbox = self.rx_fifo_element(fifonr, read_idx as usize); | ||
| 48 | |||
| 49 | let mut buffer: [u8; 8] = [0; 8]; | ||
| 50 | let maybe_header = extract_frame(mailbox, &mut buffer); | ||
| 51 | |||
| 52 | // Clear FIFO, reduces count and increments read buf | ||
| 53 | self.regs.rxfa(fifonr).modify(|w| w.set_fai(read_idx)); | ||
| 54 | |||
| 55 | match maybe_header { | ||
| 56 | Some((header, ts)) => { | ||
| 57 | let data = ClassicData::new(&buffer[0..header.len() as usize]); | ||
| 58 | Some((ClassicFrame::new(header, data.unwrap()), ts)) | ||
| 59 | } | ||
| 60 | None => None, | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | pub fn read_fd(&self, fifonr: usize) -> Option<(FdFrame, u16)> { | ||
| 65 | // Fill level - do we have a msg? | ||
| 66 | if self.regs.rxfs(fifonr).read().ffl() < 1 { | ||
| 67 | return None; | ||
| 68 | } | ||
| 69 | |||
| 70 | let read_idx = self.regs.rxfs(fifonr).read().fgi(); | ||
| 71 | let mailbox = self.rx_fifo_element(fifonr, read_idx as usize); | ||
| 72 | |||
| 73 | let mut buffer: [u8; 64] = [0; 64]; | ||
| 74 | let maybe_header = extract_frame(mailbox, &mut buffer); | ||
| 75 | |||
| 76 | // Clear FIFO, reduces count and increments read buf | ||
| 77 | self.regs.rxfa(fifonr).modify(|w| w.set_fai(read_idx)); | ||
| 78 | |||
| 79 | match maybe_header { | ||
| 80 | Some((header, ts)) => { | ||
| 81 | let data = FdData::new(&buffer[0..header.len() as usize]); | ||
| 82 | Some((FdFrame::new(header, data.unwrap()), ts)) | ||
| 83 | } | ||
| 84 | None => None, | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) { | ||
| 89 | // Fill level - do we have a msg? | ||
| 90 | //if self.regs.rxfs(fifonr).read().ffl() < 1 { return None; } | ||
| 91 | |||
| 92 | //let read_idx = self.regs.rxfs(fifonr).read().fgi(); | ||
| 93 | |||
| 94 | let mailbox = self.tx_buffer_element(bufidx); | ||
| 95 | |||
| 96 | mailbox.reset(); | ||
| 97 | put_tx_header(mailbox, header); | ||
| 98 | put_tx_data(mailbox, &buffer[..header.len() as usize]); | ||
| 99 | |||
| 100 | // Set <idx as Mailbox> as ready to transmit | ||
| 101 | self.regs.txbar().modify(|w| w.set_ar(bufidx, true)); | ||
| 102 | } | ||
| 103 | |||
| 104 | fn reg_to_error(value: u8) -> Option<BusError> { | ||
| 105 | match value { | ||
| 106 | //0b000 => None, | ||
| 107 | 0b001 => Some(BusError::Stuff), | ||
| 108 | 0b010 => Some(BusError::Form), | ||
| 109 | 0b011 => Some(BusError::Acknowledge), | ||
| 110 | 0b100 => Some(BusError::BitRecessive), | ||
| 111 | 0b101 => Some(BusError::BitDominant), | ||
| 112 | 0b110 => Some(BusError::Crc), | ||
| 113 | //0b111 => Some(BusError::NoError), | ||
| 114 | _ => None, | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | pub fn curr_error(&self) -> Option<BusError> { | ||
| 119 | let err = { self.regs.psr().read() }; | ||
| 120 | if err.bo() { | ||
| 121 | return Some(BusError::BusOff); | ||
| 122 | } else if err.ep() { | ||
| 123 | return Some(BusError::BusPassive); | ||
| 124 | } else if err.ew() { | ||
| 125 | return Some(BusError::BusWarning); | ||
| 126 | } else { | ||
| 127 | cfg_if! { | ||
| 128 | if #[cfg(stm32h7)] { | ||
| 129 | let lec = err.lec(); | ||
| 130 | } else { | ||
| 131 | let lec = err.lec().to_bits(); | ||
| 132 | } | ||
| 133 | } | ||
| 134 | if let Some(err) = Self::reg_to_error(lec) { | ||
| 135 | return Some(err); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | None | ||
| 139 | } | ||
| 140 | /// Returns if the tx queue is able to accept new messages without having to cancel an existing one | ||
| 141 | #[inline] | ||
| 142 | pub fn tx_queue_is_full(&self) -> bool { | ||
| 143 | self.regs.txfqs().read().tfqf() | ||
| 144 | } | ||
| 145 | |||
| 146 | #[inline] | ||
| 147 | pub fn has_pending_frame(&self, idx: usize) -> bool { | ||
| 148 | self.regs.txbrp().read().trp(idx) | ||
| 149 | } | ||
| 150 | |||
| 151 | /// Returns `Ok` when the mailbox is free or if it contains pending frame with a | ||
| 152 | /// lower priority (higher ID) than the identifier `id`. | ||
| 153 | #[inline] | ||
| 154 | pub fn is_available(&self, bufidx: usize, id: &embedded_can::Id) -> bool { | ||
| 155 | if self.has_pending_frame(bufidx) { | ||
| 156 | let mailbox = self.tx_buffer_element(bufidx); | ||
| 157 | |||
| 158 | let header_reg = mailbox.header.read(); | ||
| 159 | let old_id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); | ||
| 160 | |||
| 161 | *id > old_id | ||
| 162 | } else { | ||
| 163 | true | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | /// Attempts to abort the sending of a frame that is pending in a mailbox. | ||
| 168 | /// | ||
| 169 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be | ||
| 170 | /// aborted, this function has no effect and returns `false`. | ||
| 171 | /// | ||
| 172 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function | ||
| 173 | /// returns `true`. | ||
| 174 | #[inline] | ||
| 175 | pub fn abort(&self, bufidx: usize) -> bool { | ||
| 176 | let can = self.regs; | ||
| 177 | |||
| 178 | // Check if there is a request pending to abort | ||
| 179 | if self.has_pending_frame(bufidx) { | ||
| 180 | // Abort Request | ||
| 181 | can.txbcr().write(|w| w.set_cr(bufidx, true)); | ||
| 182 | |||
| 183 | // Wait for the abort request to be finished. | ||
| 184 | loop { | ||
| 185 | if can.txbcf().read().cf(bufidx) { | ||
| 186 | // Return false when a transmission has occured | ||
| 187 | break can.txbto().read().to(bufidx) == false; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | } else { | ||
| 191 | false | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | #[inline] | ||
| 196 | //fn abort_pending_mailbox<PTX, R>(&mut self, idx: Mailbox, pending: PTX) -> Option<R> | ||
| 197 | pub fn abort_pending_mailbox(&self, bufidx: usize) -> Option<ClassicFrame> | ||
| 198 | //where | ||
| 199 | // PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R, | ||
| 200 | { | ||
| 201 | if self.abort(bufidx) { | ||
| 202 | let mailbox = self.tx_buffer_element(bufidx); | ||
| 203 | |||
| 204 | let header_reg = mailbox.header.read(); | ||
| 205 | let id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); | ||
| 206 | |||
| 207 | let len = match header_reg.to_data_length() { | ||
| 208 | DataLength::Fdcan(len) => len, | ||
| 209 | DataLength::Classic(len) => len, | ||
| 210 | }; | ||
| 211 | if len as usize > ClassicFrame::MAX_DATA_LEN { | ||
| 212 | return None; | ||
| 213 | } | ||
| 214 | |||
| 215 | //let tx_ram = self.tx_msg_ram(); | ||
| 216 | let mut data = [0u8; 64]; | ||
| 217 | data_from_tx_buffer(&mut data, mailbox, len as usize); | ||
| 218 | |||
| 219 | let cd = ClassicData::new(&data).unwrap(); | ||
| 220 | Some(ClassicFrame::new(Header::new(id, len, header_reg.rtr().bit()), cd)) | ||
| 221 | } else { | ||
| 222 | // Abort request failed because the frame was already sent (or being sent) on | ||
| 223 | // the bus. All mailboxes are now free. This can happen for small prescaler | ||
| 224 | // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR | ||
| 225 | // has preempted the execution. | ||
| 226 | None | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 230 | #[inline] | ||
| 231 | //fn abort_pending_mailbox<PTX, R>(&mut self, idx: Mailbox, pending: PTX) -> Option<R> | ||
| 232 | pub fn abort_pending_fd_mailbox(&self, bufidx: usize) -> Option<FdFrame> | ||
| 233 | //where | ||
| 234 | // PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R, | ||
| 235 | { | ||
| 236 | if self.abort(bufidx) { | ||
| 237 | let mailbox = self.tx_buffer_element(bufidx); | ||
| 238 | |||
| 239 | let header_reg = mailbox.header.read(); | ||
| 240 | let id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); | ||
| 241 | |||
| 242 | let len = match header_reg.to_data_length() { | ||
| 243 | DataLength::Fdcan(len) => len, | ||
| 244 | DataLength::Classic(len) => len, | ||
| 245 | }; | ||
| 246 | if len as usize > FdFrame::MAX_DATA_LEN { | ||
| 247 | return None; | ||
| 248 | } | ||
| 249 | |||
| 250 | //let tx_ram = self.tx_msg_ram(); | ||
| 251 | let mut data = [0u8; 64]; | ||
| 252 | data_from_tx_buffer(&mut data, mailbox, len as usize); | ||
| 253 | |||
| 254 | let cd = FdData::new(&data).unwrap(); | ||
| 255 | |||
| 256 | let header = if header_reg.fdf().frame_format() == FrameFormat::Fdcan { | ||
| 257 | Header::new_fd(id, len, header_reg.rtr().bit(), header_reg.brs().bit()) | ||
| 258 | } else { | ||
| 259 | Header::new(id, len, header_reg.rtr().bit()) | ||
| 260 | }; | ||
| 261 | |||
| 262 | Some(FdFrame::new(header, cd)) | ||
| 263 | } else { | ||
| 264 | // Abort request failed because the frame was already sent (or being sent) on | ||
| 265 | // the bus. All mailboxes are now free. This can happen for small prescaler | ||
| 266 | // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR | ||
| 267 | // has preempted the execution. | ||
| 268 | None | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | /// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can | ||
| 273 | /// be preserved. | ||
| 274 | //pub fn transmit_preserve<PTX, P>( | ||
| 275 | pub fn write_classic(&self, frame: &ClassicFrame) -> nb::Result<Option<ClassicFrame>, Infallible> { | ||
| 276 | let queue_is_full = self.tx_queue_is_full(); | ||
| 277 | |||
| 278 | let id = frame.header().id(); | ||
| 279 | |||
| 280 | // If the queue is full, | ||
| 281 | // Discard the first slot with a lower priority message | ||
| 282 | let (idx, pending_frame) = if queue_is_full { | ||
| 283 | if self.is_available(0, id) { | ||
| 284 | (0, self.abort_pending_mailbox(0)) | ||
| 285 | } else if self.is_available(1, id) { | ||
| 286 | (1, self.abort_pending_mailbox(1)) | ||
| 287 | } else if self.is_available(2, id) { | ||
| 288 | (2, self.abort_pending_mailbox(2)) | ||
| 289 | } else { | ||
| 290 | // For now we bail when there is no lower priority slot available | ||
| 291 | // Can this lead to priority inversion? | ||
| 292 | return Err(nb::Error::WouldBlock); | ||
| 293 | } | ||
| 294 | } else { | ||
| 295 | // Read the Write Pointer | ||
| 296 | let idx = self.regs.txfqs().read().tfqpi(); | ||
| 297 | |||
| 298 | (idx, None) | ||
| 299 | }; | ||
| 300 | |||
| 301 | self.put_tx_frame(idx as usize, frame.header(), frame.data()); | ||
| 302 | |||
| 303 | Ok(pending_frame) | ||
| 304 | } | ||
| 305 | |||
| 306 | /// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can | ||
| 307 | /// be preserved. | ||
| 308 | //pub fn transmit_preserve<PTX, P>( | ||
| 309 | pub fn write_fd(&self, frame: &FdFrame) -> nb::Result<Option<FdFrame>, Infallible> { | ||
| 310 | let queue_is_full = self.tx_queue_is_full(); | ||
| 311 | |||
| 312 | let id = frame.header().id(); | ||
| 313 | |||
| 314 | // If the queue is full, | ||
| 315 | // Discard the first slot with a lower priority message | ||
| 316 | let (idx, pending_frame) = if queue_is_full { | ||
| 317 | if self.is_available(0, id) { | ||
| 318 | (0, self.abort_pending_fd_mailbox(0)) | ||
| 319 | } else if self.is_available(1, id) { | ||
| 320 | (1, self.abort_pending_fd_mailbox(1)) | ||
| 321 | } else if self.is_available(2, id) { | ||
| 322 | (2, self.abort_pending_fd_mailbox(2)) | ||
| 323 | } else { | ||
| 324 | // For now we bail when there is no lower priority slot available | ||
| 325 | // Can this lead to priority inversion? | ||
| 326 | return Err(nb::Error::WouldBlock); | ||
| 327 | } | ||
| 328 | } else { | ||
| 329 | // Read the Write Pointer | ||
| 330 | let idx = self.regs.txfqs().read().tfqpi(); | ||
| 331 | |||
| 332 | (idx, None) | ||
| 333 | }; | ||
| 334 | |||
| 335 | self.put_tx_frame(idx as usize, frame.header(), frame.data()); | ||
| 336 | |||
| 337 | Ok(pending_frame) | ||
| 338 | } | ||
| 339 | |||
| 340 | #[inline] | ||
| 341 | fn reset_msg_ram(&mut self) { | ||
| 342 | self.msg_ram_mut().reset(); | ||
| 343 | } | ||
| 344 | |||
| 345 | #[inline] | ||
| 346 | fn enter_init_mode(&mut self) { | ||
| 347 | self.regs.cccr().modify(|w| w.set_init(true)); | ||
| 348 | while false == self.regs.cccr().read().init() {} | ||
| 349 | self.regs.cccr().modify(|w| w.set_cce(true)); | ||
| 350 | } | ||
| 351 | |||
| 352 | /// Enables or disables loopback mode: Internally connects the TX and RX | ||
| 353 | /// signals together. | ||
| 354 | #[inline] | ||
| 355 | fn set_loopback_mode(&mut self, mode: LoopbackMode) { | ||
| 356 | let (test, mon, lbck) = match mode { | ||
| 357 | LoopbackMode::None => (false, false, false), | ||
| 358 | LoopbackMode::Internal => (true, true, true), | ||
| 359 | LoopbackMode::External => (true, false, true), | ||
| 360 | }; | ||
| 361 | |||
| 362 | self.set_test_mode(test); | ||
| 363 | self.set_bus_monitoring_mode(mon); | ||
| 364 | |||
| 365 | self.regs.test().modify(|w| w.set_lbck(lbck)); | ||
| 366 | } | ||
| 367 | |||
| 368 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. | ||
| 369 | #[inline] | ||
| 370 | fn set_bus_monitoring_mode(&mut self, enabled: bool) { | ||
| 371 | self.regs.cccr().modify(|w| w.set_mon(enabled)); | ||
| 372 | } | ||
| 373 | |||
| 374 | #[inline] | ||
| 375 | fn set_restricted_operations(&mut self, enabled: bool) { | ||
| 376 | self.regs.cccr().modify(|w| w.set_asm(enabled)); | ||
| 377 | } | ||
| 378 | |||
| 379 | #[inline] | ||
| 380 | fn set_normal_operations(&mut self, _enabled: bool) { | ||
| 381 | self.set_loopback_mode(LoopbackMode::None); | ||
| 382 | } | ||
| 383 | |||
| 384 | #[inline] | ||
| 385 | fn set_test_mode(&mut self, enabled: bool) { | ||
| 386 | self.regs.cccr().modify(|w| w.set_test(enabled)); | ||
| 387 | } | ||
| 388 | |||
| 389 | #[inline] | ||
| 390 | fn set_power_down_mode(&mut self, enabled: bool) { | ||
| 391 | self.regs.cccr().modify(|w| w.set_csr(enabled)); | ||
| 392 | while self.regs.cccr().read().csa() != enabled {} | ||
| 393 | } | ||
| 394 | |||
| 395 | /// Moves out of PoweredDownMode and into ConfigMode | ||
| 396 | #[inline] | ||
| 397 | pub fn into_config_mode(mut self, _config: FdCanConfig) { | ||
| 398 | self.set_power_down_mode(false); | ||
| 399 | self.enter_init_mode(); | ||
| 400 | |||
| 401 | self.reset_msg_ram(); | ||
| 402 | |||
| 403 | // check the FDCAN core matches our expections | ||
| 404 | assert!( | ||
| 405 | self.regs.crel().read().rel() == 3, | ||
| 406 | "Expected FDCAN core major release 3" | ||
| 407 | ); | ||
| 408 | assert!( | ||
| 409 | self.regs.endn().read().etv() == 0x87654321_u32, | ||
| 410 | "Error reading endianness test value from FDCAN core" | ||
| 411 | ); | ||
| 412 | |||
| 413 | // Framework specific settings are set here | ||
| 414 | |||
| 415 | // set TxBuffer to Queue Mode | ||
| 416 | self.regs.txbc().write(|w| w.set_tfqm(true)); | ||
| 417 | |||
| 418 | // set standard filters list size to 28 | ||
| 419 | // set extended filters list size to 8 | ||
| 420 | // REQUIRED: we use the memory map as if these settings are set | ||
| 421 | // instead of re-calculating them. | ||
| 422 | #[cfg(not(stm32h7))] | ||
| 423 | { | ||
| 424 | self.regs.rxgfc().modify(|w| { | ||
| 425 | w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX); | ||
| 426 | w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX); | ||
| 427 | }); | ||
| 428 | } | ||
| 429 | #[cfg(stm32h7)] | ||
| 430 | { | ||
| 431 | self.regs | ||
| 432 | .sidfc() | ||
| 433 | .modify(|w| w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX)); | ||
| 434 | self.regs | ||
| 435 | .xidfc() | ||
| 436 | .modify(|w| w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX)); | ||
| 437 | } | ||
| 438 | |||
| 439 | /* | ||
| 440 | for fid in 0..crate::can::message_ram::STANDARD_FILTER_MAX { | ||
| 441 | self.set_standard_filter((fid as u8).into(), StandardFilter::disable()); | ||
| 442 | } | ||
| 443 | for fid in 0..Ecrate::can::message_ram::XTENDED_FILTER_MAX { | ||
| 444 | self.set_extended_filter(fid.into(), ExtendedFilter::disable()); | ||
| 445 | } | ||
| 446 | */ | ||
| 447 | } | ||
| 448 | |||
| 449 | /// Disables the CAN interface and returns back the raw peripheral it was created from. | ||
| 450 | #[inline] | ||
| 451 | pub fn free(mut self) { | ||
| 452 | //self.disable_interrupts(Interrupts::all()); | ||
| 453 | |||
| 454 | //TODO check this! | ||
| 455 | self.enter_init_mode(); | ||
| 456 | self.set_power_down_mode(true); | ||
| 457 | //self.control.instance | ||
| 458 | } | ||
| 459 | |||
| 460 | /// Applies the settings of a new FdCanConfig See [`FdCanConfig`] | ||
| 461 | #[inline] | ||
| 462 | pub fn apply_config(&mut self, config: FdCanConfig) { | ||
| 463 | self.set_data_bit_timing(config.dbtr); | ||
| 464 | self.set_nominal_bit_timing(config.nbtr); | ||
| 465 | self.set_automatic_retransmit(config.automatic_retransmit); | ||
| 466 | self.set_transmit_pause(config.transmit_pause); | ||
| 467 | self.set_frame_transmit(config.frame_transmit); | ||
| 468 | //self.set_interrupt_line_config(config.interrupt_line_config); | ||
| 469 | self.set_non_iso_mode(config.non_iso_mode); | ||
| 470 | self.set_edge_filtering(config.edge_filtering); | ||
| 471 | self.set_protocol_exception_handling(config.protocol_exception_handling); | ||
| 472 | self.set_global_filter(config.global_filter); | ||
| 473 | } | ||
| 474 | |||
| 475 | #[inline] | ||
| 476 | fn leave_init_mode(&mut self, config: FdCanConfig) { | ||
| 477 | self.apply_config(config); | ||
| 478 | |||
| 479 | self.regs.cccr().modify(|w| w.set_cce(false)); | ||
| 480 | self.regs.cccr().modify(|w| w.set_init(false)); | ||
| 481 | while self.regs.cccr().read().init() == true {} | ||
| 482 | } | ||
| 483 | |||
| 484 | /// Moves out of ConfigMode and into specified mode | ||
| 485 | #[inline] | ||
| 486 | pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::FdcanOperatingMode) { | ||
| 487 | match mode { | ||
| 488 | crate::can::FdcanOperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal), | ||
| 489 | crate::can::FdcanOperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External), | ||
| 490 | crate::can::FdcanOperatingMode::NormalOperationMode => self.set_normal_operations(true), | ||
| 491 | crate::can::FdcanOperatingMode::RestrictedOperationMode => self.set_restricted_operations(true), | ||
| 492 | crate::can::FdcanOperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true), | ||
| 493 | } | ||
| 494 | self.leave_init_mode(config); | ||
| 495 | } | ||
| 496 | |||
| 497 | /// Moves out of ConfigMode and into InternalLoopbackMode | ||
| 498 | #[inline] | ||
| 499 | pub fn into_internal_loopback(mut self, config: FdCanConfig) { | ||
| 500 | self.set_loopback_mode(LoopbackMode::Internal); | ||
| 501 | self.leave_init_mode(config); | ||
| 502 | } | ||
| 503 | |||
| 504 | /// Moves out of ConfigMode and into ExternalLoopbackMode | ||
| 505 | #[inline] | ||
| 506 | pub fn into_external_loopback(mut self, config: FdCanConfig) { | ||
| 507 | self.set_loopback_mode(LoopbackMode::External); | ||
| 508 | self.leave_init_mode(config); | ||
| 509 | } | ||
| 510 | |||
| 511 | /// Moves out of ConfigMode and into RestrictedOperationMode | ||
| 512 | #[inline] | ||
| 513 | pub fn into_restricted(mut self, config: FdCanConfig) { | ||
| 514 | self.set_restricted_operations(true); | ||
| 515 | self.leave_init_mode(config); | ||
| 516 | } | ||
| 517 | |||
| 518 | /// Moves out of ConfigMode and into NormalOperationMode | ||
| 519 | #[inline] | ||
| 520 | pub fn into_normal(mut self, config: FdCanConfig) { | ||
| 521 | self.set_normal_operations(true); | ||
| 522 | self.leave_init_mode(config); | ||
| 523 | } | ||
| 524 | |||
| 525 | /// Moves out of ConfigMode and into BusMonitoringMode | ||
| 526 | #[inline] | ||
| 527 | pub fn into_bus_monitoring(mut self, config: FdCanConfig) { | ||
| 528 | self.set_bus_monitoring_mode(true); | ||
| 529 | self.leave_init_mode(config); | ||
| 530 | } | ||
| 531 | |||
| 532 | /// Moves out of ConfigMode and into Testmode | ||
| 533 | #[inline] | ||
| 534 | pub fn into_test_mode(mut self, config: FdCanConfig) { | ||
| 535 | self.set_test_mode(true); | ||
| 536 | self.leave_init_mode(config); | ||
| 537 | } | ||
| 538 | |||
| 539 | /// Moves out of ConfigMode and into PoweredDownmode | ||
| 540 | #[inline] | ||
| 541 | pub fn into_powered_down(mut self, config: FdCanConfig) { | ||
| 542 | self.set_power_down_mode(true); | ||
| 543 | self.leave_init_mode(config); | ||
| 544 | } | ||
| 545 | |||
| 546 | /// Configures the bit timings. | ||
| 547 | /// | ||
| 548 | /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter | ||
| 549 | /// parameters as follows: | ||
| 550 | /// | ||
| 551 | /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). | ||
| 552 | /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). | ||
| 553 | /// - *Sample Point*: Should normally be left at the default value of 87.5%. | ||
| 554 | /// - *SJW*: Should normally be left at the default value of 1. | ||
| 555 | /// | ||
| 556 | /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` | ||
| 557 | /// parameter to this method. | ||
| 558 | #[inline] | ||
| 559 | pub fn set_nominal_bit_timing(&mut self, btr: NominalBitTiming) { | ||
| 560 | //self.control.config.nbtr = btr; | ||
| 561 | |||
| 562 | self.regs.nbtp().write(|w| { | ||
| 563 | w.set_nbrp(btr.nbrp() - 1); | ||
| 564 | w.set_ntseg1(btr.ntseg1() - 1); | ||
| 565 | w.set_ntseg2(btr.ntseg2() - 1); | ||
| 566 | w.set_nsjw(btr.nsjw() - 1); | ||
| 567 | }); | ||
| 568 | } | ||
| 569 | |||
| 570 | /// Configures the data bit timings for the FdCan Variable Bitrates. | ||
| 571 | /// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS. | ||
| 572 | #[inline] | ||
| 573 | pub fn set_data_bit_timing(&mut self, btr: DataBitTiming) { | ||
| 574 | //self.control.config.dbtr = btr; | ||
| 575 | |||
| 576 | self.regs.dbtp().write(|w| { | ||
| 577 | w.set_dbrp(btr.dbrp() - 1); | ||
| 578 | w.set_dtseg1(btr.dtseg1() - 1); | ||
| 579 | w.set_dtseg2(btr.dtseg2() - 1); | ||
| 580 | w.set_dsjw(btr.dsjw() - 1); | ||
| 581 | }); | ||
| 582 | } | ||
| 583 | |||
| 584 | /// Enables or disables automatic retransmission of messages | ||
| 585 | /// | ||
| 586 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame | ||
| 587 | /// util it can be sent. Otherwise, it will try only once to send each frame. | ||
| 588 | /// | ||
| 589 | /// Automatic retransmission is enabled by default. | ||
| 590 | #[inline] | ||
| 591 | pub fn set_automatic_retransmit(&mut self, enabled: bool) { | ||
| 592 | self.regs.cccr().modify(|w| w.set_dar(!enabled)); | ||
| 593 | //self.control.config.automatic_retransmit = enabled; | ||
| 594 | } | ||
| 595 | |||
| 596 | /// Configures the transmit pause feature. See | ||
| 597 | /// [`FdCanConfig::set_transmit_pause`] | ||
| 598 | #[inline] | ||
| 599 | pub fn set_transmit_pause(&mut self, enabled: bool) { | ||
| 600 | self.regs.cccr().modify(|w| w.set_txp(!enabled)); | ||
| 601 | //self.control.config.transmit_pause = enabled; | ||
| 602 | } | ||
| 603 | |||
| 604 | /// Configures non-iso mode. See [`FdCanConfig::set_non_iso_mode`] | ||
| 605 | #[inline] | ||
| 606 | pub fn set_non_iso_mode(&mut self, enabled: bool) { | ||
| 607 | self.regs.cccr().modify(|w| w.set_niso(enabled)); | ||
| 608 | //self.control.config.non_iso_mode = enabled; | ||
| 609 | } | ||
| 610 | |||
| 611 | /// Configures edge filtering. See [`FdCanConfig::set_edge_filtering`] | ||
| 612 | #[inline] | ||
| 613 | pub fn set_edge_filtering(&mut self, enabled: bool) { | ||
| 614 | self.regs.cccr().modify(|w| w.set_efbi(enabled)); | ||
| 615 | //self.control.config.edge_filtering = enabled; | ||
| 616 | } | ||
| 617 | |||
| 618 | /// Configures frame transmission mode. See | ||
| 619 | /// [`FdCanConfig::set_frame_transmit`] | ||
| 620 | #[inline] | ||
| 621 | pub fn set_frame_transmit(&mut self, fts: FrameTransmissionConfig) { | ||
| 622 | let (fdoe, brse) = match fts { | ||
| 623 | FrameTransmissionConfig::ClassicCanOnly => (false, false), | ||
| 624 | FrameTransmissionConfig::AllowFdCan => (true, false), | ||
| 625 | FrameTransmissionConfig::AllowFdCanAndBRS => (true, true), | ||
| 626 | }; | ||
| 627 | |||
| 628 | self.regs.cccr().modify(|w| { | ||
| 629 | w.set_fdoe(fdoe); | ||
| 630 | #[cfg(stm32h7)] | ||
| 631 | w.set_bse(brse); | ||
| 632 | #[cfg(not(stm32h7))] | ||
| 633 | w.set_brse(brse); | ||
| 634 | }); | ||
| 635 | |||
| 636 | //self.control.config.frame_transmit = fts; | ||
| 637 | } | ||
| 638 | |||
| 639 | /// Sets the protocol exception handling on/off | ||
| 640 | #[inline] | ||
| 641 | pub fn set_protocol_exception_handling(&mut self, enabled: bool) { | ||
| 642 | self.regs.cccr().modify(|w| w.set_pxhd(!enabled)); | ||
| 643 | |||
| 644 | //self.control.config.protocol_exception_handling = enabled; | ||
| 645 | } | ||
| 646 | |||
| 647 | /// Configures and resets the timestamp counter | ||
| 648 | #[inline] | ||
| 649 | pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) { | ||
| 650 | #[cfg(stm32h7)] | ||
| 651 | let (tcp, tss) = match select { | ||
| 652 | TimestampSource::None => (0, 0), | ||
| 653 | TimestampSource::Prescaler(p) => (p as u8, 1), | ||
| 654 | TimestampSource::FromTIM3 => (0, 2), | ||
| 655 | }; | ||
| 656 | |||
| 657 | #[cfg(not(stm32h7))] | ||
| 658 | let (tcp, tss) = match select { | ||
| 659 | TimestampSource::None => (0, stm32_metapac::can::vals::Tss::ZERO), | ||
| 660 | TimestampSource::Prescaler(p) => (p as u8, stm32_metapac::can::vals::Tss::INCREMENT), | ||
| 661 | TimestampSource::FromTIM3 => (0, stm32_metapac::can::vals::Tss::EXTERNAL), | ||
| 662 | }; | ||
| 663 | |||
| 664 | self.regs.tscc().write(|w| { | ||
| 665 | w.set_tcp(tcp); | ||
| 666 | w.set_tss(tss); | ||
| 667 | }); | ||
| 668 | |||
| 669 | //self.control.config.timestamp_source = select; | ||
| 670 | } | ||
| 671 | |||
| 672 | #[cfg(not(stm32h7))] | ||
| 673 | /// Configures the global filter settings | ||
| 674 | #[inline] | ||
| 675 | pub fn set_global_filter(&mut self, filter: GlobalFilter) { | ||
| 676 | let anfs = match filter.handle_standard_frames { | ||
| 677 | crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_0, | ||
| 678 | crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_1, | ||
| 679 | crate::can::fd::config::NonMatchingFilter::Reject => stm32_metapac::can::vals::Anfs::REJECT, | ||
| 680 | }; | ||
| 681 | let anfe = match filter.handle_extended_frames { | ||
| 682 | crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => stm32_metapac::can::vals::Anfe::ACCEPT_FIFO_0, | ||
| 683 | crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => stm32_metapac::can::vals::Anfe::ACCEPT_FIFO_1, | ||
| 684 | crate::can::fd::config::NonMatchingFilter::Reject => stm32_metapac::can::vals::Anfe::REJECT, | ||
| 685 | }; | ||
| 686 | |||
| 687 | self.regs.rxgfc().modify(|w| { | ||
| 688 | w.set_anfs(anfs); | ||
| 689 | w.set_anfe(anfe); | ||
| 690 | w.set_rrfs(filter.reject_remote_standard_frames); | ||
| 691 | w.set_rrfe(filter.reject_remote_extended_frames); | ||
| 692 | }); | ||
| 693 | } | ||
| 694 | |||
| 695 | #[cfg(stm32h7)] | ||
| 696 | /// Configures the global filter settings | ||
| 697 | #[inline] | ||
| 698 | pub fn set_global_filter(&mut self, filter: GlobalFilter) { | ||
| 699 | let anfs = match filter.handle_standard_frames { | ||
| 700 | crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => 0, | ||
| 701 | crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => 1, | ||
| 702 | crate::can::fd::config::NonMatchingFilter::Reject => 2, | ||
| 703 | }; | ||
| 704 | |||
| 705 | let anfe = match filter.handle_extended_frames { | ||
| 706 | crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => 0, | ||
| 707 | crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => 1, | ||
| 708 | crate::can::fd::config::NonMatchingFilter::Reject => 2, | ||
| 709 | }; | ||
| 710 | |||
| 711 | self.regs.gfc().modify(|w| { | ||
| 712 | w.set_anfs(anfs); | ||
| 713 | w.set_anfe(anfe); | ||
| 714 | w.set_rrfs(filter.reject_remote_standard_frames); | ||
| 715 | w.set_rrfe(filter.reject_remote_extended_frames); | ||
| 716 | }); | ||
| 717 | } | ||
| 718 | } | ||
| 719 | |||
| 720 | fn make_id(id: u32, extended: bool) -> embedded_can::Id { | ||
| 721 | if extended { | ||
| 722 | embedded_can::Id::from(unsafe { embedded_can::ExtendedId::new_unchecked(id & 0x1FFFFFFF) }) | ||
| 723 | } else { | ||
| 724 | embedded_can::Id::from(unsafe { embedded_can::StandardId::new_unchecked((id & 0x000007FF) as u16) }) | ||
| 725 | } | ||
| 726 | } | ||
| 727 | |||
| 728 | fn put_tx_header(mailbox: &mut TxBufferElement, header: &Header) { | ||
| 729 | let (id, id_type) = match header.id() { | ||
| 730 | embedded_can::Id::Standard(id) => (id.as_raw() as u32, IdType::StandardId), | ||
| 731 | embedded_can::Id::Extended(id) => (id.as_raw() as u32, IdType::ExtendedId), | ||
| 732 | }; | ||
| 733 | |||
| 734 | // Use FDCAN only for DLC > 8. FDCAN users can revise this if required. | ||
| 735 | let frame_format = if header.len() > 8 || header.fdcan() { | ||
| 736 | FrameFormat::Fdcan | ||
| 737 | } else { | ||
| 738 | FrameFormat::Classic | ||
| 739 | }; | ||
| 740 | let brs = header.len() > 8 || header.bit_rate_switching(); | ||
| 741 | |||
| 742 | mailbox.header.write(|w| { | ||
| 743 | unsafe { w.id().bits(id) } | ||
| 744 | .rtr() | ||
| 745 | .bit(header.len() == 0 && header.rtr()) | ||
| 746 | .xtd() | ||
| 747 | .set_id_type(id_type) | ||
| 748 | .set_len(DataLength::new(header.len(), frame_format)) | ||
| 749 | .set_event(Event::NoEvent) | ||
| 750 | .fdf() | ||
| 751 | .set_format(frame_format) | ||
| 752 | .brs() | ||
| 753 | .bit(brs) | ||
| 754 | //esi.set_error_indicator(//TODO//) | ||
| 755 | }); | ||
| 756 | } | ||
| 757 | |||
| 758 | fn put_tx_data(mailbox: &mut TxBufferElement, buffer: &[u8]) { | ||
| 759 | let mut lbuffer = [0_u32; 16]; | ||
| 760 | let len = buffer.len(); | ||
| 761 | let data = unsafe { slice::from_raw_parts_mut(lbuffer.as_mut_ptr() as *mut u8, len) }; | ||
| 762 | data[..len].copy_from_slice(&buffer[..len]); | ||
| 763 | let data_len = ((len) + 3) / 4; | ||
| 764 | for (register, byte) in mailbox.data.iter_mut().zip(lbuffer[..data_len].iter()) { | ||
| 765 | unsafe { register.write(*byte) }; | ||
| 766 | } | ||
| 767 | } | ||
| 768 | |||
| 769 | fn data_from_fifo(buffer: &mut [u8], mailbox: &RxFifoElement, len: usize) { | ||
| 770 | for (i, register) in mailbox.data.iter().enumerate() { | ||
| 771 | let register_value = register.read(); | ||
| 772 | let register_bytes = unsafe { slice::from_raw_parts(®ister_value as *const u32 as *const u8, 4) }; | ||
| 773 | let num_bytes = (len) - i * 4; | ||
| 774 | if num_bytes <= 4 { | ||
| 775 | buffer[i * 4..i * 4 + num_bytes].copy_from_slice(®ister_bytes[..num_bytes]); | ||
| 776 | break; | ||
| 777 | } | ||
| 778 | buffer[i * 4..(i + 1) * 4].copy_from_slice(register_bytes); | ||
| 779 | } | ||
| 780 | } | ||
| 781 | |||
| 782 | fn data_from_tx_buffer(buffer: &mut [u8], mailbox: &TxBufferElement, len: usize) { | ||
| 783 | for (i, register) in mailbox.data.iter().enumerate() { | ||
| 784 | let register_value = register.read(); | ||
| 785 | let register_bytes = unsafe { slice::from_raw_parts(®ister_value as *const u32 as *const u8, 4) }; | ||
| 786 | let num_bytes = (len) - i * 4; | ||
| 787 | if num_bytes <= 4 { | ||
| 788 | buffer[i * 4..i * 4 + num_bytes].copy_from_slice(®ister_bytes[..num_bytes]); | ||
| 789 | break; | ||
| 790 | } | ||
| 791 | buffer[i * 4..(i + 1) * 4].copy_from_slice(register_bytes); | ||
| 792 | } | ||
| 793 | } | ||
| 794 | |||
| 795 | impl From<&RxFifoElement> for ClassicFrame { | ||
| 796 | fn from(mailbox: &RxFifoElement) -> Self { | ||
| 797 | let header_reg = mailbox.header.read(); | ||
| 798 | |||
| 799 | let id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); | ||
| 800 | let dlc = header_reg.to_data_length().len(); | ||
| 801 | let len = dlc as usize; | ||
| 802 | |||
| 803 | let mut buffer: [u8; 64] = [0; 64]; | ||
| 804 | data_from_fifo(&mut buffer, mailbox, len); | ||
| 805 | let data = ClassicData::new(&buffer[0..len]); | ||
| 806 | let header = Header::new(id, dlc, header_reg.rtr().bits()); | ||
| 807 | ClassicFrame::new(header, data.unwrap()) | ||
| 808 | } | ||
| 809 | } | ||
| 810 | |||
| 811 | fn extract_frame(mailbox: &RxFifoElement, buffer: &mut [u8]) -> Option<(Header, u16)> { | ||
| 812 | let header_reg = mailbox.header.read(); | ||
| 813 | |||
| 814 | let id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); | ||
| 815 | let dlc = header_reg.to_data_length().len(); | ||
| 816 | let len = dlc as usize; | ||
| 817 | let timestamp = header_reg.txts().bits; | ||
| 818 | if len > buffer.len() { | ||
| 819 | return None; | ||
| 820 | } | ||
| 821 | data_from_fifo(buffer, mailbox, len); | ||
| 822 | let header = if header_reg.fdf().bits { | ||
| 823 | Header::new_fd(id, dlc, header_reg.rtr().bits(), header_reg.brs().bits()) | ||
| 824 | } else { | ||
| 825 | Header::new(id, dlc, header_reg.rtr().bits()) | ||
| 826 | }; | ||
| 827 | Some((header, timestamp)) | ||
| 828 | } | ||
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index faf4af73f..f1f6f935e 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs | |||
| @@ -1,16 +1,16 @@ | |||
| 1 | #[allow(unused_variables)] | ||
| 1 | use core::future::poll_fn; | 2 | use core::future::poll_fn; |
| 2 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 3 | use core::ops::{Deref, DerefMut}; | ||
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| 5 | 5 | ||
| 6 | use cfg_if::cfg_if; | 6 | pub mod fd; |
| 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 8 | pub use fdcan::frame::{FrameFormat, RxFrameInfo, TxFrameHeader}; | 8 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 9 | pub use fdcan::id::{ExtendedId, Id, StandardId}; | 9 | use embassy_sync::channel::Channel; |
| 10 | use fdcan::message_ram::RegisterBlock; | 10 | use fd::config::*; |
| 11 | use fdcan::{self, LastErrorCode}; | 11 | use fd::filter::*; |
| 12 | pub use fdcan::{config, filter}; | ||
| 13 | 12 | ||
| 13 | use crate::can::fd::peripheral::Registers; | ||
| 14 | use crate::gpio::sealed::AFType; | 14 | use crate::gpio::sealed::AFType; |
| 15 | use crate::interrupt::typelevel::Interrupt; | 15 | use crate::interrupt::typelevel::Interrupt; |
| 16 | use crate::rcc::RccPeripheral; | 16 | use crate::rcc::RccPeripheral; |
| @@ -20,127 +20,14 @@ pub mod enums; | |||
| 20 | use enums::*; | 20 | use enums::*; |
| 21 | pub mod util; | 21 | pub mod util; |
| 22 | 22 | ||
| 23 | /// CAN Frame returned by read | 23 | pub mod frame; |
| 24 | pub struct RxFrame { | 24 | use frame::*; |
| 25 | /// CAN Header info: frame ID, data length and other meta | ||
| 26 | pub header: RxFrameInfo, | ||
| 27 | /// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data | ||
| 28 | pub data: Data, | ||
| 29 | /// Reception time. | ||
| 30 | #[cfg(feature = "time")] | ||
| 31 | pub timestamp: embassy_time::Instant, | ||
| 32 | } | ||
| 33 | |||
| 34 | /// CAN frame used for write | ||
| 35 | pub struct TxFrame { | ||
| 36 | /// CAN Header info: frame ID, data length and other meta | ||
| 37 | pub header: TxFrameHeader, | ||
| 38 | /// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data | ||
| 39 | pub data: Data, | ||
| 40 | } | ||
| 41 | |||
| 42 | impl TxFrame { | ||
| 43 | /// Create new TX frame from header and data | ||
| 44 | pub fn new(header: TxFrameHeader, data: &[u8]) -> Option<Self> { | ||
| 45 | if data.len() < header.len as usize { | ||
| 46 | return None; | ||
| 47 | } | ||
| 48 | |||
| 49 | let Some(data) = Data::new(data) else { return None }; | ||
| 50 | |||
| 51 | Some(TxFrame { header, data }) | ||
| 52 | } | ||
| 53 | |||
| 54 | fn from_preserved(header: TxFrameHeader, data32: &[u32]) -> Option<Self> { | ||
| 55 | let mut data = [0u8; 64]; | ||
| 56 | |||
| 57 | for i in 0..data32.len() { | ||
| 58 | data[4 * i..][..4].copy_from_slice(&data32[i].to_le_bytes()); | ||
| 59 | } | ||
| 60 | |||
| 61 | let Some(data) = Data::new(&data) else { return None }; | ||
| 62 | |||
| 63 | Some(TxFrame { header, data }) | ||
| 64 | } | ||
| 65 | |||
| 66 | /// Access frame data. Slice length will match header. | ||
| 67 | pub fn data(&self) -> &[u8] { | ||
| 68 | &self.data.bytes[..(self.header.len as usize)] | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | impl RxFrame { | ||
| 73 | pub(crate) fn new( | ||
| 74 | header: RxFrameInfo, | ||
| 75 | data: &[u8], | ||
| 76 | #[cfg(feature = "time")] timestamp: embassy_time::Instant, | ||
| 77 | ) -> Self { | ||
| 78 | let data = Data::new(&data).unwrap_or_else(|| Data::empty()); | ||
| 79 | 25 | ||
| 80 | RxFrame { | 26 | #[cfg(feature = "time")] |
| 81 | header, | 27 | type Timestamp = embassy_time::Instant; |
| 82 | data, | ||
| 83 | #[cfg(feature = "time")] | ||
| 84 | timestamp, | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | /// Access frame data. Slice length will match header. | ||
| 89 | pub fn data(&self) -> &[u8] { | ||
| 90 | &self.data.bytes[..(self.header.len as usize)] | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | /// Payload of a (FD)CAN data frame. | ||
| 95 | /// | ||
| 96 | /// Contains 0 to 64 Bytes of data. | ||
| 97 | #[derive(Debug, Copy, Clone)] | ||
| 98 | pub struct Data { | ||
| 99 | pub(crate) bytes: [u8; 64], | ||
| 100 | } | ||
| 101 | |||
| 102 | impl Data { | ||
| 103 | /// Creates a data payload from a raw byte slice. | ||
| 104 | /// | ||
| 105 | /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or | ||
| 106 | /// cannot be represented with an FDCAN DLC. | ||
| 107 | pub fn new(data: &[u8]) -> Option<Self> { | ||
| 108 | if !Data::is_valid_len(data.len()) { | ||
| 109 | return None; | ||
| 110 | } | ||
| 111 | |||
| 112 | let mut bytes = [0; 64]; | ||
| 113 | bytes[..data.len()].copy_from_slice(data); | ||
| 114 | |||
| 115 | Some(Self { bytes }) | ||
| 116 | } | ||
| 117 | |||
| 118 | /// Raw read access to data. | ||
| 119 | pub fn raw(&self) -> &[u8] { | ||
| 120 | &self.bytes | ||
| 121 | } | ||
| 122 | 28 | ||
| 123 | /// Checks if the length can be encoded in FDCAN DLC field. | 29 | #[cfg(not(feature = "time"))] |
| 124 | pub const fn is_valid_len(len: usize) -> bool { | 30 | type Timestamp = u16; |
| 125 | match len { | ||
| 126 | 0..=8 => true, | ||
| 127 | 12 => true, | ||
| 128 | 16 => true, | ||
| 129 | 20 => true, | ||
| 130 | 24 => true, | ||
| 131 | 32 => true, | ||
| 132 | 48 => true, | ||
| 133 | 64 => true, | ||
| 134 | _ => false, | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | /// Creates an empty data payload containing 0 bytes. | ||
| 139 | #[inline] | ||
| 140 | pub const fn empty() -> Self { | ||
| 141 | Self { bytes: [0; 64] } | ||
| 142 | } | ||
| 143 | } | ||
| 144 | 31 | ||
| 145 | /// Interrupt handler channel 0. | 32 | /// Interrupt handler channel 0. |
| 146 | pub struct IT0InterruptHandler<T: Instance> { | 33 | pub struct IT0InterruptHandler<T: Instance> { |
| @@ -154,14 +41,37 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup | |||
| 154 | 41 | ||
| 155 | let ir = regs.ir().read(); | 42 | let ir = regs.ir().read(); |
| 156 | 43 | ||
| 157 | if ir.tc() { | 44 | { |
| 158 | regs.ir().write(|w| w.set_tc(true)); | 45 | if ir.tc() { |
| 159 | T::state().tx_waker.wake(); | 46 | regs.ir().write(|w| w.set_tc(true)); |
| 160 | } | 47 | } |
| 48 | if ir.tefn() { | ||
| 49 | regs.ir().write(|w| w.set_tefn(true)); | ||
| 50 | } | ||
| 161 | 51 | ||
| 162 | if ir.tefn() { | 52 | match &T::state().tx_mode { |
| 163 | regs.ir().write(|w| w.set_tefn(true)); | 53 | sealed::TxMode::NonBuffered(waker) => waker.wake(), |
| 164 | T::state().tx_waker.wake(); | 54 | sealed::TxMode::ClassicBuffered(buf) => { |
| 55 | if !T::registers().tx_queue_is_full() { | ||
| 56 | match buf.tx_receiver.try_receive() { | ||
| 57 | Ok(frame) => { | ||
| 58 | _ = T::registers().write_classic(&frame); | ||
| 59 | } | ||
| 60 | Err(_) => {} | ||
| 61 | } | ||
| 62 | } | ||
| 63 | } | ||
| 64 | sealed::TxMode::FdBuffered(buf) => { | ||
| 65 | if !T::registers().tx_queue_is_full() { | ||
| 66 | match buf.tx_receiver.try_receive() { | ||
| 67 | Ok(frame) => { | ||
| 68 | _ = T::registers().write_fd(&frame); | ||
| 69 | } | ||
| 70 | Err(_) => {} | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } | ||
| 74 | } | ||
| 165 | } | 75 | } |
| 166 | 76 | ||
| 167 | if ir.ped() || ir.pea() { | 77 | if ir.ped() || ir.pea() { |
| @@ -172,13 +82,11 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup | |||
| 172 | } | 82 | } |
| 173 | 83 | ||
| 174 | if ir.rfn(0) { | 84 | if ir.rfn(0) { |
| 175 | regs.ir().write(|w| w.set_rfn(0, true)); | 85 | T::state().rx_mode.on_interrupt::<T>(0); |
| 176 | T::state().rx_waker.wake(); | ||
| 177 | } | 86 | } |
| 178 | 87 | ||
| 179 | if ir.rfn(1) { | 88 | if ir.rfn(1) { |
| 180 | regs.ir().write(|w| w.set_rfn(1, true)); | 89 | T::state().rx_mode.on_interrupt::<T>(1); |
| 181 | T::state().rx_waker.wake(); | ||
| 182 | } | 90 | } |
| 183 | } | 91 | } |
| 184 | } | 92 | } |
| @@ -192,44 +100,56 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT1Interrupt> for IT1Interrup | |||
| 192 | unsafe fn on_interrupt() {} | 100 | unsafe fn on_interrupt() {} |
| 193 | } | 101 | } |
| 194 | 102 | ||
| 195 | impl BusError { | 103 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
| 196 | fn try_from(lec: LastErrorCode) -> Option<BusError> { | 104 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 197 | match lec { | 105 | /// Different operating modes |
| 198 | LastErrorCode::AckError => Some(BusError::Acknowledge), | 106 | pub enum FdcanOperatingMode { |
| 199 | // `0` data bit encodes a dominant state. `1` data bit is recessive. | 107 | //PoweredDownMode, |
| 200 | // Bit0Error: During transmit, the node wanted to send a 0 but monitored a 1 | 108 | //ConfigMode, |
| 201 | LastErrorCode::Bit0Error => Some(BusError::BitRecessive), | 109 | /// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without |
| 202 | LastErrorCode::Bit1Error => Some(BusError::BitDominant), | 110 | /// affecting a running CAN system connected to the FDCAN_TX and FDCAN_RX pins. In this |
| 203 | LastErrorCode::CRCError => Some(BusError::Crc), | 111 | /// mode, FDCAN_RX pin is disconnected from the FDCAN and FDCAN_TX pin is held |
| 204 | LastErrorCode::FormError => Some(BusError::Form), | 112 | /// recessive. |
| 205 | LastErrorCode::StuffError => Some(BusError::Stuff), | 113 | InternalLoopbackMode, |
| 206 | _ => None, | 114 | /// This mode is provided for hardware self-test. To be independent from external stimulation, |
| 207 | } | 115 | /// the FDCAN ignores acknowledge errors (recessive bit sampled in the acknowledge slot of a |
| 208 | } | 116 | /// data / remote frame) in Loop Back mode. In this mode the FDCAN performs an internal |
| 117 | /// feedback from its transmit output to its receive input. The actual value of the FDCAN_RX | ||
| 118 | /// input pin is disregarded by the FDCAN. The transmitted messages can be monitored at the | ||
| 119 | /// FDCAN_TX transmit pin. | ||
| 120 | ExternalLoopbackMode, | ||
| 121 | /// The normal use of the Fdcan instance after configurations | ||
| 122 | NormalOperationMode, | ||
| 123 | /// In Restricted operation mode the node is able to receive data and remote frames and to give | ||
| 124 | /// acknowledge to valid frames, but it does not send data frames, remote frames, active error | ||
| 125 | /// frames, or overload frames. In case of an error condition or overload condition, it does not | ||
| 126 | /// send dominant bits, instead it waits for the occurrence of bus idle condition to resynchronize | ||
| 127 | /// itself to the CAN communication. The error counters for transmit and receive are frozen while | ||
| 128 | /// error logging (can_errors) is active. TODO: automatically enter in this mode? | ||
| 129 | RestrictedOperationMode, | ||
| 130 | /// In Bus monitoring mode (for more details refer to ISO11898-1, 10.12 Bus monitoring), | ||
| 131 | /// the FDCAN is able to receive valid data frames and valid remote frames, but cannot start a | ||
| 132 | /// transmission. In this mode, it sends only recessive bits on the CAN bus. If the FDCAN is | ||
| 133 | /// required to send a dominant bit (ACK bit, overload flag, active error flag), the bit is | ||
| 134 | /// rerouted internally so that the FDCAN can monitor it, even if the CAN bus remains in recessive | ||
| 135 | /// state. In Bus monitoring mode the TXBRP register is held in reset state. The Bus monitoring | ||
| 136 | /// mode can be used to analyze the traffic on a CAN bus without affecting it by the transmission | ||
| 137 | /// of dominant bits. | ||
| 138 | BusMonitoringMode, | ||
| 139 | //TestMode, | ||
| 209 | } | 140 | } |
| 210 | 141 | ||
| 211 | /// Operating modes trait | ||
| 212 | pub trait FdcanOperatingMode {} | ||
| 213 | impl FdcanOperatingMode for fdcan::PoweredDownMode {} | ||
| 214 | impl FdcanOperatingMode for fdcan::ConfigMode {} | ||
| 215 | impl FdcanOperatingMode for fdcan::InternalLoopbackMode {} | ||
| 216 | impl FdcanOperatingMode for fdcan::ExternalLoopbackMode {} | ||
| 217 | impl FdcanOperatingMode for fdcan::NormalOperationMode {} | ||
| 218 | impl FdcanOperatingMode for fdcan::RestrictedOperationMode {} | ||
| 219 | impl FdcanOperatingMode for fdcan::BusMonitoringMode {} | ||
| 220 | impl FdcanOperatingMode for fdcan::TestMode {} | ||
| 221 | |||
| 222 | /// FDCAN Instance | 142 | /// FDCAN Instance |
| 223 | pub struct Fdcan<'d, T: Instance, M: FdcanOperatingMode> { | 143 | pub struct FdcanConfigurator<'d, T: Instance> { |
| 144 | config: crate::can::fd::config::FdCanConfig, | ||
| 224 | /// Reference to internals. | 145 | /// Reference to internals. |
| 225 | pub can: fdcan::FdCan<FdcanInstance<'d, T>, M>, | 146 | instance: FdcanInstance<'d, T>, |
| 226 | ns_per_timer_tick: u64, // For FDCAN internal timer | ||
| 227 | } | 147 | } |
| 228 | 148 | ||
| 229 | fn calc_ns_per_timer_tick<T: Instance>(mode: config::FrameTransmissionConfig) -> u64 { | 149 | fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 { |
| 230 | match mode { | 150 | match mode { |
| 231 | // Use timestamp from Rx FIFO to adjust timestamp reported to user | 151 | // Use timestamp from Rx FIFO to adjust timestamp reported to user |
| 232 | config::FrameTransmissionConfig::ClassicCanOnly => { | 152 | crate::can::fd::config::FrameTransmissionConfig::ClassicCanOnly => { |
| 233 | let freq = T::frequency(); | 153 | let freq = T::frequency(); |
| 234 | let prescale: u64 = | 154 | let prescale: u64 = |
| 235 | ({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64; | 155 | ({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64; |
| @@ -241,42 +161,7 @@ fn calc_ns_per_timer_tick<T: Instance>(mode: config::FrameTransmissionConfig) -> | |||
| 241 | } | 161 | } |
| 242 | } | 162 | } |
| 243 | 163 | ||
| 244 | #[cfg(feature = "time")] | 164 | impl<'d, T: Instance> FdcanConfigurator<'d, T> { |
| 245 | fn calc_timestamp<T: Instance>(ns_per_timer_tick: u64, ts_val: u16) -> embassy_time::Instant { | ||
| 246 | let now_embassy = embassy_time::Instant::now(); | ||
| 247 | if ns_per_timer_tick == 0 { | ||
| 248 | return now_embassy; | ||
| 249 | } | ||
| 250 | let now_can = { T::regs().tscv().read().tsc() }; | ||
| 251 | let delta = now_can.overflowing_sub(ts_val).0 as u64; | ||
| 252 | let ns = ns_per_timer_tick * delta as u64; | ||
| 253 | now_embassy - embassy_time::Duration::from_nanos(ns) | ||
| 254 | } | ||
| 255 | |||
| 256 | fn curr_error<T: Instance>() -> Option<BusError> { | ||
| 257 | let err = { T::regs().psr().read() }; | ||
| 258 | if err.bo() { | ||
| 259 | return Some(BusError::BusOff); | ||
| 260 | } else if err.ep() { | ||
| 261 | return Some(BusError::BusPassive); | ||
| 262 | } else if err.ew() { | ||
| 263 | return Some(BusError::BusWarning); | ||
| 264 | } else { | ||
| 265 | cfg_if! { | ||
| 266 | if #[cfg(stm32h7)] { | ||
| 267 | let lec = err.lec(); | ||
| 268 | } else { | ||
| 269 | let lec = err.lec().to_bits(); | ||
| 270 | } | ||
| 271 | } | ||
| 272 | if let Ok(err) = LastErrorCode::try_from(lec) { | ||
| 273 | return BusError::try_from(err); | ||
| 274 | } | ||
| 275 | } | ||
| 276 | None | ||
| 277 | } | ||
| 278 | |||
| 279 | impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { | ||
| 280 | /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. | 165 | /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. |
| 281 | /// You must call [Fdcan::enable_non_blocking] to use the peripheral. | 166 | /// You must call [Fdcan::enable_non_blocking] to use the peripheral. |
| 282 | pub fn new( | 167 | pub fn new( |
| @@ -286,7 +171,7 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { | |||
| 286 | _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>> | 171 | _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>> |
| 287 | + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> | 172 | + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> |
| 288 | + 'd, | 173 | + 'd, |
| 289 | ) -> Fdcan<'d, T, fdcan::ConfigMode> { | 174 | ) -> FdcanConfigurator<'d, T> { |
| 290 | into_ref!(peri, rx, tx); | 175 | into_ref!(peri, rx, tx); |
| 291 | 176 | ||
| 292 | rx.set_as_af(rx.af_num(), AFType::Input); | 177 | rx.set_as_af(rx.af_num(), AFType::Input); |
| @@ -294,11 +179,12 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { | |||
| 294 | 179 | ||
| 295 | T::enable_and_reset(); | 180 | T::enable_and_reset(); |
| 296 | 181 | ||
| 182 | let mut config = crate::can::fd::config::FdCanConfig::default(); | ||
| 183 | T::registers().into_config_mode(config); | ||
| 184 | |||
| 297 | rx.set_as_af(rx.af_num(), AFType::Input); | 185 | rx.set_as_af(rx.af_num(), AFType::Input); |
| 298 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | 186 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |
| 299 | 187 | ||
| 300 | let mut can = fdcan::FdCan::new(FdcanInstance(peri)).into_config_mode(); | ||
| 301 | |||
| 302 | T::configure_msg_ram(); | 188 | T::configure_msg_ram(); |
| 303 | unsafe { | 189 | unsafe { |
| 304 | // Enable timestamping | 190 | // Enable timestamping |
| @@ -308,6 +194,7 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { | |||
| 308 | .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT)); | 194 | .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT)); |
| 309 | #[cfg(stm32h7)] | 195 | #[cfg(stm32h7)] |
| 310 | T::regs().tscc().write(|w| w.set_tss(0x01)); | 196 | T::regs().tscc().write(|w| w.set_tss(0x01)); |
| 197 | config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1); | ||
| 311 | 198 | ||
| 312 | T::IT0Interrupt::unpend(); // Not unsafe | 199 | T::IT0Interrupt::unpend(); // Not unsafe |
| 313 | T::IT0Interrupt::enable(); | 200 | T::IT0Interrupt::enable(); |
| @@ -320,94 +207,134 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { | |||
| 320 | T::regs().txbtie().write(|w| w.0 = 0xffff_ffff); | 207 | T::regs().txbtie().write(|w| w.0 = 0xffff_ffff); |
| 321 | } | 208 | } |
| 322 | 209 | ||
| 323 | can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo0NewMsg); | 210 | T::regs().ie().modify(|w| { |
| 324 | can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo1NewMsg); | 211 | w.set_rfne(0, true); // Rx Fifo 0 New Msg |
| 325 | can.enable_interrupt(fdcan::interrupt::Interrupt::TxComplete); | 212 | w.set_rfne(1, true); // Rx Fifo 1 New Msg |
| 326 | can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_0, true); | 213 | w.set_tce(true); // Tx Complete |
| 327 | can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_1, true); | 214 | }); |
| 215 | T::regs().ile().modify(|w| { | ||
| 216 | w.set_eint0(true); // Interrupt Line 0 | ||
| 217 | w.set_eint1(true); // Interrupt Line 1 | ||
| 218 | }); | ||
| 219 | |||
| 220 | Self { | ||
| 221 | config, | ||
| 222 | instance: FdcanInstance(peri), | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | /// Get configuration | ||
| 227 | pub fn config(&self) -> crate::can::fd::config::FdCanConfig { | ||
| 228 | return self.config; | ||
| 229 | } | ||
| 328 | 230 | ||
| 329 | let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(can.get_config().frame_transmit); | 231 | /// Set configuration |
| 330 | Self { can, ns_per_timer_tick } | 232 | pub fn set_config(&mut self, config: crate::can::fd::config::FdCanConfig) { |
| 233 | self.config = config; | ||
| 331 | } | 234 | } |
| 332 | 235 | ||
| 333 | /// Configures the bit timings calculated from supplied bitrate. | 236 | /// Configures the bit timings calculated from supplied bitrate. |
| 334 | pub fn set_bitrate(&mut self, bitrate: u32) { | 237 | pub fn set_bitrate(&mut self, bitrate: u32) { |
| 335 | let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); | 238 | let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); |
| 336 | self.can.set_nominal_bit_timing(config::NominalBitTiming { | 239 | |
| 240 | let nbtr = crate::can::fd::config::NominalBitTiming { | ||
| 337 | sync_jump_width: bit_timing.sync_jump_width, | 241 | sync_jump_width: bit_timing.sync_jump_width, |
| 338 | prescaler: bit_timing.prescaler, | 242 | prescaler: bit_timing.prescaler, |
| 339 | seg1: bit_timing.seg1, | 243 | seg1: bit_timing.seg1, |
| 340 | seg2: bit_timing.seg2, | 244 | seg2: bit_timing.seg2, |
| 341 | }); | 245 | }; |
| 246 | self.config = self.config.set_nominal_bit_timing(nbtr); | ||
| 342 | } | 247 | } |
| 343 | } | ||
| 344 | 248 | ||
| 345 | macro_rules! impl_transition { | 249 | /// Configures the bit timings for VBR data calculated from supplied bitrate. This also sets confit to allow can FD and VBR |
| 346 | ($from_mode:ident, $to_mode:ident, $name:ident, $func: ident) => { | 250 | pub fn set_fd_data_bitrate(&mut self, bitrate: u32, transceiver_delay_compensation: bool) { |
| 347 | impl<'d, T: Instance> Fdcan<'d, T, fdcan::$from_mode> { | 251 | let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); |
| 348 | /// Transition from $from_mode:ident mode to $to_mode:ident mode | 252 | // Note, used existing calcluation for normal(non-VBR) bitrate, appears to work for 250k/1M |
| 349 | pub fn $name(self) -> Fdcan<'d, T, fdcan::$to_mode> { | 253 | let nbtr = crate::can::fd::config::DataBitTiming { |
| 350 | let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.can.get_config().frame_transmit); | 254 | transceiver_delay_compensation, |
| 351 | Fdcan { | 255 | sync_jump_width: bit_timing.sync_jump_width, |
| 352 | can: self.can.$func(), | 256 | prescaler: bit_timing.prescaler, |
| 353 | ns_per_timer_tick, | 257 | seg1: bit_timing.seg1, |
| 354 | } | 258 | seg2: bit_timing.seg2, |
| 355 | } | 259 | }; |
| 260 | self.config.frame_transmit = FrameTransmissionConfig::AllowFdCanAndBRS; | ||
| 261 | self.config = self.config.set_data_bit_timing(nbtr); | ||
| 262 | } | ||
| 263 | |||
| 264 | /// Set an Standard Address CAN filter into slot 'id' | ||
| 265 | #[inline] | ||
| 266 | pub fn set_standard_filter(&mut self, slot: StandardFilterSlot, filter: StandardFilter) { | ||
| 267 | T::registers().msg_ram_mut().filters.flssa[slot as usize].activate(filter); | ||
| 268 | } | ||
| 269 | |||
| 270 | /// Set an array of Standard Address CAN filters and overwrite the current set | ||
| 271 | pub fn set_standard_filters(&mut self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) { | ||
| 272 | for (i, f) in filters.iter().enumerate() { | ||
| 273 | T::registers().msg_ram_mut().filters.flssa[i].activate(*f); | ||
| 356 | } | 274 | } |
| 357 | }; | 275 | } |
| 358 | } | ||
| 359 | 276 | ||
| 360 | impl_transition!(PoweredDownMode, ConfigMode, into_config_mode, into_config_mode); | 277 | /// Set an Extended Address CAN filter into slot 'id' |
| 361 | impl_transition!(InternalLoopbackMode, ConfigMode, into_config_mode, into_config_mode); | 278 | #[inline] |
| 279 | pub fn set_extended_filter(&mut self, slot: ExtendedFilterSlot, filter: ExtendedFilter) { | ||
| 280 | T::registers().msg_ram_mut().filters.flesa[slot as usize].activate(filter); | ||
| 281 | } | ||
| 362 | 282 | ||
| 363 | impl_transition!(ConfigMode, NormalOperationMode, into_normal_mode, into_normal); | 283 | /// Set an array of Extended Address CAN filters and overwrite the current set |
| 364 | impl_transition!( | 284 | pub fn set_extended_filters(&mut self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) { |
| 365 | ConfigMode, | 285 | for (i, f) in filters.iter().enumerate() { |
| 366 | ExternalLoopbackMode, | 286 | T::registers().msg_ram_mut().filters.flesa[i].activate(*f); |
| 367 | into_external_loopback_mode, | 287 | } |
| 368 | into_external_loopback | 288 | } |
| 369 | ); | ||
| 370 | impl_transition!( | ||
| 371 | ConfigMode, | ||
| 372 | InternalLoopbackMode, | ||
| 373 | into_internal_loopback_mode, | ||
| 374 | into_internal_loopback | ||
| 375 | ); | ||
| 376 | 289 | ||
| 377 | impl<'d, T: Instance, M: FdcanOperatingMode> Fdcan<'d, T, M> | 290 | /// Start in mode. |
| 378 | where | 291 | pub fn start(self, mode: FdcanOperatingMode) -> Fdcan<'d, T> { |
| 379 | M: fdcan::Transmit, | 292 | let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit); |
| 380 | M: fdcan::Receive, | 293 | critical_section::with(|_| unsafe { |
| 381 | { | 294 | T::mut_state().ns_per_timer_tick = ns_per_timer_tick; |
| 382 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | 295 | }); |
| 383 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | 296 | T::registers().into_mode(self.config, mode); |
| 384 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 297 | let ret = Fdcan { |
| 385 | /// transmitted, then tries again. | 298 | config: self.config, |
| 386 | pub async fn write(&mut self, frame: &TxFrame) -> Option<TxFrame> { | 299 | instance: self.instance, |
| 387 | poll_fn(|cx| { | 300 | _mode: mode, |
| 388 | T::state().tx_waker.register(cx.waker()); | 301 | }; |
| 389 | if let Ok(dropped) = self | 302 | ret |
| 390 | .can | 303 | } |
| 391 | .transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| { | ||
| 392 | TxFrame::from_preserved(hdr, data32) | ||
| 393 | }) | ||
| 394 | { | ||
| 395 | return Poll::Ready(dropped.flatten()); | ||
| 396 | } | ||
| 397 | 304 | ||
| 398 | // Couldn't replace any lower priority frames. Need to wait for some mailboxes | 305 | /// Start, entering mode. Does same as start(mode) |
| 399 | // to clear. | 306 | pub fn into_normal_mode(self) -> Fdcan<'d, T> { |
| 400 | Poll::Pending | 307 | self.start(FdcanOperatingMode::NormalOperationMode) |
| 401 | }) | ||
| 402 | .await | ||
| 403 | } | 308 | } |
| 404 | 309 | ||
| 310 | /// Start, entering mode. Does same as start(mode) | ||
| 311 | pub fn into_internal_loopback_mode(self) -> Fdcan<'d, T> { | ||
| 312 | self.start(FdcanOperatingMode::InternalLoopbackMode) | ||
| 313 | } | ||
| 314 | |||
| 315 | /// Start, entering mode. Does same as start(mode) | ||
| 316 | pub fn into_external_loopback_mode(self) -> Fdcan<'d, T> { | ||
| 317 | self.start(FdcanOperatingMode::ExternalLoopbackMode) | ||
| 318 | } | ||
| 319 | } | ||
| 320 | |||
| 321 | /// FDCAN Instance | ||
| 322 | pub struct Fdcan<'d, T: Instance> { | ||
| 323 | config: crate::can::fd::config::FdCanConfig, | ||
| 324 | /// Reference to internals. | ||
| 325 | instance: FdcanInstance<'d, T>, | ||
| 326 | _mode: FdcanOperatingMode, | ||
| 327 | } | ||
| 328 | |||
| 329 | impl<'d, T: Instance> Fdcan<'d, T> { | ||
| 405 | /// Flush one of the TX mailboxes. | 330 | /// Flush one of the TX mailboxes. |
| 406 | pub async fn flush(&self, mb: fdcan::Mailbox) { | 331 | pub async fn flush(&self, idx: usize) { |
| 407 | poll_fn(|cx| { | 332 | poll_fn(|cx| { |
| 408 | T::state().tx_waker.register(cx.waker()); | 333 | T::state().tx_mode.register(cx.waker()); |
| 409 | 334 | ||
| 410 | let idx: u8 = mb.into(); | 335 | if idx > 3 { |
| 336 | panic!("Bad mailbox"); | ||
| 337 | } | ||
| 411 | let idx = 1 << idx; | 338 | let idx = 1 << idx; |
| 412 | if !T::regs().txbrp().read().trp(idx) { | 339 | if !T::regs().txbrp().read().trp(idx) { |
| 413 | return Poll::Ready(()); | 340 | return Poll::Ready(()); |
| @@ -418,179 +345,454 @@ where | |||
| 418 | .await; | 345 | .await; |
| 419 | } | 346 | } |
| 420 | 347 | ||
| 348 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | ||
| 349 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | ||
| 350 | /// can be replaced, this call asynchronously waits for a frame to be successfully | ||
| 351 | /// transmitted, then tries again. | ||
| 352 | pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> { | ||
| 353 | T::state().tx_mode.write::<T>(frame).await | ||
| 354 | } | ||
| 355 | |||
| 421 | /// Returns the next received message frame | 356 | /// Returns the next received message frame |
| 422 | pub async fn read(&mut self) -> Result<RxFrame, BusError> { | 357 | pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { |
| 423 | poll_fn(|cx| { | 358 | T::state().rx_mode.read::<T>().await |
| 424 | T::state().err_waker.register(cx.waker()); | 359 | } |
| 425 | T::state().rx_waker.register(cx.waker()); | 360 | |
| 426 | 361 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | |
| 427 | let mut buffer: [u8; 64] = [0; 64]; | 362 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames |
| 428 | if let Ok(rx) = self.can.receive0(&mut buffer) { | 363 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 429 | // rx: fdcan::ReceiveOverrun<RxFrameInfo> | 364 | /// transmitted, then tries again. |
| 430 | // TODO: report overrun? | 365 | pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { |
| 431 | // for now we just drop it | 366 | T::state().tx_mode.write_fd::<T>(frame).await |
| 432 | 367 | } | |
| 433 | let frame: RxFrame = RxFrame::new( | 368 | |
| 434 | rx.unwrap(), | 369 | /// Returns the next received message frame |
| 435 | &buffer, | 370 | pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { |
| 436 | #[cfg(feature = "time")] | 371 | T::state().rx_mode.read_fd::<T>().await |
| 437 | calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp), | ||
| 438 | ); | ||
| 439 | return Poll::Ready(Ok(frame)); | ||
| 440 | } else if let Ok(rx) = self.can.receive1(&mut buffer) { | ||
| 441 | // rx: fdcan::ReceiveOverrun<RxFrameInfo> | ||
| 442 | // TODO: report overrun? | ||
| 443 | // for now we just drop it | ||
| 444 | |||
| 445 | let frame: RxFrame = RxFrame::new( | ||
| 446 | rx.unwrap(), | ||
| 447 | &buffer, | ||
| 448 | #[cfg(feature = "time")] | ||
| 449 | calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp), | ||
| 450 | ); | ||
| 451 | return Poll::Ready(Ok(frame)); | ||
| 452 | } else if let Some(err) = curr_error::<T>() { | ||
| 453 | // TODO: this is probably wrong | ||
| 454 | return Poll::Ready(Err(err)); | ||
| 455 | } | ||
| 456 | Poll::Pending | ||
| 457 | }) | ||
| 458 | .await | ||
| 459 | } | 372 | } |
| 460 | 373 | ||
| 461 | /// Split instance into separate Tx(write) and Rx(read) portions | 374 | /// Split instance into separate Tx(write) and Rx(read) portions |
| 462 | pub fn split<'c>(&'c mut self) -> (FdcanTx<'c, 'd, T, M>, FdcanRx<'c, 'd, T, M>) { | 375 | pub fn split(self) -> (FdcanTx<'d, T>, FdcanRx<'d, T>) { |
| 463 | let (mut _control, tx, rx0, rx1) = self.can.split_by_ref(); | ||
| 464 | ( | 376 | ( |
| 465 | FdcanTx { _control, tx }, | 377 | FdcanTx { |
| 378 | config: self.config, | ||
| 379 | _instance: self.instance, | ||
| 380 | _mode: self._mode, | ||
| 381 | }, | ||
| 466 | FdcanRx { | 382 | FdcanRx { |
| 467 | rx0, | 383 | _instance1: PhantomData::<T>, |
| 468 | rx1, | 384 | _instance2: T::regs(), |
| 469 | ns_per_timer_tick: self.ns_per_timer_tick, | 385 | _mode: self._mode, |
| 470 | }, | 386 | }, |
| 471 | ) | 387 | ) |
| 472 | } | 388 | } |
| 389 | |||
| 390 | /// Join split rx and tx portions back together | ||
| 391 | pub fn join(tx: FdcanTx<'d, T>, rx: FdcanRx<'d, T>) -> Self { | ||
| 392 | Fdcan { | ||
| 393 | config: tx.config, | ||
| 394 | //_instance2: T::regs(), | ||
| 395 | instance: tx._instance, | ||
| 396 | _mode: rx._mode, | ||
| 397 | } | ||
| 398 | } | ||
| 399 | |||
| 400 | /// Return a buffered instance of driver without CAN FD support. User must supply Buffers | ||
| 401 | pub fn buffered<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>( | ||
| 402 | &self, | ||
| 403 | tx_buf: &'static mut TxBuf<TX_BUF_SIZE>, | ||
| 404 | rxb: &'static mut RxBuf<RX_BUF_SIZE>, | ||
| 405 | ) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { | ||
| 406 | BufferedCan::new(PhantomData::<T>, T::regs(), self._mode, tx_buf, rxb) | ||
| 407 | } | ||
| 408 | |||
| 409 | /// Return a buffered instance of driver with CAN FD support. User must supply Buffers | ||
| 410 | pub fn buffered_fd<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>( | ||
| 411 | &self, | ||
| 412 | tx_buf: &'static mut TxFdBuf<TX_BUF_SIZE>, | ||
| 413 | rxb: &'static mut RxFdBuf<RX_BUF_SIZE>, | ||
| 414 | ) -> BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { | ||
| 415 | BufferedCanFd::new(PhantomData::<T>, T::regs(), self._mode, tx_buf, rxb) | ||
| 416 | } | ||
| 473 | } | 417 | } |
| 474 | 418 | ||
| 475 | /// FDCAN Tx only Instance | 419 | /// User supplied buffer for RX Buffering |
| 476 | pub struct FdcanTx<'c, 'd, T: Instance, M: fdcan::Transmit> { | 420 | pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, (ClassicFrame, Timestamp), BUF_SIZE>; |
| 477 | _control: &'c mut fdcan::FdCanControl<FdcanInstance<'d, T>, M>, | 421 | |
| 478 | tx: &'c mut fdcan::Tx<FdcanInstance<'d, T>, M>, | 422 | /// User supplied buffer for TX buffering |
| 423 | pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, ClassicFrame, BUF_SIZE>; | ||
| 424 | |||
| 425 | /// Buffered FDCAN Instance | ||
| 426 | pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { | ||
| 427 | _instance1: PhantomData<T>, | ||
| 428 | _instance2: &'d crate::pac::can::Fdcan, | ||
| 429 | _mode: FdcanOperatingMode, | ||
| 430 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, | ||
| 431 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, | ||
| 479 | } | 432 | } |
| 480 | 433 | ||
| 481 | impl<'c, 'd, T: Instance, M: fdcan::Transmit> FdcanTx<'c, 'd, T, M> { | 434 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> |
| 482 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | 435 | BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> |
| 483 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | 436 | { |
| 484 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 437 | fn new( |
| 485 | /// transmitted, then tries again. | 438 | _instance1: PhantomData<T>, |
| 486 | pub async fn write(&mut self, frame: &TxFrame) -> Option<TxFrame> { | 439 | _instance2: &'d crate::pac::can::Fdcan, |
| 487 | poll_fn(|cx| { | 440 | _mode: FdcanOperatingMode, |
| 488 | T::state().tx_waker.register(cx.waker()); | 441 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, |
| 489 | if let Ok(dropped) = self | 442 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, |
| 490 | .tx | 443 | ) -> Self { |
| 491 | .transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| { | 444 | BufferedCan { |
| 492 | TxFrame::from_preserved(hdr, data32) | 445 | _instance1, |
| 493 | }) | 446 | _instance2, |
| 494 | { | 447 | _mode, |
| 495 | return Poll::Ready(dropped.flatten()); | 448 | tx_buf, |
| 496 | } | 449 | rx_buf, |
| 450 | } | ||
| 451 | .setup() | ||
| 452 | } | ||
| 497 | 453 | ||
| 498 | // Couldn't replace any lower priority frames. Need to wait for some mailboxes | 454 | fn setup(self) -> Self { |
| 499 | // to clear. | 455 | // We don't want interrupts being processed while we change modes. |
| 500 | Poll::Pending | 456 | critical_section::with(|_| unsafe { |
| 501 | }) | 457 | let rx_inner = sealed::ClassicBufferedRxInner { |
| 502 | .await | 458 | rx_sender: self.rx_buf.sender().into(), |
| 459 | }; | ||
| 460 | let tx_inner = sealed::ClassicBufferedTxInner { | ||
| 461 | tx_receiver: self.tx_buf.receiver().into(), | ||
| 462 | }; | ||
| 463 | T::mut_state().rx_mode = sealed::RxMode::ClassicBuffered(rx_inner); | ||
| 464 | T::mut_state().tx_mode = sealed::TxMode::ClassicBuffered(tx_inner); | ||
| 465 | }); | ||
| 466 | self | ||
| 467 | } | ||
| 468 | |||
| 469 | /// Async write frame to TX buffer. | ||
| 470 | pub async fn write(&mut self, frame: ClassicFrame) { | ||
| 471 | self.tx_buf.send(frame).await; | ||
| 472 | T::IT0Interrupt::pend(); // Wake for Tx | ||
| 473 | } | ||
| 474 | |||
| 475 | /// Async read frame from RX buffer. | ||
| 476 | pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { | ||
| 477 | Ok(self.rx_buf.receive().await) | ||
| 503 | } | 478 | } |
| 504 | } | 479 | } |
| 505 | 480 | ||
| 506 | /// FDCAN Rx only Instance | 481 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop |
| 507 | #[allow(dead_code)] | 482 | for BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> |
| 508 | pub struct FdcanRx<'c, 'd, T: Instance, M: fdcan::Receive> { | 483 | { |
| 509 | rx0: &'c mut fdcan::Rx<FdcanInstance<'d, T>, M, fdcan::Fifo0>, | 484 | fn drop(&mut self) { |
| 510 | rx1: &'c mut fdcan::Rx<FdcanInstance<'d, T>, M, fdcan::Fifo1>, | 485 | critical_section::with(|_| unsafe { |
| 511 | ns_per_timer_tick: u64, // For FDCAN internal timer | 486 | T::mut_state().rx_mode = sealed::RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); |
| 487 | T::mut_state().tx_mode = sealed::TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 488 | }); | ||
| 489 | } | ||
| 512 | } | 490 | } |
| 513 | 491 | ||
| 514 | impl<'c, 'd, T: Instance, M: fdcan::Receive> FdcanRx<'c, 'd, T, M> { | 492 | /// User supplied buffer for RX Buffering |
| 515 | /// Returns the next received message frame | 493 | pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, (FdFrame, Timestamp), BUF_SIZE>; |
| 516 | pub async fn read(&mut self) -> Result<RxFrame, BusError> { | ||
| 517 | poll_fn(|cx| { | ||
| 518 | T::state().err_waker.register(cx.waker()); | ||
| 519 | T::state().rx_waker.register(cx.waker()); | ||
| 520 | |||
| 521 | let mut buffer: [u8; 64] = [0; 64]; | ||
| 522 | if let Ok(rx) = self.rx0.receive(&mut buffer) { | ||
| 523 | // rx: fdcan::ReceiveOverrun<RxFrameInfo> | ||
| 524 | // TODO: report overrun? | ||
| 525 | // for now we just drop it | ||
| 526 | let frame: RxFrame = RxFrame::new( | ||
| 527 | rx.unwrap(), | ||
| 528 | &buffer, | ||
| 529 | #[cfg(feature = "time")] | ||
| 530 | calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp), | ||
| 531 | ); | ||
| 532 | return Poll::Ready(Ok(frame)); | ||
| 533 | } else if let Ok(rx) = self.rx1.receive(&mut buffer) { | ||
| 534 | // rx: fdcan::ReceiveOverrun<RxFrameInfo> | ||
| 535 | // TODO: report overrun? | ||
| 536 | // for now we just drop it | ||
| 537 | let frame: RxFrame = RxFrame::new( | ||
| 538 | rx.unwrap(), | ||
| 539 | &buffer, | ||
| 540 | #[cfg(feature = "time")] | ||
| 541 | calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp), | ||
| 542 | ); | ||
| 543 | return Poll::Ready(Ok(frame)); | ||
| 544 | } else if let Some(err) = curr_error::<T>() { | ||
| 545 | // TODO: this is probably wrong | ||
| 546 | return Poll::Ready(Err(err)); | ||
| 547 | } | ||
| 548 | 494 | ||
| 549 | Poll::Pending | 495 | /// User supplied buffer for TX buffering |
| 550 | }) | 496 | pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>; |
| 551 | .await | 497 | |
| 498 | /// Buffered FDCAN Instance | ||
| 499 | pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { | ||
| 500 | _instance1: PhantomData<T>, | ||
| 501 | _instance2: &'d crate::pac::can::Fdcan, | ||
| 502 | _mode: FdcanOperatingMode, | ||
| 503 | tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, | ||
| 504 | rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, | ||
| 505 | } | ||
| 506 | |||
| 507 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | ||
| 508 | BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> | ||
| 509 | { | ||
| 510 | fn new( | ||
| 511 | _instance1: PhantomData<T>, | ||
| 512 | _instance2: &'d crate::pac::can::Fdcan, | ||
| 513 | _mode: FdcanOperatingMode, | ||
| 514 | tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, | ||
| 515 | rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, | ||
| 516 | ) -> Self { | ||
| 517 | BufferedCanFd { | ||
| 518 | _instance1, | ||
| 519 | _instance2, | ||
| 520 | _mode, | ||
| 521 | tx_buf, | ||
| 522 | rx_buf, | ||
| 523 | } | ||
| 524 | .setup() | ||
| 525 | } | ||
| 526 | |||
| 527 | fn setup(self) -> Self { | ||
| 528 | // We don't want interrupts being processed while we change modes. | ||
| 529 | critical_section::with(|_| unsafe { | ||
| 530 | let rx_inner = sealed::FdBufferedRxInner { | ||
| 531 | rx_sender: self.rx_buf.sender().into(), | ||
| 532 | }; | ||
| 533 | let tx_inner = sealed::FdBufferedTxInner { | ||
| 534 | tx_receiver: self.tx_buf.receiver().into(), | ||
| 535 | }; | ||
| 536 | T::mut_state().rx_mode = sealed::RxMode::FdBuffered(rx_inner); | ||
| 537 | T::mut_state().tx_mode = sealed::TxMode::FdBuffered(tx_inner); | ||
| 538 | }); | ||
| 539 | self | ||
| 540 | } | ||
| 541 | |||
| 542 | /// Async write frame to TX buffer. | ||
| 543 | pub async fn write(&mut self, frame: FdFrame) { | ||
| 544 | self.tx_buf.send(frame).await; | ||
| 545 | T::IT0Interrupt::pend(); // Wake for Tx | ||
| 546 | } | ||
| 547 | |||
| 548 | /// Async read frame from RX buffer. | ||
| 549 | pub async fn read(&mut self) -> Result<(FdFrame, Timestamp), BusError> { | ||
| 550 | Ok(self.rx_buf.receive().await) | ||
| 552 | } | 551 | } |
| 553 | } | 552 | } |
| 554 | impl<'d, T: Instance, M: FdcanOperatingMode> Deref for Fdcan<'d, T, M> { | ||
| 555 | type Target = fdcan::FdCan<FdcanInstance<'d, T>, M>; | ||
| 556 | 553 | ||
| 557 | fn deref(&self) -> &Self::Target { | 554 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop |
| 558 | &self.can | 555 | for BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> |
| 556 | { | ||
| 557 | fn drop(&mut self) { | ||
| 558 | critical_section::with(|_| unsafe { | ||
| 559 | T::mut_state().rx_mode = sealed::RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 560 | T::mut_state().tx_mode = sealed::TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 561 | }); | ||
| 559 | } | 562 | } |
| 560 | } | 563 | } |
| 561 | 564 | ||
| 562 | impl<'d, T: Instance, M: FdcanOperatingMode> DerefMut for Fdcan<'d, T, M> { | 565 | /// FDCAN Rx only Instance |
| 563 | fn deref_mut(&mut self) -> &mut Self::Target { | 566 | pub struct FdcanRx<'d, T: Instance> { |
| 564 | &mut self.can | 567 | _instance1: PhantomData<T>, |
| 568 | _instance2: &'d crate::pac::can::Fdcan, | ||
| 569 | _mode: FdcanOperatingMode, | ||
| 570 | } | ||
| 571 | |||
| 572 | /// FDCAN Tx only Instance | ||
| 573 | pub struct FdcanTx<'d, T: Instance> { | ||
| 574 | config: crate::can::fd::config::FdCanConfig, | ||
| 575 | _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>); | ||
| 576 | _mode: FdcanOperatingMode, | ||
| 577 | } | ||
| 578 | |||
| 579 | impl<'c, 'd, T: Instance> FdcanTx<'d, T> { | ||
| 580 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | ||
| 581 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | ||
| 582 | /// can be replaced, this call asynchronously waits for a frame to be successfully | ||
| 583 | /// transmitted, then tries again. | ||
| 584 | pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> { | ||
| 585 | T::state().tx_mode.write::<T>(frame).await | ||
| 586 | } | ||
| 587 | |||
| 588 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | ||
| 589 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | ||
| 590 | /// can be replaced, this call asynchronously waits for a frame to be successfully | ||
| 591 | /// transmitted, then tries again. | ||
| 592 | pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { | ||
| 593 | T::state().tx_mode.write_fd::<T>(frame).await | ||
| 594 | } | ||
| 595 | } | ||
| 596 | |||
| 597 | impl<'c, 'd, T: Instance> FdcanRx<'d, T> { | ||
| 598 | /// Returns the next received message frame | ||
| 599 | pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { | ||
| 600 | T::state().rx_mode.read::<T>().await | ||
| 601 | } | ||
| 602 | |||
| 603 | /// Returns the next received message frame | ||
| 604 | pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { | ||
| 605 | T::state().rx_mode.read_fd::<T>().await | ||
| 565 | } | 606 | } |
| 566 | } | 607 | } |
| 567 | 608 | ||
| 568 | pub(crate) mod sealed { | 609 | pub(crate) mod sealed { |
| 610 | use core::future::poll_fn; | ||
| 611 | use core::task::Poll; | ||
| 612 | |||
| 613 | use embassy_sync::channel::{DynamicReceiver, DynamicSender}; | ||
| 569 | use embassy_sync::waitqueue::AtomicWaker; | 614 | use embassy_sync::waitqueue::AtomicWaker; |
| 570 | 615 | ||
| 616 | use crate::can::_version::{BusError, Timestamp}; | ||
| 617 | use crate::can::frame::{ClassicFrame, FdFrame}; | ||
| 618 | |||
| 619 | pub struct ClassicBufferedRxInner { | ||
| 620 | pub rx_sender: DynamicSender<'static, (ClassicFrame, Timestamp)>, | ||
| 621 | } | ||
| 622 | pub struct ClassicBufferedTxInner { | ||
| 623 | pub tx_receiver: DynamicReceiver<'static, ClassicFrame>, | ||
| 624 | } | ||
| 625 | |||
| 626 | pub struct FdBufferedRxInner { | ||
| 627 | pub rx_sender: DynamicSender<'static, (FdFrame, Timestamp)>, | ||
| 628 | } | ||
| 629 | pub struct FdBufferedTxInner { | ||
| 630 | pub tx_receiver: DynamicReceiver<'static, FdFrame>, | ||
| 631 | } | ||
| 632 | |||
| 633 | pub enum RxMode { | ||
| 634 | NonBuffered(AtomicWaker), | ||
| 635 | ClassicBuffered(ClassicBufferedRxInner), | ||
| 636 | FdBuffered(FdBufferedRxInner), | ||
| 637 | } | ||
| 638 | |||
| 639 | impl RxMode { | ||
| 640 | pub fn register(&self, arg: &core::task::Waker) { | ||
| 641 | match self { | ||
| 642 | RxMode::NonBuffered(waker) => waker.register(arg), | ||
| 643 | _ => { | ||
| 644 | panic!("Bad Mode") | ||
| 645 | } | ||
| 646 | } | ||
| 647 | } | ||
| 648 | |||
| 649 | pub fn on_interrupt<T: Instance>(&self, fifonr: usize) { | ||
| 650 | T::regs().ir().write(|w| w.set_rfn(fifonr, true)); | ||
| 651 | match self { | ||
| 652 | RxMode::NonBuffered(waker) => { | ||
| 653 | waker.wake(); | ||
| 654 | } | ||
| 655 | RxMode::ClassicBuffered(buf) => { | ||
| 656 | if let Some(r) = T::registers().read_classic(fifonr) { | ||
| 657 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1); | ||
| 658 | let _ = buf.rx_sender.try_send((r.0, ts)); | ||
| 659 | } | ||
| 660 | } | ||
| 661 | RxMode::FdBuffered(buf) => { | ||
| 662 | if let Some(r) = T::registers().read_fd(fifonr) { | ||
| 663 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1); | ||
| 664 | let _ = buf.rx_sender.try_send((r.0, ts)); | ||
| 665 | } | ||
| 666 | } | ||
| 667 | } | ||
| 668 | } | ||
| 669 | |||
| 670 | pub async fn read<T: Instance>(&self) -> Result<(ClassicFrame, Timestamp), BusError> { | ||
| 671 | poll_fn(|cx| { | ||
| 672 | T::state().err_waker.register(cx.waker()); | ||
| 673 | self.register(cx.waker()); | ||
| 674 | |||
| 675 | if let Some((msg, ts)) = T::registers().read_classic(0) { | ||
| 676 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | ||
| 677 | return Poll::Ready(Ok((msg, ts))); | ||
| 678 | } else if let Some((msg, ts)) = T::registers().read_classic(1) { | ||
| 679 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | ||
| 680 | return Poll::Ready(Ok((msg, ts))); | ||
| 681 | } else if let Some(err) = T::registers().curr_error() { | ||
| 682 | // TODO: this is probably wrong | ||
| 683 | return Poll::Ready(Err(err)); | ||
| 684 | } | ||
| 685 | Poll::Pending | ||
| 686 | }) | ||
| 687 | .await | ||
| 688 | } | ||
| 689 | |||
| 690 | pub async fn read_fd<T: Instance>(&self) -> Result<(FdFrame, Timestamp), BusError> { | ||
| 691 | poll_fn(|cx| { | ||
| 692 | T::state().err_waker.register(cx.waker()); | ||
| 693 | self.register(cx.waker()); | ||
| 694 | |||
| 695 | if let Some((msg, ts)) = T::registers().read_fd(0) { | ||
| 696 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | ||
| 697 | return Poll::Ready(Ok((msg, ts))); | ||
| 698 | } else if let Some((msg, ts)) = T::registers().read_fd(1) { | ||
| 699 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | ||
| 700 | return Poll::Ready(Ok((msg, ts))); | ||
| 701 | } else if let Some(err) = T::registers().curr_error() { | ||
| 702 | // TODO: this is probably wrong | ||
| 703 | return Poll::Ready(Err(err)); | ||
| 704 | } | ||
| 705 | Poll::Pending | ||
| 706 | }) | ||
| 707 | .await | ||
| 708 | } | ||
| 709 | } | ||
| 710 | |||
| 711 | pub enum TxMode { | ||
| 712 | NonBuffered(AtomicWaker), | ||
| 713 | ClassicBuffered(ClassicBufferedTxInner), | ||
| 714 | FdBuffered(FdBufferedTxInner), | ||
| 715 | } | ||
| 716 | |||
| 717 | impl TxMode { | ||
| 718 | pub fn register(&self, arg: &core::task::Waker) { | ||
| 719 | match self { | ||
| 720 | TxMode::NonBuffered(waker) => { | ||
| 721 | waker.register(arg); | ||
| 722 | } | ||
| 723 | _ => { | ||
| 724 | panic!("Bad mode"); | ||
| 725 | } | ||
| 726 | } | ||
| 727 | } | ||
| 728 | |||
| 729 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | ||
| 730 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | ||
| 731 | /// can be replaced, this call asynchronously waits for a frame to be successfully | ||
| 732 | /// transmitted, then tries again. | ||
| 733 | pub async fn write<T: Instance>(&self, frame: &ClassicFrame) -> Option<ClassicFrame> { | ||
| 734 | poll_fn(|cx| { | ||
| 735 | self.register(cx.waker()); | ||
| 736 | |||
| 737 | if let Ok(dropped) = T::registers().write_classic(frame) { | ||
| 738 | return Poll::Ready(dropped); | ||
| 739 | } | ||
| 740 | |||
| 741 | // Couldn't replace any lower priority frames. Need to wait for some mailboxes | ||
| 742 | // to clear. | ||
| 743 | Poll::Pending | ||
| 744 | }) | ||
| 745 | .await | ||
| 746 | } | ||
| 747 | |||
| 748 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | ||
| 749 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | ||
| 750 | /// can be replaced, this call asynchronously waits for a frame to be successfully | ||
| 751 | /// transmitted, then tries again. | ||
| 752 | pub async fn write_fd<T: Instance>(&self, frame: &FdFrame) -> Option<FdFrame> { | ||
| 753 | poll_fn(|cx| { | ||
| 754 | self.register(cx.waker()); | ||
| 755 | |||
| 756 | if let Ok(dropped) = T::registers().write_fd(frame) { | ||
| 757 | return Poll::Ready(dropped); | ||
| 758 | } | ||
| 759 | |||
| 760 | // Couldn't replace any lower priority frames. Need to wait for some mailboxes | ||
| 761 | // to clear. | ||
| 762 | Poll::Pending | ||
| 763 | }) | ||
| 764 | .await | ||
| 765 | } | ||
| 766 | } | ||
| 767 | |||
| 571 | pub struct State { | 768 | pub struct State { |
| 572 | pub tx_waker: AtomicWaker, | 769 | pub rx_mode: RxMode, |
| 770 | pub tx_mode: TxMode, | ||
| 771 | pub ns_per_timer_tick: u64, | ||
| 772 | |||
| 573 | pub err_waker: AtomicWaker, | 773 | pub err_waker: AtomicWaker, |
| 574 | pub rx_waker: AtomicWaker, | ||
| 575 | } | 774 | } |
| 576 | 775 | ||
| 577 | impl State { | 776 | impl State { |
| 578 | pub const fn new() -> Self { | 777 | pub const fn new() -> Self { |
| 579 | Self { | 778 | Self { |
| 580 | tx_waker: AtomicWaker::new(), | 779 | rx_mode: RxMode::NonBuffered(AtomicWaker::new()), |
| 780 | tx_mode: TxMode::NonBuffered(AtomicWaker::new()), | ||
| 781 | ns_per_timer_tick: 0, | ||
| 581 | err_waker: AtomicWaker::new(), | 782 | err_waker: AtomicWaker::new(), |
| 582 | rx_waker: AtomicWaker::new(), | ||
| 583 | } | 783 | } |
| 584 | } | 784 | } |
| 585 | } | 785 | } |
| 586 | 786 | ||
| 587 | pub trait Instance { | 787 | pub trait Instance { |
| 588 | const REGISTERS: *mut fdcan::RegisterBlock; | ||
| 589 | const MSG_RAM: *mut fdcan::message_ram::RegisterBlock; | ||
| 590 | const MSG_RAM_OFFSET: usize; | 788 | const MSG_RAM_OFFSET: usize; |
| 591 | 789 | ||
| 592 | fn regs() -> &'static crate::pac::can::Fdcan; | 790 | fn regs() -> &'static crate::pac::can::Fdcan; |
| 791 | fn registers() -> crate::can::fd::peripheral::Registers; | ||
| 792 | fn ram() -> &'static crate::pac::fdcanram::Fdcanram; | ||
| 593 | fn state() -> &'static State; | 793 | fn state() -> &'static State; |
| 794 | unsafe fn mut_state() -> &'static mut State; | ||
| 795 | fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp; | ||
| 594 | 796 | ||
| 595 | #[cfg(not(stm32h7))] | 797 | #[cfg(not(stm32h7))] |
| 596 | fn configure_msg_ram() {} | 798 | fn configure_msg_ram() {} |
| @@ -599,7 +801,8 @@ pub(crate) mod sealed { | |||
| 599 | fn configure_msg_ram() { | 801 | fn configure_msg_ram() { |
| 600 | let r = Self::regs(); | 802 | let r = Self::regs(); |
| 601 | 803 | ||
| 602 | use fdcan::message_ram::*; | 804 | use crate::can::fd::message_ram::*; |
| 805 | //use fdcan::message_ram::*; | ||
| 603 | let mut offset_words = Self::MSG_RAM_OFFSET as u16; | 806 | let mut offset_words = Self::MSG_RAM_OFFSET as u16; |
| 604 | 807 | ||
| 605 | // 11-bit filter | 808 | // 11-bit filter |
| @@ -677,32 +880,45 @@ pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + ' | |||
| 677 | /// Fdcan Instance struct | 880 | /// Fdcan Instance struct |
| 678 | pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); | 881 | pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); |
| 679 | 882 | ||
| 680 | unsafe impl<'d, T: Instance> fdcan::message_ram::Instance for FdcanInstance<'d, T> { | ||
| 681 | const MSG_RAM: *mut RegisterBlock = T::MSG_RAM; | ||
| 682 | } | ||
| 683 | |||
| 684 | unsafe impl<'d, T: Instance> fdcan::Instance for FdcanInstance<'d, T> | ||
| 685 | where | ||
| 686 | FdcanInstance<'d, T>: fdcan::message_ram::Instance, | ||
| 687 | { | ||
| 688 | const REGISTERS: *mut fdcan::RegisterBlock = T::REGISTERS; | ||
| 689 | } | ||
| 690 | |||
| 691 | macro_rules! impl_fdcan { | 883 | macro_rules! impl_fdcan { |
| 692 | ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => { | 884 | ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => { |
| 693 | impl sealed::Instance for peripherals::$inst { | 885 | impl sealed::Instance for peripherals::$inst { |
| 694 | const REGISTERS: *mut fdcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; | ||
| 695 | const MSG_RAM: *mut fdcan::message_ram::RegisterBlock = crate::pac::$msg_ram_inst.as_ptr() as *mut _; | ||
| 696 | const MSG_RAM_OFFSET: usize = $msg_ram_offset; | 886 | const MSG_RAM_OFFSET: usize = $msg_ram_offset; |
| 697 | 887 | ||
| 698 | fn regs() -> &'static crate::pac::can::Fdcan { | 888 | fn regs() -> &'static crate::pac::can::Fdcan { |
| 699 | &crate::pac::$inst | 889 | &crate::pac::$inst |
| 700 | } | 890 | } |
| 701 | 891 | fn registers() -> Registers { | |
| 892 | Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst} | ||
| 893 | } | ||
| 894 | fn ram() -> &'static crate::pac::fdcanram::Fdcanram { | ||
| 895 | &crate::pac::$msg_ram_inst | ||
| 896 | } | ||
| 897 | unsafe fn mut_state() -> & 'static mut sealed::State { | ||
| 898 | static mut STATE: sealed::State = sealed::State::new(); | ||
| 899 | & mut STATE | ||
| 900 | } | ||
| 702 | fn state() -> &'static sealed::State { | 901 | fn state() -> &'static sealed::State { |
| 703 | static STATE: sealed::State = sealed::State::new(); | 902 | unsafe { peripherals::$inst::mut_state() } |
| 704 | &STATE | ||
| 705 | } | 903 | } |
| 904 | |||
| 905 | #[cfg(feature = "time")] | ||
| 906 | fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { | ||
| 907 | let now_embassy = embassy_time::Instant::now(); | ||
| 908 | if ns_per_timer_tick == 0 { | ||
| 909 | return now_embassy; | ||
| 910 | } | ||
| 911 | let cantime = { Self::regs().tscv().read().tsc() }; | ||
| 912 | let delta = cantime.overflowing_sub(ts_val).0 as u64; | ||
| 913 | let ns = ns_per_timer_tick * delta as u64; | ||
| 914 | now_embassy - embassy_time::Duration::from_nanos(ns) | ||
| 915 | } | ||
| 916 | |||
| 917 | #[cfg(not(feature = "time"))] | ||
| 918 | fn calc_timestamp(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { | ||
| 919 | ts_val | ||
| 920 | } | ||
| 921 | |||
| 706 | } | 922 | } |
| 707 | 923 | ||
| 708 | impl Instance for peripherals::$inst {} | 924 | impl Instance for peripherals::$inst {} |
diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs new file mode 100644 index 000000000..725a9b1ab --- /dev/null +++ b/embassy-stm32/src/can/frame.rs | |||
| @@ -0,0 +1,370 @@ | |||
| 1 | //! Definition for CAN Frames | ||
| 2 | use bit_field::BitField; | ||
| 3 | |||
| 4 | /// CAN Header, without meta data | ||
| 5 | #[derive(Debug, Copy, Clone)] | ||
| 6 | pub struct Header { | ||
| 7 | id: embedded_can::Id, | ||
| 8 | len: u8, | ||
| 9 | flags: u8, | ||
| 10 | } | ||
| 11 | |||
| 12 | impl Header { | ||
| 13 | const FLAG_RTR: usize = 0; // Remote | ||
| 14 | const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN | ||
| 15 | const FLAG_BRS: usize = 2; // Bit-rate switching, ignored for Classic CAN | ||
| 16 | |||
| 17 | /// Create new CAN Header | ||
| 18 | pub fn new(id: embedded_can::Id, len: u8, rtr: bool) -> Header { | ||
| 19 | let mut flags = 0u8; | ||
| 20 | flags.set_bit(Self::FLAG_RTR, rtr); | ||
| 21 | Header { id, len, flags } | ||
| 22 | } | ||
| 23 | |||
| 24 | /// Create new CAN FD Header | ||
| 25 | pub fn new_fd(id: embedded_can::Id, len: u8, rtr: bool, brs: bool) -> Header { | ||
| 26 | let mut flags = 0u8; | ||
| 27 | flags.set_bit(Self::FLAG_RTR, rtr); | ||
| 28 | flags.set_bit(Self::FLAG_FDCAN, true); | ||
| 29 | flags.set_bit(Self::FLAG_BRS, brs); | ||
| 30 | Header { id, len, flags } | ||
| 31 | } | ||
| 32 | |||
| 33 | /// Return ID | ||
| 34 | pub fn id(&self) -> &embedded_can::Id { | ||
| 35 | &self.id | ||
| 36 | } | ||
| 37 | |||
| 38 | /// Return length as u8 | ||
| 39 | pub fn len(&self) -> u8 { | ||
| 40 | self.len | ||
| 41 | } | ||
| 42 | |||
| 43 | /// Is remote frame | ||
| 44 | pub fn rtr(&self) -> bool { | ||
| 45 | self.flags.get_bit(Self::FLAG_RTR) | ||
| 46 | } | ||
| 47 | |||
| 48 | /// Request/is FDCAN frame | ||
| 49 | pub fn fdcan(&self) -> bool { | ||
| 50 | self.flags.get_bit(Self::FLAG_FDCAN) | ||
| 51 | } | ||
| 52 | |||
| 53 | /// Request/is Flexible Data Rate | ||
| 54 | pub fn bit_rate_switching(&self) -> bool { | ||
| 55 | self.flags.get_bit(Self::FLAG_BRS) | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | /// Payload of a classic CAN data frame. | ||
| 60 | /// | ||
| 61 | /// Contains 0 to 8 Bytes of data. | ||
| 62 | #[derive(Debug, Copy, Clone)] | ||
| 63 | pub struct ClassicData { | ||
| 64 | pub(crate) bytes: [u8; 8], | ||
| 65 | } | ||
| 66 | |||
| 67 | impl ClassicData { | ||
| 68 | /// Creates a data payload from a raw byte slice. | ||
| 69 | /// | ||
| 70 | /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or | ||
| 71 | /// cannot be represented with an FDCAN DLC. | ||
| 72 | pub fn new(data: &[u8]) -> Option<Self> { | ||
| 73 | if !FdData::is_valid_len(data.len()) { | ||
| 74 | return None; | ||
| 75 | } | ||
| 76 | |||
| 77 | let mut bytes = [0; 8]; | ||
| 78 | bytes[..data.len()].copy_from_slice(data); | ||
| 79 | |||
| 80 | Some(Self { bytes }) | ||
| 81 | } | ||
| 82 | |||
| 83 | /// Raw read access to data. | ||
| 84 | pub fn raw(&self) -> &[u8] { | ||
| 85 | &self.bytes | ||
| 86 | } | ||
| 87 | |||
| 88 | /// Checks if the length can be encoded in FDCAN DLC field. | ||
| 89 | pub const fn is_valid_len(len: usize) -> bool { | ||
| 90 | match len { | ||
| 91 | 0..=8 => true, | ||
| 92 | _ => false, | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | /// Creates an empty data payload containing 0 bytes. | ||
| 97 | #[inline] | ||
| 98 | pub const fn empty() -> Self { | ||
| 99 | Self { bytes: [0; 8] } | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | /// Frame with up to 8 bytes of data payload as per Classic CAN | ||
| 104 | #[derive(Debug, Copy, Clone)] | ||
| 105 | pub struct ClassicFrame { | ||
| 106 | can_header: Header, | ||
| 107 | data: ClassicData, | ||
| 108 | } | ||
| 109 | |||
| 110 | impl ClassicFrame { | ||
| 111 | pub(crate) const MAX_DATA_LEN: usize = 8; | ||
| 112 | |||
| 113 | /// Create a new CAN classic Frame | ||
| 114 | pub fn new(can_header: Header, data: ClassicData) -> ClassicFrame { | ||
| 115 | ClassicFrame { can_header, data } | ||
| 116 | } | ||
| 117 | |||
| 118 | /// Create new extended frame | ||
| 119 | pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> { | ||
| 120 | if let Some(id) = embedded_can::ExtendedId::new(raw_id) { | ||
| 121 | match ClassicData::new(raw_data) { | ||
| 122 | Some(data) => Some(ClassicFrame::new( | ||
| 123 | Header::new(id.into(), raw_data.len() as u8, false), | ||
| 124 | data, | ||
| 125 | )), | ||
| 126 | None => None, | ||
| 127 | } | ||
| 128 | } else { | ||
| 129 | None | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | /// Create new standard frame | ||
| 134 | pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> { | ||
| 135 | if let Some(id) = embedded_can::StandardId::new(raw_id) { | ||
| 136 | match ClassicData::new(raw_data) { | ||
| 137 | Some(data) => Some(ClassicFrame::new( | ||
| 138 | Header::new(id.into(), raw_data.len() as u8, false), | ||
| 139 | data, | ||
| 140 | )), | ||
| 141 | None => None, | ||
| 142 | } | ||
| 143 | } else { | ||
| 144 | None | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | /// Create new remote frame | ||
| 149 | pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { | ||
| 150 | if len <= 8usize { | ||
| 151 | Some(ClassicFrame::new( | ||
| 152 | Header::new(id.into(), len as u8, true), | ||
| 153 | ClassicData::empty(), | ||
| 154 | )) | ||
| 155 | } else { | ||
| 156 | None | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | /// Get reference to data | ||
| 161 | pub fn header(&self) -> &Header { | ||
| 162 | &self.can_header | ||
| 163 | } | ||
| 164 | |||
| 165 | /// Return ID | ||
| 166 | pub fn id(&self) -> &embedded_can::Id { | ||
| 167 | &self.can_header.id | ||
| 168 | } | ||
| 169 | |||
| 170 | /// Get reference to data | ||
| 171 | pub fn data(&self) -> &[u8] { | ||
| 172 | &self.data.raw() | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | impl embedded_can::Frame for ClassicFrame { | ||
| 177 | fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { | ||
| 178 | match ClassicData::new(raw_data) { | ||
| 179 | Some(data) => Some(ClassicFrame::new( | ||
| 180 | Header::new(id.into(), raw_data.len() as u8, false), | ||
| 181 | data, | ||
| 182 | )), | ||
| 183 | None => None, | ||
| 184 | } | ||
| 185 | } | ||
| 186 | fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { | ||
| 187 | if len <= 8 { | ||
| 188 | Some(ClassicFrame::new( | ||
| 189 | Header::new(id.into(), len as u8, true), | ||
| 190 | ClassicData::empty(), | ||
| 191 | )) | ||
| 192 | } else { | ||
| 193 | None | ||
| 194 | } | ||
| 195 | } | ||
| 196 | fn is_extended(&self) -> bool { | ||
| 197 | match self.can_header.id { | ||
| 198 | embedded_can::Id::Extended(_) => true, | ||
| 199 | embedded_can::Id::Standard(_) => true, | ||
| 200 | } | ||
| 201 | } | ||
| 202 | fn is_remote_frame(&self) -> bool { | ||
| 203 | self.can_header.rtr() | ||
| 204 | } | ||
| 205 | fn id(&self) -> embedded_can::Id { | ||
| 206 | self.can_header.id | ||
| 207 | } | ||
| 208 | fn dlc(&self) -> usize { | ||
| 209 | self.can_header.len as usize | ||
| 210 | } | ||
| 211 | fn data(&self) -> &[u8] { | ||
| 212 | &self.data.raw() | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | /// Payload of a (FD)CAN data frame. | ||
| 217 | /// | ||
| 218 | /// Contains 0 to 64 Bytes of data. | ||
| 219 | #[derive(Debug, Copy, Clone)] | ||
| 220 | pub struct FdData { | ||
| 221 | pub(crate) bytes: [u8; 64], | ||
| 222 | } | ||
| 223 | |||
| 224 | impl FdData { | ||
| 225 | /// Creates a data payload from a raw byte slice. | ||
| 226 | /// | ||
| 227 | /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or | ||
| 228 | /// cannot be represented with an FDCAN DLC. | ||
| 229 | pub fn new(data: &[u8]) -> Option<Self> { | ||
| 230 | if !FdData::is_valid_len(data.len()) { | ||
| 231 | return None; | ||
| 232 | } | ||
| 233 | |||
| 234 | let mut bytes = [0; 64]; | ||
| 235 | bytes[..data.len()].copy_from_slice(data); | ||
| 236 | |||
| 237 | Some(Self { bytes }) | ||
| 238 | } | ||
| 239 | |||
| 240 | /// Raw read access to data. | ||
| 241 | pub fn raw(&self) -> &[u8] { | ||
| 242 | &self.bytes | ||
| 243 | } | ||
| 244 | |||
| 245 | /// Checks if the length can be encoded in FDCAN DLC field. | ||
| 246 | pub const fn is_valid_len(len: usize) -> bool { | ||
| 247 | match len { | ||
| 248 | 0..=8 => true, | ||
| 249 | 12 => true, | ||
| 250 | 16 => true, | ||
| 251 | 20 => true, | ||
| 252 | 24 => true, | ||
| 253 | 32 => true, | ||
| 254 | 48 => true, | ||
| 255 | 64 => true, | ||
| 256 | _ => false, | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | /// Creates an empty data payload containing 0 bytes. | ||
| 261 | #[inline] | ||
| 262 | pub const fn empty() -> Self { | ||
| 263 | Self { bytes: [0; 64] } | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | /// Frame with up to 8 bytes of data payload as per Fd CAN | ||
| 268 | #[derive(Debug, Copy, Clone)] | ||
| 269 | pub struct FdFrame { | ||
| 270 | can_header: Header, | ||
| 271 | data: FdData, | ||
| 272 | } | ||
| 273 | |||
| 274 | impl FdFrame { | ||
| 275 | pub(crate) const MAX_DATA_LEN: usize = 64; | ||
| 276 | |||
| 277 | /// Create a new CAN classic Frame | ||
| 278 | pub fn new(can_header: Header, data: FdData) -> FdFrame { | ||
| 279 | FdFrame { can_header, data } | ||
| 280 | } | ||
| 281 | |||
| 282 | /// Create new extended frame | ||
| 283 | pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> { | ||
| 284 | if let Some(id) = embedded_can::ExtendedId::new(raw_id) { | ||
| 285 | match FdData::new(raw_data) { | ||
| 286 | Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)), | ||
| 287 | None => None, | ||
| 288 | } | ||
| 289 | } else { | ||
| 290 | None | ||
| 291 | } | ||
| 292 | } | ||
| 293 | |||
| 294 | /// Create new standard frame | ||
| 295 | pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> { | ||
| 296 | if let Some(id) = embedded_can::StandardId::new(raw_id) { | ||
| 297 | match FdData::new(raw_data) { | ||
| 298 | Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)), | ||
| 299 | None => None, | ||
| 300 | } | ||
| 301 | } else { | ||
| 302 | None | ||
| 303 | } | ||
| 304 | } | ||
| 305 | |||
| 306 | /// Create new remote frame | ||
| 307 | pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { | ||
| 308 | if len <= 8 { | ||
| 309 | Some(FdFrame::new(Header::new(id.into(), len as u8, true), FdData::empty())) | ||
| 310 | } else { | ||
| 311 | None | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 315 | /// Get reference to data | ||
| 316 | pub fn header(&self) -> &Header { | ||
| 317 | &self.can_header | ||
| 318 | } | ||
| 319 | |||
| 320 | /// Return ID | ||
| 321 | pub fn id(&self) -> &embedded_can::Id { | ||
| 322 | &self.can_header.id | ||
| 323 | } | ||
| 324 | |||
| 325 | /// Get reference to data | ||
| 326 | pub fn data(&self) -> &[u8] { | ||
| 327 | &self.data.raw() | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | impl embedded_can::Frame for FdFrame { | ||
| 332 | fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { | ||
| 333 | match FdData::new(raw_data) { | ||
| 334 | Some(data) => Some(FdFrame::new( | ||
| 335 | Header::new_fd(id.into(), raw_data.len() as u8, false, true), | ||
| 336 | data, | ||
| 337 | )), | ||
| 338 | None => None, | ||
| 339 | } | ||
| 340 | } | ||
| 341 | fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { | ||
| 342 | if len <= 8 { | ||
| 343 | Some(FdFrame::new( | ||
| 344 | Header::new_fd(id.into(), len as u8, true, true), | ||
| 345 | FdData::empty(), | ||
| 346 | )) | ||
| 347 | } else { | ||
| 348 | None | ||
| 349 | } | ||
| 350 | } | ||
| 351 | fn is_extended(&self) -> bool { | ||
| 352 | match self.can_header.id { | ||
| 353 | embedded_can::Id::Extended(_) => true, | ||
| 354 | embedded_can::Id::Standard(_) => true, | ||
| 355 | } | ||
| 356 | } | ||
| 357 | fn is_remote_frame(&self) -> bool { | ||
| 358 | self.can_header.rtr() | ||
| 359 | } | ||
| 360 | fn id(&self) -> embedded_can::Id { | ||
| 361 | self.can_header.id | ||
| 362 | } | ||
| 363 | // Returns length in bytes even for CANFD packets which embedded-can does not really mention. | ||
| 364 | fn dlc(&self) -> usize { | ||
| 365 | self.can_header.len as usize | ||
| 366 | } | ||
| 367 | fn data(&self) -> &[u8] { | ||
| 368 | &self.data.raw() | ||
| 369 | } | ||
| 370 | } | ||
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 077cfdcd9..994bdb1e6 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs | |||
| @@ -299,7 +299,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 299 | STATE.complete_count[this.channel.index()].store(0, Ordering::Release); | 299 | STATE.complete_count[this.channel.index()].store(0, Ordering::Release); |
| 300 | 300 | ||
| 301 | #[cfg(dmamux)] | 301 | #[cfg(dmamux)] |
| 302 | super::dmamux::configure_dmamux(&mut *this.channel, _request); | 302 | super::dmamux::configure_dmamux(&*this.channel, _request); |
| 303 | 303 | ||
| 304 | ch.par().write_value(peri_addr as u32); | 304 | ch.par().write_value(peri_addr as u32); |
| 305 | ch.mar().write_value(mem_addr as u32); | 305 | ch.mar().write_value(mem_addr as u32); |
| @@ -483,7 +483,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 483 | this.clear_irqs(); | 483 | this.clear_irqs(); |
| 484 | 484 | ||
| 485 | #[cfg(dmamux)] | 485 | #[cfg(dmamux)] |
| 486 | super::dmamux::configure_dmamux(&mut *this.channel, _request); | 486 | super::dmamux::configure_dmamux(&*this.channel, _request); |
| 487 | 487 | ||
| 488 | let ch = dma.ch(channel_number); | 488 | let ch = dma.ch(channel_number); |
| 489 | ch.par().write_value(peri_addr as u32); | 489 | ch.par().write_value(peri_addr as u32); |
| @@ -641,7 +641,7 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | |||
| 641 | this.clear_irqs(); | 641 | this.clear_irqs(); |
| 642 | 642 | ||
| 643 | #[cfg(dmamux)] | 643 | #[cfg(dmamux)] |
| 644 | super::dmamux::configure_dmamux(&mut *this.channel, _request); | 644 | super::dmamux::configure_dmamux(&*this.channel, _request); |
| 645 | 645 | ||
| 646 | let ch = dma.ch(channel_number); | 646 | let ch = dma.ch(channel_number); |
| 647 | ch.par().write_value(peri_addr as u32); | 647 | ch.par().write_value(peri_addr as u32); |
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index ef9bb3d78..e762b1bde 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs | |||
| @@ -366,7 +366,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 366 | this.clear_irqs(); | 366 | this.clear_irqs(); |
| 367 | 367 | ||
| 368 | #[cfg(dmamux)] | 368 | #[cfg(dmamux)] |
| 369 | super::dmamux::configure_dmamux(&mut *this.channel, _request); | 369 | super::dmamux::configure_dmamux(&*this.channel, _request); |
| 370 | 370 | ||
| 371 | ch.par().write_value(peri_addr as u32); | 371 | ch.par().write_value(peri_addr as u32); |
| 372 | ch.m0ar().write_value(mem_addr as u32); | 372 | ch.m0ar().write_value(mem_addr as u32); |
| @@ -522,7 +522,7 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { | |||
| 522 | this.clear_irqs(); | 522 | this.clear_irqs(); |
| 523 | 523 | ||
| 524 | #[cfg(dmamux)] | 524 | #[cfg(dmamux)] |
| 525 | super::dmamux::configure_dmamux(&mut *this.channel, _request); | 525 | super::dmamux::configure_dmamux(&*this.channel, _request); |
| 526 | 526 | ||
| 527 | let ch = dma.st(channel_number); | 527 | let ch = dma.st(channel_number); |
| 528 | ch.par().write_value(peri_addr as u32); | 528 | ch.par().write_value(peri_addr as u32); |
| @@ -726,7 +726,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 726 | this.clear_irqs(); | 726 | this.clear_irqs(); |
| 727 | 727 | ||
| 728 | #[cfg(dmamux)] | 728 | #[cfg(dmamux)] |
| 729 | super::dmamux::configure_dmamux(&mut *this.channel, _request); | 729 | super::dmamux::configure_dmamux(&*this.channel, _request); |
| 730 | 730 | ||
| 731 | let ch = dma.st(channel_number); | 731 | let ch = dma.st(channel_number); |
| 732 | ch.par().write_value(peri_addr as u32); | 732 | ch.par().write_value(peri_addr as u32); |
| @@ -901,7 +901,7 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | |||
| 901 | this.clear_irqs(); | 901 | this.clear_irqs(); |
| 902 | 902 | ||
| 903 | #[cfg(dmamux)] | 903 | #[cfg(dmamux)] |
| 904 | super::dmamux::configure_dmamux(&mut *this.channel, _request); | 904 | super::dmamux::configure_dmamux(&*this.channel, _request); |
| 905 | 905 | ||
| 906 | let ch = dma.st(channel_number); | 906 | let ch = dma.st(channel_number); |
| 907 | ch.par().write_value(peri_addr as u32); | 907 | ch.par().write_value(peri_addr as u32); |
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs index 9cd494724..ac6f44107 100644 --- a/embassy-stm32/src/dma/dmamux.rs +++ b/embassy-stm32/src/dma/dmamux.rs | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | use crate::{pac, peripherals}; | 3 | use crate::{pac, peripherals}; |
| 4 | 4 | ||
| 5 | pub(crate) fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) { | 5 | pub(crate) fn configure_dmamux<M: MuxChannel>(channel: &M, request: u8) { |
| 6 | let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num()); | 6 | let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num()); |
| 7 | ch_mux_regs.write(|reg| { | 7 | ch_mux_regs.write(|reg| { |
| 8 | reg.set_nbreq(0); | 8 | reg.set_nbreq(0); |
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index 34b2426b9..337e7b309 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs | |||
| @@ -259,7 +259,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 259 | let this = Self { channel }; | 259 | let this = Self { channel }; |
| 260 | 260 | ||
| 261 | #[cfg(dmamux)] | 261 | #[cfg(dmamux)] |
| 262 | super::dmamux::configure_dmamux(&mut *this.channel, request); | 262 | super::dmamux::configure_dmamux(&*this.channel, request); |
| 263 | 263 | ||
| 264 | ch.cr().write(|w| w.set_reset(true)); | 264 | ch.cr().write(|w| w.set_reset(true)); |
| 265 | ch.fcr().write(|w| w.0 = 0xFFFF_FFFF); // clear all irqs | 265 | ch.fcr().write(|w| w.0 = 0xFFFF_FFFF); // clear all irqs |
diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs new file mode 100644 index 000000000..db05bef5d --- /dev/null +++ b/embassy-stm32/src/flash/h50.rs | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | /// STM32H50 series flash impl. See RM0492 | ||
| 2 | use core::{ | ||
| 3 | ptr::write_volatile, | ||
| 4 | sync::atomic::{fence, Ordering}, | ||
| 5 | }; | ||
| 6 | |||
| 7 | use cortex_m::interrupt; | ||
| 8 | use pac::flash::regs::Nssr; | ||
| 9 | use pac::flash::vals::Bksel; | ||
| 10 | |||
| 11 | use super::{Error, FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | ||
| 12 | use crate::pac; | ||
| 13 | |||
| 14 | pub(crate) const fn is_default_layout() -> bool { | ||
| 15 | true | ||
| 16 | } | ||
| 17 | |||
| 18 | pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { | ||
| 19 | &FLASH_REGIONS | ||
| 20 | } | ||
| 21 | |||
| 22 | pub(crate) unsafe fn lock() { | ||
| 23 | pac::FLASH.nscr().modify(|w| w.set_lock(true)); | ||
| 24 | } | ||
| 25 | |||
| 26 | pub(crate) unsafe fn unlock() { | ||
| 27 | while busy() {} | ||
| 28 | |||
| 29 | if pac::FLASH.nscr().read().lock() { | ||
| 30 | pac::FLASH.nskeyr().write_value(0x4567_0123); | ||
| 31 | pac::FLASH.nskeyr().write_value(0xCDEF_89AB); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | pub(crate) unsafe fn enable_blocking_write() { | ||
| 36 | assert_eq!(0, WRITE_SIZE % 4); | ||
| 37 | pac::FLASH.nscr().write(|w| w.set_pg(true)); | ||
| 38 | } | ||
| 39 | |||
| 40 | pub(crate) unsafe fn disable_blocking_write() { | ||
| 41 | pac::FLASH.nscr().write(|w| w.set_pg(false)); | ||
| 42 | } | ||
| 43 | |||
| 44 | pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | ||
| 45 | let mut address = start_address; | ||
| 46 | for val in buf.chunks(4) { | ||
| 47 | write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); | ||
| 48 | address += val.len() as u32; | ||
| 49 | |||
| 50 | // prevents parallelism errors | ||
| 51 | fence(Ordering::SeqCst); | ||
| 52 | } | ||
| 53 | |||
| 54 | wait_ready_blocking() | ||
| 55 | } | ||
| 56 | |||
| 57 | pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { | ||
| 58 | assert!(sector.bank != FlashBank::Otp); | ||
| 59 | assert!(sector.index_in_bank < 8); | ||
| 60 | |||
| 61 | while busy() {} | ||
| 62 | |||
| 63 | interrupt::free(|_| { | ||
| 64 | pac::FLASH.nscr().modify(|w| { | ||
| 65 | w.set_bksel(match sector.bank { | ||
| 66 | FlashBank::Bank1 => Bksel::B_0X0, | ||
| 67 | FlashBank::Bank2 => Bksel::B_0X1, | ||
| 68 | _ => unreachable!(), | ||
| 69 | }); | ||
| 70 | w.set_snb(sector.index_in_bank); | ||
| 71 | w.set_ser(true); | ||
| 72 | w.set_strt(true); | ||
| 73 | }) | ||
| 74 | }); | ||
| 75 | |||
| 76 | let ret = wait_ready_blocking(); | ||
| 77 | pac::FLASH.nscr().modify(|w| w.set_ser(false)); | ||
| 78 | ret | ||
| 79 | } | ||
| 80 | |||
| 81 | pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> { | ||
| 82 | loop { | ||
| 83 | let sr = pac::FLASH.nssr().read(); | ||
| 84 | |||
| 85 | if !sr_busy(sr) { | ||
| 86 | if sr.wrperr() { | ||
| 87 | return Err(Error::Protected); | ||
| 88 | } | ||
| 89 | if sr.pgserr() { | ||
| 90 | return Err(Error::Seq); | ||
| 91 | } | ||
| 92 | if sr.strberr() { | ||
| 93 | // writing several times to the same byte in the write buffer | ||
| 94 | return Err(Error::Prog); | ||
| 95 | } | ||
| 96 | if sr.incerr() { | ||
| 97 | // attempting write operation before completion of previous | ||
| 98 | // write operation | ||
| 99 | return Err(Error::Seq); | ||
| 100 | } | ||
| 101 | |||
| 102 | return Ok(()); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | pub(crate) unsafe fn clear_all_err() { | ||
| 108 | pac::FLASH.nsccr().modify(|w| { | ||
| 109 | w.set_clr_wrperr(true); | ||
| 110 | w.set_clr_pgserr(true); | ||
| 111 | w.set_clr_strberr(true); | ||
| 112 | w.set_clr_incerr(true); | ||
| 113 | }) | ||
| 114 | } | ||
| 115 | |||
| 116 | fn sr_busy(sr: Nssr) -> bool { | ||
| 117 | // Note: RM0492 sometimes incorrectly refers to WBNE as NSWBNE | ||
| 118 | sr.bsy() || sr.dbne() || sr.wbne() | ||
| 119 | } | ||
| 120 | |||
| 121 | fn busy() -> bool { | ||
| 122 | let sr = pac::FLASH.nssr().read(); | ||
| 123 | sr_busy(sr) | ||
| 124 | } | ||
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 4f43a7a48..1d8031e82 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs | |||
| @@ -102,10 +102,11 @@ pub enum FlashBank { | |||
| 102 | #[cfg_attr(flash_h7, path = "h7.rs")] | 102 | #[cfg_attr(flash_h7, path = "h7.rs")] |
| 103 | #[cfg_attr(flash_h7ab, path = "h7.rs")] | 103 | #[cfg_attr(flash_h7ab, path = "h7.rs")] |
| 104 | #[cfg_attr(flash_u5, path = "u5.rs")] | 104 | #[cfg_attr(flash_u5, path = "u5.rs")] |
| 105 | #[cfg_attr(flash_h50, path = "h50.rs")] | ||
| 105 | #[cfg_attr( | 106 | #[cfg_attr( |
| 106 | not(any( | 107 | not(any( |
| 107 | flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0, | 108 | flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0, |
| 108 | flash_g4, flash_h7, flash_h7ab, flash_u5 | 109 | flash_g4, flash_h7, flash_h7ab, flash_u5, flash_h50 |
| 109 | )), | 110 | )), |
| 110 | path = "other.rs" | 111 | path = "other.rs" |
| 111 | )] | 112 | )] |
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index d381ec1bd..39407b28c 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs | |||
| @@ -201,11 +201,18 @@ impl LsConfig { | |||
| 201 | bdcr().modify(|w| w.set_bdrst(true)); | 201 | bdcr().modify(|w| w.set_bdrst(true)); |
| 202 | bdcr().modify(|w| w.set_bdrst(false)); | 202 | bdcr().modify(|w| w.set_bdrst(false)); |
| 203 | } | 203 | } |
| 204 | #[cfg(any(stm32h5))] | 204 | // H5 has a terrible, terrible errata: 'SRAM2 is erased when the backup domain is reset' |
| 205 | { | 205 | // pending a more sane sane way to handle this, just don't reset BD for now. |
| 206 | bdcr().modify(|w| w.set_vswrst(true)); | 206 | // This means the RTCSEL write below will have no effect, only if it has already been written |
| 207 | bdcr().modify(|w| w.set_vswrst(false)); | 207 | // after last power-on. Since it's uncommon to dynamically change RTCSEL, this is better than |
| 208 | } | 208 | // letting half our RAM go magically *poof*. |
| 209 | // STM32H503CB/EB/KB/RB device errata - 2.2.8 SRAM2 unduly erased upon a backup domain reset | ||
| 210 | // STM32H562xx/563xx/573xx device errata - 2.2.14 SRAM2 is erased when the backup domain is reset | ||
| 211 | //#[cfg(any(stm32h5))] | ||
| 212 | //{ | ||
| 213 | // bdcr().modify(|w| w.set_vswrst(true)); | ||
| 214 | // bdcr().modify(|w| w.set_vswrst(false)); | ||
| 215 | //} | ||
| 209 | #[cfg(any(stm32c0, stm32l0))] | 216 | #[cfg(any(stm32c0, stm32l0))] |
| 210 | { | 217 | { |
| 211 | bdcr().modify(|w| w.set_rtcrst(true)); | 218 | bdcr().modify(|w| w.set_rtcrst(true)); |
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 20cc3112a..72613f0f3 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs | |||
| @@ -1,134 +1,83 @@ | |||
| 1 | pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange, Plldiv, Pllm, Plln, Ppre as APBPrescaler}; | 1 | pub use crate::pac::pwr::vals::Vos as VoltageScale; |
| 2 | use crate::pac::rcc::vals::{Msirgsel, Pllmboost, Pllrge, Pllsrc, Sw}; | 2 | pub use crate::pac::rcc::vals::{ |
| 3 | Hpre as AHBPrescaler, Msirange, Msirange as MSIRange, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, | ||
| 4 | Pllsrc as PllSource, Ppre as APBPrescaler, Sw as ClockSrc, | ||
| 5 | }; | ||
| 6 | use crate::pac::rcc::vals::{Hseext, Msirgsel, Pllmboost, Pllrge}; | ||
| 3 | use crate::pac::{FLASH, PWR, RCC}; | 7 | use crate::pac::{FLASH, PWR, RCC}; |
| 4 | use crate::time::Hertz; | 8 | use crate::time::Hertz; |
| 5 | 9 | ||
| 6 | /// HSI speed | 10 | /// HSI speed |
| 7 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); | 11 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); |
| 8 | 12 | ||
| 9 | pub use crate::pac::pwr::vals::Vos as VoltageScale; | 13 | #[derive(Clone, Copy, Eq, PartialEq)] |
| 10 | 14 | pub enum HseMode { | |
| 11 | #[derive(Copy, Clone)] | 15 | /// crystal/ceramic oscillator (HSEBYP=0) |
| 12 | #[allow(non_camel_case_types)] | 16 | Oscillator, |
| 13 | pub enum ClockSrc { | 17 | /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) |
| 14 | /// Use an internal medium speed oscillator (MSIS) as the system clock. | 18 | Bypass, |
| 15 | MSI(Msirange), | 19 | /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1) |
| 16 | /// Use the external high speed clock as the system clock. | 20 | BypassDigital, |
| 17 | /// | ||
| 18 | /// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must | ||
| 19 | /// never exceed 50 MHz. | ||
| 20 | HSE(Hertz), | ||
| 21 | /// Use the 16 MHz internal high speed oscillator as the system clock. | ||
| 22 | HSI, | ||
| 23 | /// Use PLL1 as the system clock. | ||
| 24 | PLL1_R(PllConfig), | ||
| 25 | } | 21 | } |
| 26 | 22 | ||
| 27 | impl Default for ClockSrc { | 23 | #[derive(Clone, Copy, Eq, PartialEq)] |
| 28 | fn default() -> Self { | 24 | pub struct Hse { |
| 29 | // The default system clock source is MSIS @ 4 MHz, per RM0456 § 11.4.9 | 25 | /// HSE frequency. |
| 30 | ClockSrc::MSI(Msirange::RANGE_4MHZ) | 26 | pub freq: Hertz, |
| 31 | } | 27 | /// HSE mode. |
| 28 | pub mode: HseMode, | ||
| 32 | } | 29 | } |
| 33 | 30 | ||
| 34 | #[derive(Clone, Copy)] | 31 | #[derive(Clone, Copy)] |
| 35 | pub struct PllConfig { | 32 | pub struct Pll { |
| 36 | /// The clock source for the PLL. | 33 | /// The clock source for the PLL. |
| 37 | pub source: PllSource, | 34 | pub source: PllSource, |
| 38 | /// The PLL prescaler. | 35 | /// The PLL pre-divider. |
| 39 | /// | 36 | /// |
| 40 | /// The clock speed of the `source` divided by `m` must be between 4 and 16 MHz. | 37 | /// The clock speed of the `source` divided by `m` must be between 4 and 16 MHz. |
| 41 | pub m: Pllm, | 38 | pub prediv: PllPreDiv, |
| 42 | /// The PLL multiplier. | 39 | /// The PLL multiplier. |
| 43 | /// | 40 | /// |
| 44 | /// The multiplied clock – `source` divided by `m` times `n` – must be between 128 and 544 | 41 | /// The multiplied clock – `source` divided by `m` times `n` – must be between 128 and 544 |
| 45 | /// MHz. The upper limit may be lower depending on the `Config { voltage_range }`. | 42 | /// MHz. The upper limit may be lower depending on the `Config { voltage_range }`. |
| 46 | pub n: Plln, | 43 | pub mul: PllMul, |
| 47 | /// The divider for the P output. | 44 | /// The divider for the P output. |
| 48 | /// | 45 | /// |
| 49 | /// The P output is one of several options | 46 | /// The P output is one of several options |
| 50 | /// that can be used to feed the SAI/MDF/ADF Clock mux's. | 47 | /// that can be used to feed the SAI/MDF/ADF Clock mux's. |
| 51 | pub p: Plldiv, | 48 | pub divp: Option<PllDiv>, |
| 52 | /// The divider for the Q output. | 49 | /// The divider for the Q output. |
| 53 | /// | 50 | /// |
| 54 | /// The Q ouput is one of severals options that can be used to feed the 48MHz clocks | 51 | /// The Q ouput is one of severals options that can be used to feed the 48MHz clocks |
| 55 | /// and the OCTOSPI clock. It may also be used on the MDF/ADF clock mux's. | 52 | /// and the OCTOSPI clock. It may also be used on the MDF/ADF clock mux's. |
| 56 | pub q: Plldiv, | 53 | pub divq: Option<PllDiv>, |
| 57 | /// The divider for the R output. | 54 | /// The divider for the R output. |
| 58 | /// | 55 | /// |
| 59 | /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r` | 56 | /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r` |
| 60 | /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default | 57 | /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default |
| 61 | /// `Config { voltage_range }`. | 58 | /// `Config { voltage_range }`. |
| 62 | pub r: Plldiv, | 59 | pub divr: Option<PllDiv>, |
| 63 | } | ||
| 64 | |||
| 65 | impl PllConfig { | ||
| 66 | /// A configuration for HSI / 1 * 10 / 1 = 160 MHz | ||
| 67 | pub const fn hsi_160mhz() -> Self { | ||
| 68 | PllConfig { | ||
| 69 | source: PllSource::HSI, | ||
| 70 | m: Pllm::DIV1, | ||
| 71 | n: Plln::MUL10, | ||
| 72 | p: Plldiv::DIV3, | ||
| 73 | q: Plldiv::DIV2, | ||
| 74 | r: Plldiv::DIV1, | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | /// A configuration for MSIS @ 48 MHz / 3 * 10 / 1 = 160 MHz | ||
| 79 | pub const fn msis_160mhz() -> Self { | ||
| 80 | PllConfig { | ||
| 81 | source: PllSource::MSIS(Msirange::RANGE_48MHZ), | ||
| 82 | m: Pllm::DIV3, | ||
| 83 | n: Plln::MUL10, | ||
| 84 | p: Plldiv::DIV3, | ||
| 85 | q: Plldiv::DIV2, | ||
| 86 | r: Plldiv::DIV1, | ||
| 87 | } | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | #[derive(Clone, Copy)] | ||
| 92 | pub enum PllSource { | ||
| 93 | /// Use an internal medium speed oscillator as the PLL source. | ||
| 94 | MSIS(Msirange), | ||
| 95 | /// Use the external high speed clock as the system PLL source. | ||
| 96 | /// | ||
| 97 | /// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must | ||
| 98 | /// never exceed 50 MHz. | ||
| 99 | HSE(Hertz), | ||
| 100 | /// Use the 16 MHz internal high speed oscillator as the PLL source. | ||
| 101 | HSI, | ||
| 102 | } | 60 | } |
| 103 | 61 | ||
| 104 | impl Into<Pllsrc> for PllSource { | 62 | pub struct Config { |
| 105 | fn into(self) -> Pllsrc { | 63 | // base clock sources |
| 106 | match self { | 64 | pub msi: Option<MSIRange>, |
| 107 | PllSource::MSIS(..) => Pllsrc::MSIS, | 65 | pub hsi: bool, |
| 108 | PllSource::HSE(..) => Pllsrc::HSE, | 66 | pub hse: Option<Hse>, |
| 109 | PllSource::HSI => Pllsrc::HSI, | 67 | pub hsi48: Option<super::Hsi48Config>, |
| 110 | } | ||
| 111 | } | ||
| 112 | } | ||
| 113 | 68 | ||
| 114 | impl Into<Sw> for ClockSrc { | 69 | // pll |
| 115 | fn into(self) -> Sw { | 70 | pub pll1: Option<Pll>, |
| 116 | match self { | 71 | pub pll2: Option<Pll>, |
| 117 | ClockSrc::MSI(..) => Sw::MSIS, | 72 | pub pll3: Option<Pll>, |
| 118 | ClockSrc::HSE(..) => Sw::HSE, | ||
| 119 | ClockSrc::HSI => Sw::HSI, | ||
| 120 | ClockSrc::PLL1_R(..) => Sw::PLL1_R, | ||
| 121 | } | ||
| 122 | } | ||
| 123 | } | ||
| 124 | 73 | ||
| 125 | pub struct Config { | 74 | // sysclk, buses. |
| 126 | pub mux: ClockSrc, | 75 | pub mux: ClockSrc, |
| 127 | pub ahb_pre: AHBPrescaler, | 76 | pub ahb_pre: AHBPrescaler, |
| 128 | pub apb1_pre: APBPrescaler, | 77 | pub apb1_pre: APBPrescaler, |
| 129 | pub apb2_pre: APBPrescaler, | 78 | pub apb2_pre: APBPrescaler, |
| 130 | pub apb3_pre: APBPrescaler, | 79 | pub apb3_pre: APBPrescaler, |
| 131 | pub hsi48: Option<super::Hsi48Config>, | 80 | |
| 132 | /// The voltage range influences the maximum clock frequencies for different parts of the | 81 | /// The voltage range influences the maximum clock frequencies for different parts of the |
| 133 | /// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks | 82 | /// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks |
| 134 | /// exceeding 55 MHz require at least `RANGE2`. | 83 | /// exceeding 55 MHz require at least `RANGE2`. |
| @@ -138,35 +87,35 @@ pub struct Config { | |||
| 138 | pub ls: super::LsConfig, | 87 | pub ls: super::LsConfig, |
| 139 | } | 88 | } |
| 140 | 89 | ||
| 141 | impl Config { | 90 | impl Default for Config { |
| 142 | unsafe fn init_hsi(&self) -> Hertz { | 91 | fn default() -> Self { |
| 143 | RCC.cr().write(|w| w.set_hsion(true)); | 92 | Self { |
| 144 | while !RCC.cr().read().hsirdy() {} | 93 | msi: Some(Msirange::RANGE_4MHZ), |
| 145 | 94 | hse: None, | |
| 146 | HSI_FREQ | 95 | hsi: false, |
| 147 | } | 96 | hsi48: Some(Default::default()), |
| 148 | 97 | pll1: None, | |
| 149 | unsafe fn init_hse(&self, frequency: Hertz) -> Hertz { | 98 | pll2: None, |
| 150 | // Check frequency limits per RM456 § 11.4.10 | 99 | pll3: None, |
| 151 | match self.voltage_range { | 100 | mux: ClockSrc::MSIS, |
| 152 | VoltageScale::RANGE1 | VoltageScale::RANGE2 | VoltageScale::RANGE3 => { | 101 | ahb_pre: AHBPrescaler::DIV1, |
| 153 | assert!(frequency.0 <= 50_000_000); | 102 | apb1_pre: APBPrescaler::DIV1, |
| 154 | } | 103 | apb2_pre: APBPrescaler::DIV1, |
| 155 | VoltageScale::RANGE4 => { | 104 | apb3_pre: APBPrescaler::DIV1, |
| 156 | assert!(frequency.0 <= 25_000_000); | 105 | voltage_range: VoltageScale::RANGE1, |
| 157 | } | 106 | ls: Default::default(), |
| 158 | } | 107 | } |
| 159 | |||
| 160 | // Enable HSE, and wait for it to stabilize | ||
| 161 | RCC.cr().write(|w| w.set_hseon(true)); | ||
| 162 | while !RCC.cr().read().hserdy() {} | ||
| 163 | |||
| 164 | frequency | ||
| 165 | } | 108 | } |
| 109 | } | ||
| 110 | |||
| 111 | pub(crate) unsafe fn init(config: Config) { | ||
| 112 | // Set the requested power mode | ||
| 113 | PWR.vosr().modify(|w| w.set_vos(config.voltage_range)); | ||
| 114 | while !PWR.vosr().read().vosrdy() {} | ||
| 166 | 115 | ||
| 167 | unsafe fn init_msis(&self, range: Msirange) -> Hertz { | 116 | let msi = config.msi.map(|range| { |
| 168 | // Check MSI output per RM0456 § 11.4.10 | 117 | // Check MSI output per RM0456 § 11.4.10 |
| 169 | match self.voltage_range { | 118 | match config.voltage_range { |
| 170 | VoltageScale::RANGE4 => { | 119 | VoltageScale::RANGE4 => { |
| 171 | assert!(msirange_to_hertz(range).0 <= 24_000_000); | 120 | assert!(msirange_to_hertz(range).0 <= 24_000_000); |
| 172 | } | 121 | } |
| @@ -191,223 +140,98 @@ impl Config { | |||
| 191 | }); | 140 | }); |
| 192 | while !RCC.cr().read().msisrdy() {} | 141 | while !RCC.cr().read().msisrdy() {} |
| 193 | msirange_to_hertz(range) | 142 | msirange_to_hertz(range) |
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | impl Default for Config { | ||
| 198 | fn default() -> Self { | ||
| 199 | Self { | ||
| 200 | mux: ClockSrc::default(), | ||
| 201 | ahb_pre: AHBPrescaler::DIV1, | ||
| 202 | apb1_pre: APBPrescaler::DIV1, | ||
| 203 | apb2_pre: APBPrescaler::DIV1, | ||
| 204 | apb3_pre: APBPrescaler::DIV1, | ||
| 205 | hsi48: Some(Default::default()), | ||
| 206 | voltage_range: VoltageScale::RANGE3, | ||
| 207 | ls: Default::default(), | ||
| 208 | } | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | pub(crate) unsafe fn init(config: Config) { | ||
| 213 | // Ensure PWR peripheral clock is enabled | ||
| 214 | RCC.ahb3enr().modify(|w| { | ||
| 215 | w.set_pwren(true); | ||
| 216 | }); | 143 | }); |
| 217 | RCC.ahb3enr().read(); // synchronize | ||
| 218 | 144 | ||
| 219 | // Set the requested power mode | 145 | let hsi = config.hsi.then(|| { |
| 220 | PWR.vosr().modify(|w| { | 146 | RCC.cr().write(|w| w.set_hsion(true)); |
| 221 | w.set_vos(config.voltage_range); | 147 | while !RCC.cr().read().hsirdy() {} |
| 148 | |||
| 149 | HSI_FREQ | ||
| 222 | }); | 150 | }); |
| 223 | while !PWR.vosr().read().vosrdy() {} | ||
| 224 | 151 | ||
| 225 | let sys_clk = match config.mux { | 152 | let hse = config.hse.map(|hse| { |
| 226 | ClockSrc::MSI(range) => config.init_msis(range), | 153 | // Check frequency limits per RM456 § 11.4.10 |
| 227 | ClockSrc::HSE(freq) => config.init_hse(freq), | 154 | match config.voltage_range { |
| 228 | ClockSrc::HSI => config.init_hsi(), | 155 | VoltageScale::RANGE1 | VoltageScale::RANGE2 | VoltageScale::RANGE3 => { |
| 229 | ClockSrc::PLL1_R(pll) => { | 156 | assert!(hse.freq.0 <= 50_000_000); |
| 230 | // Configure the PLL source | ||
| 231 | let source_clk = match pll.source { | ||
| 232 | PllSource::MSIS(range) => config.init_msis(range), | ||
| 233 | PllSource::HSE(hertz) => config.init_hse(hertz), | ||
| 234 | PllSource::HSI => config.init_hsi(), | ||
| 235 | }; | ||
| 236 | |||
| 237 | // Calculate the reference clock, which is the source divided by m | ||
| 238 | let reference_clk = source_clk / pll.m; | ||
| 239 | |||
| 240 | // Check limits per RM0456 § 11.4.6 | ||
| 241 | assert!(Hertz::mhz(4) <= reference_clk && reference_clk <= Hertz::mhz(16)); | ||
| 242 | |||
| 243 | // Calculate the PLL1 VCO clock and PLL1 R output clock | ||
| 244 | let pll1_clk = reference_clk * pll.n; | ||
| 245 | let pll1r_clk = pll1_clk / pll.r; | ||
| 246 | |||
| 247 | // Check system clock per RM0456 § 11.4.9 | ||
| 248 | assert!(pll1r_clk <= Hertz::mhz(160)); | ||
| 249 | |||
| 250 | // Check PLL clocks per RM0456 § 11.4.10 | ||
| 251 | match config.voltage_range { | ||
| 252 | VoltageScale::RANGE1 => { | ||
| 253 | assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544)); | ||
| 254 | assert!(pll1r_clk <= Hertz::mhz(208)); | ||
| 255 | } | ||
| 256 | VoltageScale::RANGE2 => { | ||
| 257 | assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544)); | ||
| 258 | assert!(pll1r_clk <= Hertz::mhz(110)); | ||
| 259 | } | ||
| 260 | VoltageScale::RANGE3 => { | ||
| 261 | assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(330)); | ||
| 262 | assert!(pll1r_clk <= Hertz::mhz(55)); | ||
| 263 | } | ||
| 264 | VoltageScale::RANGE4 => { | ||
| 265 | panic!("PLL is unavailable in voltage range 4"); | ||
| 266 | } | ||
| 267 | } | 157 | } |
| 158 | VoltageScale::RANGE4 => { | ||
| 159 | assert!(hse.freq.0 <= 25_000_000); | ||
| 160 | } | ||
| 161 | } | ||
| 268 | 162 | ||
| 269 | // § 10.5.4: if we're targeting >= 55 MHz, we must configure PLL1MBOOST to a prescaler | 163 | // Enable HSE, and wait for it to stabilize |
| 270 | // value that results in an output between 4 and 16 MHz for the PWR EPOD boost | 164 | RCC.cr().write(|w| { |
| 271 | let mboost = if pll1r_clk >= Hertz::mhz(55) { | 165 | w.set_hseon(true); |
| 272 | // source_clk can be up to 50 MHz, so there's just a few cases: | 166 | w.set_hsebyp(hse.mode != HseMode::Oscillator); |
| 273 | if source_clk > Hertz::mhz(32) { | 167 | w.set_hseext(match hse.mode { |
| 274 | // Divide by 4, giving EPOD 8-12.5 MHz | 168 | HseMode::Oscillator | HseMode::Bypass => Hseext::ANALOG, |
| 275 | Pllmboost::DIV4 | 169 | HseMode::BypassDigital => Hseext::DIGITAL, |
| 276 | } else if source_clk > Hertz::mhz(16) { | ||
| 277 | // Divide by 2, giving EPOD 8-16 MHz | ||
| 278 | Pllmboost::DIV2 | ||
| 279 | } else { | ||
| 280 | // Bypass, giving EPOD 4-16 MHz | ||
| 281 | Pllmboost::DIV1 | ||
| 282 | } | ||
| 283 | } else { | ||
| 284 | // Nothing to do | ||
| 285 | Pllmboost::DIV1 | ||
| 286 | }; | ||
| 287 | |||
| 288 | // Disable the PLL, and wait for it to disable | ||
| 289 | RCC.cr().modify(|w| w.set_pllon(0, false)); | ||
| 290 | while RCC.cr().read().pllrdy(0) {} | ||
| 291 | |||
| 292 | // Configure the PLL | ||
| 293 | RCC.pll1cfgr().write(|w| { | ||
| 294 | // Configure PLL1 source and prescaler | ||
| 295 | w.set_pllsrc(pll.source.into()); | ||
| 296 | w.set_pllm(pll.m); | ||
| 297 | |||
| 298 | // Configure PLL1 input frequncy range | ||
| 299 | let input_range = if reference_clk <= Hertz::mhz(8) { | ||
| 300 | Pllrge::FREQ_4TO8MHZ | ||
| 301 | } else { | ||
| 302 | Pllrge::FREQ_8TO16MHZ | ||
| 303 | }; | ||
| 304 | w.set_pllrge(input_range); | ||
| 305 | |||
| 306 | // Set the prescaler for PWR EPOD | ||
| 307 | w.set_pllmboost(mboost); | ||
| 308 | |||
| 309 | // Enable PLL1_R output | ||
| 310 | w.set_pllren(true); | ||
| 311 | }); | 170 | }); |
| 171 | }); | ||
| 172 | while !RCC.cr().read().hserdy() {} | ||
| 312 | 173 | ||
| 313 | // Configure the PLL divisors | 174 | hse.freq |
| 314 | RCC.pll1divr().modify(|w| { | 175 | }); |
| 315 | // Set the VCO multiplier | ||
| 316 | w.set_plln(pll.n); | ||
| 317 | w.set_pllp(pll.p); | ||
| 318 | w.set_pllq(pll.q); | ||
| 319 | // Set the R output divisor | ||
| 320 | w.set_pllr(pll.r); | ||
| 321 | }); | ||
| 322 | 176 | ||
| 323 | // Do we need the EPOD booster to reach the target clock speed per § 10.5.4? | 177 | let hsi48 = config.hsi48.map(super::init_hsi48); |
| 324 | if pll1r_clk >= Hertz::mhz(55) { | ||
| 325 | // Enable the booster | ||
| 326 | PWR.vosr().modify(|w| { | ||
| 327 | w.set_boosten(true); | ||
| 328 | }); | ||
| 329 | while !PWR.vosr().read().boostrdy() {} | ||
| 330 | } | ||
| 331 | 178 | ||
| 332 | // Enable the PLL | 179 | let pll_input = PllInput { hse, hsi, msi }; |
| 333 | RCC.cr().modify(|w| w.set_pllon(0, true)); | 180 | let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range); |
| 334 | while !RCC.cr().read().pllrdy(0) {} | 181 | let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range); |
| 182 | let pll3 = init_pll(PllInstance::Pll3, config.pll3, &pll_input, config.voltage_range); | ||
| 335 | 183 | ||
| 336 | pll1r_clk | 184 | let sys_clk = match config.mux { |
| 337 | } | 185 | ClockSrc::HSE => hse.unwrap(), |
| 186 | ClockSrc::HSI => hsi.unwrap(), | ||
| 187 | ClockSrc::MSIS => msi.unwrap(), | ||
| 188 | ClockSrc::PLL1_R => pll1.r.unwrap(), | ||
| 338 | }; | 189 | }; |
| 339 | 190 | ||
| 340 | let hsi48 = config.hsi48.map(super::init_hsi48); | 191 | // Do we need the EPOD booster to reach the target clock speed per § 10.5.4? |
| 192 | if sys_clk >= Hertz::mhz(55) { | ||
| 193 | // Enable the booster | ||
| 194 | PWR.vosr().modify(|w| w.set_boosten(true)); | ||
| 195 | while !PWR.vosr().read().boostrdy() {} | ||
| 196 | } | ||
| 341 | 197 | ||
| 342 | // The clock source is ready | 198 | // The clock source is ready |
| 343 | // Calculate and set the flash wait states | 199 | // Calculate and set the flash wait states |
| 344 | let wait_states = match config.voltage_range { | 200 | let wait_states = match config.voltage_range { |
| 345 | // VOS 1 range VCORE 1.26V - 1.40V | 201 | // VOS 1 range VCORE 1.26V - 1.40V |
| 346 | VoltageScale::RANGE1 => { | 202 | VoltageScale::RANGE1 => match sys_clk.0 { |
| 347 | if sys_clk.0 < 32_000_000 { | 203 | ..=32_000_000 => 0, |
| 348 | 0 | 204 | ..=64_000_000 => 1, |
| 349 | } else if sys_clk.0 < 64_000_000 { | 205 | ..=96_000_000 => 2, |
| 350 | 1 | 206 | ..=128_000_000 => 3, |
| 351 | } else if sys_clk.0 < 96_000_000 { | 207 | _ => 4, |
| 352 | 2 | 208 | }, |
| 353 | } else if sys_clk.0 < 128_000_000 { | ||
| 354 | 3 | ||
| 355 | } else { | ||
| 356 | 4 | ||
| 357 | } | ||
| 358 | } | ||
| 359 | // VOS 2 range VCORE 1.15V - 1.26V | 209 | // VOS 2 range VCORE 1.15V - 1.26V |
| 360 | VoltageScale::RANGE2 => { | 210 | VoltageScale::RANGE2 => match sys_clk.0 { |
| 361 | if sys_clk.0 < 30_000_000 { | 211 | ..=30_000_000 => 0, |
| 362 | 0 | 212 | ..=60_000_000 => 1, |
| 363 | } else if sys_clk.0 < 60_000_000 { | 213 | ..=90_000_000 => 2, |
| 364 | 1 | 214 | _ => 3, |
| 365 | } else if sys_clk.0 < 90_000_000 { | 215 | }, |
| 366 | 2 | ||
| 367 | } else { | ||
| 368 | 3 | ||
| 369 | } | ||
| 370 | } | ||
| 371 | // VOS 3 range VCORE 1.05V - 1.15V | 216 | // VOS 3 range VCORE 1.05V - 1.15V |
| 372 | VoltageScale::RANGE3 => { | 217 | VoltageScale::RANGE3 => match sys_clk.0 { |
| 373 | if sys_clk.0 < 24_000_000 { | 218 | ..=24_000_000 => 0, |
| 374 | 0 | 219 | ..=48_000_000 => 1, |
| 375 | } else if sys_clk.0 < 48_000_000 { | 220 | _ => 2, |
| 376 | 1 | 221 | }, |
| 377 | } else { | ||
| 378 | 2 | ||
| 379 | } | ||
| 380 | } | ||
| 381 | // VOS 4 range VCORE 0.95V - 1.05V | 222 | // VOS 4 range VCORE 0.95V - 1.05V |
| 382 | VoltageScale::RANGE4 => { | 223 | VoltageScale::RANGE4 => match sys_clk.0 { |
| 383 | if sys_clk.0 < 12_000_000 { | 224 | ..=12_000_000 => 0, |
| 384 | 0 | 225 | _ => 1, |
| 385 | } else { | 226 | }, |
| 386 | 1 | ||
| 387 | } | ||
| 388 | } | ||
| 389 | }; | 227 | }; |
| 390 | FLASH.acr().modify(|w| { | 228 | FLASH.acr().modify(|w| { |
| 391 | w.set_latency(wait_states); | 229 | w.set_latency(wait_states); |
| 392 | }); | 230 | }); |
| 393 | 231 | ||
| 394 | // Switch the system clock source | 232 | // Switch the system clock source |
| 395 | RCC.cfgr1().modify(|w| { | 233 | RCC.cfgr1().modify(|w| w.set_sw(config.mux)); |
| 396 | w.set_sw(config.mux.into()); | 234 | while RCC.cfgr1().read().sws() != config.mux {} |
| 397 | }); | ||
| 398 | |||
| 399 | // RM0456 § 11.4.9 specifies maximum bus frequencies per voltage range, but the maximum bus | ||
| 400 | // frequency for each voltage range exactly matches the maximum permitted PLL output frequency. | ||
| 401 | // Given that: | ||
| 402 | // | ||
| 403 | // 1. Any bus frequency can never exceed the system clock frequency; | ||
| 404 | // 2. We checked the PLL output frequency if we're using it as a system clock; | ||
| 405 | // 3. The maximum HSE frequencies at each voltage range are lower than the bus limits, and | ||
| 406 | // we checked the HSE frequency if configured as a system clock; and | ||
| 407 | // 4. The maximum frequencies from the other clock sources are lower than the lowest bus | ||
| 408 | // frequency limit | ||
| 409 | // | ||
| 410 | // ...then we do not need to perform additional bus-related frequency checks. | ||
| 411 | 235 | ||
| 412 | // Configure the bus prescalers | 236 | // Configure the bus prescalers |
| 413 | RCC.cfgr2().modify(|w| { | 237 | RCC.cfgr2().modify(|w| { |
| @@ -419,64 +243,52 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 419 | w.set_ppre3(config.apb3_pre); | 243 | w.set_ppre3(config.apb3_pre); |
| 420 | }); | 244 | }); |
| 421 | 245 | ||
| 422 | let ahb_freq = sys_clk / config.ahb_pre; | 246 | let hclk = sys_clk / config.ahb_pre; |
| 423 | |||
| 424 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | ||
| 425 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | ||
| 426 | pre => { | ||
| 427 | let freq = ahb_freq / pre; | ||
| 428 | (freq, freq * 2u32) | ||
| 429 | } | ||
| 430 | }; | ||
| 431 | 247 | ||
| 432 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | 248 | let hclk_max = match config.voltage_range { |
| 433 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | 249 | VoltageScale::RANGE1 => Hertz::mhz(160), |
| 434 | pre => { | 250 | VoltageScale::RANGE2 => Hertz::mhz(110), |
| 435 | let freq = ahb_freq / pre; | 251 | VoltageScale::RANGE3 => Hertz::mhz(55), |
| 436 | (freq, freq * 2u32) | 252 | VoltageScale::RANGE4 => Hertz::mhz(25), |
| 437 | } | ||
| 438 | }; | 253 | }; |
| 254 | assert!(hclk <= hclk_max); | ||
| 439 | 255 | ||
| 440 | let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre { | 256 | let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); |
| 441 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | 257 | let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); |
| 442 | pre => { | 258 | let (pclk3, _) = super::util::calc_pclk(hclk, config.apb3_pre); |
| 443 | let freq = ahb_freq / pre; | ||
| 444 | (freq, freq * 2u32) | ||
| 445 | } | ||
| 446 | }; | ||
| 447 | 259 | ||
| 448 | let rtc = config.ls.init(); | 260 | let rtc = config.ls.init(); |
| 449 | 261 | ||
| 450 | set_clocks!( | 262 | set_clocks!( |
| 451 | sys: Some(sys_clk), | 263 | sys: Some(sys_clk), |
| 452 | hclk1: Some(ahb_freq), | 264 | hclk1: Some(hclk), |
| 453 | hclk2: Some(ahb_freq), | 265 | hclk2: Some(hclk), |
| 454 | hclk3: Some(ahb_freq), | 266 | hclk3: Some(hclk), |
| 455 | pclk1: Some(apb1_freq), | 267 | pclk1: Some(pclk1), |
| 456 | pclk2: Some(apb2_freq), | 268 | pclk2: Some(pclk2), |
| 457 | pclk3: Some(apb3_freq), | 269 | pclk3: Some(pclk3), |
| 458 | pclk1_tim: Some(apb1_tim_freq), | 270 | pclk1_tim: Some(pclk1_tim), |
| 459 | pclk2_tim: Some(apb2_tim_freq), | 271 | pclk2_tim: Some(pclk2_tim), |
| 460 | hsi48: hsi48, | 272 | hsi48: hsi48, |
| 461 | rtc: rtc, | 273 | rtc: rtc, |
| 274 | hse: hse, | ||
| 275 | hsi: hsi, | ||
| 276 | pll1_p: pll1.p, | ||
| 277 | pll1_q: pll1.q, | ||
| 278 | pll1_r: pll1.r, | ||
| 279 | pll2_p: pll2.p, | ||
| 280 | pll2_q: pll2.q, | ||
| 281 | pll2_r: pll2.r, | ||
| 282 | pll3_p: pll3.p, | ||
| 283 | pll3_q: pll3.q, | ||
| 284 | pll3_r: pll3.r, | ||
| 462 | 285 | ||
| 463 | // TODO | 286 | // TODO |
| 464 | hse: None, | ||
| 465 | hsi: None, | ||
| 466 | audioclk: None, | 287 | audioclk: None, |
| 467 | hsi48_div_2: None, | 288 | hsi48_div_2: None, |
| 468 | lse: None, | 289 | lse: None, |
| 469 | lsi: None, | 290 | lsi: None, |
| 470 | msik: None, | 291 | msik: None, |
| 471 | pll1_p: None, | ||
| 472 | pll1_q: None, | ||
| 473 | pll1_r: None, | ||
| 474 | pll2_p: None, | ||
| 475 | pll2_q: None, | ||
| 476 | pll2_r: None, | ||
| 477 | pll3_p: None, | ||
| 478 | pll3_q: None, | ||
| 479 | pll3_r: None, | ||
| 480 | iclk: None, | 292 | iclk: None, |
| 481 | ); | 293 | ); |
| 482 | } | 294 | } |
| @@ -501,3 +313,126 @@ fn msirange_to_hertz(range: Msirange) -> Hertz { | |||
| 501 | Msirange::RANGE_100KHZ => Hertz(100_000), | 313 | Msirange::RANGE_100KHZ => Hertz(100_000), |
| 502 | } | 314 | } |
| 503 | } | 315 | } |
| 316 | |||
| 317 | pub(super) struct PllInput { | ||
| 318 | pub hsi: Option<Hertz>, | ||
| 319 | pub hse: Option<Hertz>, | ||
| 320 | pub msi: Option<Hertz>, | ||
| 321 | } | ||
| 322 | |||
| 323 | #[allow(unused)] | ||
| 324 | #[derive(Default)] | ||
| 325 | pub(super) struct PllOutput { | ||
| 326 | pub p: Option<Hertz>, | ||
| 327 | pub q: Option<Hertz>, | ||
| 328 | pub r: Option<Hertz>, | ||
| 329 | } | ||
| 330 | |||
| 331 | #[derive(PartialEq, Eq, Clone, Copy)] | ||
| 332 | enum PllInstance { | ||
| 333 | Pll1 = 0, | ||
| 334 | Pll2 = 1, | ||
| 335 | Pll3 = 2, | ||
| 336 | } | ||
| 337 | |||
| 338 | fn pll_enable(instance: PllInstance, enabled: bool) { | ||
| 339 | RCC.cr().modify(|w| w.set_pllon(instance as _, enabled)); | ||
| 340 | while RCC.cr().read().pllrdy(instance as _) != enabled {} | ||
| 341 | } | ||
| 342 | |||
| 343 | fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput, voltage_range: VoltageScale) -> PllOutput { | ||
| 344 | // Disable PLL | ||
| 345 | pll_enable(instance, false); | ||
| 346 | |||
| 347 | let Some(pll) = config else { return PllOutput::default() }; | ||
| 348 | |||
| 349 | let src_freq = match pll.source { | ||
| 350 | PllSource::DISABLE => panic!("must not select PLL source as DISABLE"), | ||
| 351 | PllSource::HSE => unwrap!(input.hse), | ||
| 352 | PllSource::HSI => unwrap!(input.hsi), | ||
| 353 | PllSource::MSIS => unwrap!(input.msi), | ||
| 354 | }; | ||
| 355 | |||
| 356 | // Calculate the reference clock, which is the source divided by m | ||
| 357 | let ref_freq = src_freq / pll.prediv; | ||
| 358 | // Check limits per RM0456 § 11.4.6 | ||
| 359 | assert!(Hertz::mhz(4) <= ref_freq && ref_freq <= Hertz::mhz(16)); | ||
| 360 | |||
| 361 | // Check PLL clocks per RM0456 § 11.4.10 | ||
| 362 | let (vco_min, vco_max, out_max) = match voltage_range { | ||
| 363 | VoltageScale::RANGE1 => (Hertz::mhz(128), Hertz::mhz(544), Hertz::mhz(208)), | ||
| 364 | VoltageScale::RANGE2 => (Hertz::mhz(128), Hertz::mhz(544), Hertz::mhz(110)), | ||
| 365 | VoltageScale::RANGE3 => (Hertz::mhz(128), Hertz::mhz(330), Hertz::mhz(55)), | ||
| 366 | VoltageScale::RANGE4 => panic!("PLL is unavailable in voltage range 4"), | ||
| 367 | }; | ||
| 368 | |||
| 369 | // Calculate the PLL VCO clock | ||
| 370 | let vco_freq = ref_freq * pll.mul; | ||
| 371 | assert!(vco_freq >= vco_min && vco_freq <= vco_max); | ||
| 372 | |||
| 373 | // Calculate output clocks. | ||
| 374 | let p = pll.divp.map(|div| vco_freq / div); | ||
| 375 | let q = pll.divq.map(|div| vco_freq / div); | ||
| 376 | let r = pll.divr.map(|div| vco_freq / div); | ||
| 377 | for freq in [p, q, r] { | ||
| 378 | if let Some(freq) = freq { | ||
| 379 | assert!(freq <= out_max); | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | let divr = match instance { | ||
| 384 | PllInstance::Pll1 => RCC.pll1divr(), | ||
| 385 | PllInstance::Pll2 => RCC.pll2divr(), | ||
| 386 | PllInstance::Pll3 => RCC.pll3divr(), | ||
| 387 | }; | ||
| 388 | divr.write(|w| { | ||
| 389 | w.set_plln(pll.mul); | ||
| 390 | w.set_pllp(pll.divp.unwrap_or(PllDiv::DIV1)); | ||
| 391 | w.set_pllq(pll.divq.unwrap_or(PllDiv::DIV1)); | ||
| 392 | w.set_pllr(pll.divr.unwrap_or(PllDiv::DIV1)); | ||
| 393 | }); | ||
| 394 | |||
| 395 | let input_range = match ref_freq.0 { | ||
| 396 | ..=8_000_000 => Pllrge::FREQ_4TO8MHZ, | ||
| 397 | _ => Pllrge::FREQ_8TO16MHZ, | ||
| 398 | }; | ||
| 399 | |||
| 400 | macro_rules! write_fields { | ||
| 401 | ($w:ident) => { | ||
| 402 | $w.set_pllpen(pll.divp.is_some()); | ||
| 403 | $w.set_pllqen(pll.divq.is_some()); | ||
| 404 | $w.set_pllren(pll.divr.is_some()); | ||
| 405 | $w.set_pllm(pll.prediv); | ||
| 406 | $w.set_pllsrc(pll.source); | ||
| 407 | $w.set_pllrge(input_range); | ||
| 408 | }; | ||
| 409 | } | ||
| 410 | |||
| 411 | match instance { | ||
| 412 | PllInstance::Pll1 => RCC.pll1cfgr().write(|w| { | ||
| 413 | // § 10.5.4: if we're targeting >= 55 MHz, we must configure PLL1MBOOST to a prescaler | ||
| 414 | // value that results in an output between 4 and 16 MHz for the PWR EPOD boost | ||
| 415 | if r.unwrap() >= Hertz::mhz(55) { | ||
| 416 | // source_clk can be up to 50 MHz, so there's just a few cases: | ||
| 417 | let mboost = match src_freq.0 { | ||
| 418 | ..=16_000_000 => Pllmboost::DIV1, // Bypass, giving EPOD 4-16 MHz | ||
| 419 | ..=32_000_000 => Pllmboost::DIV2, // Divide by 2, giving EPOD 8-16 MHz | ||
| 420 | _ => Pllmboost::DIV4, // Divide by 4, giving EPOD 8-12.5 MHz | ||
| 421 | }; | ||
| 422 | w.set_pllmboost(mboost); | ||
| 423 | } | ||
| 424 | write_fields!(w); | ||
| 425 | }), | ||
| 426 | PllInstance::Pll2 => RCC.pll2cfgr().write(|w| { | ||
| 427 | write_fields!(w); | ||
| 428 | }), | ||
| 429 | PllInstance::Pll3 => RCC.pll3cfgr().write(|w| { | ||
| 430 | write_fields!(w); | ||
| 431 | }), | ||
| 432 | } | ||
| 433 | |||
| 434 | // Enable PLL | ||
| 435 | pll_enable(instance, true); | ||
| 436 | |||
| 437 | PllOutput { p, q, r } | ||
| 438 | } | ||
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 9480d6972..9397da2a1 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs | |||
| @@ -65,17 +65,17 @@ pub(crate) mod sealed { | |||
| 65 | fn regs_core() -> crate::pac::timer::TimCore; | 65 | fn regs_core() -> crate::pac::timer::TimCore; |
| 66 | 66 | ||
| 67 | /// Start the timer. | 67 | /// Start the timer. |
| 68 | fn start(&mut self) { | 68 | fn start(&self) { |
| 69 | Self::regs_core().cr1().modify(|r| r.set_cen(true)); | 69 | Self::regs_core().cr1().modify(|r| r.set_cen(true)); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | /// Stop the timer. | 72 | /// Stop the timer. |
| 73 | fn stop(&mut self) { | 73 | fn stop(&self) { |
| 74 | Self::regs_core().cr1().modify(|r| r.set_cen(false)); | 74 | Self::regs_core().cr1().modify(|r| r.set_cen(false)); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | /// Reset the counter value to 0 | 77 | /// Reset the counter value to 0 |
| 78 | fn reset(&mut self) { | 78 | fn reset(&self) { |
| 79 | Self::regs_core().cnt().write(|r| r.set_cnt(0)); | 79 | Self::regs_core().cnt().write(|r| r.set_cnt(0)); |
| 80 | } | 80 | } |
| 81 | 81 | ||
| @@ -85,7 +85,7 @@ pub(crate) mod sealed { | |||
| 85 | /// the timer counter will wrap around at the same frequency as is being set. | 85 | /// the timer counter will wrap around at the same frequency as is being set. |
| 86 | /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved | 86 | /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved |
| 87 | /// because it needs to count up and down. | 87 | /// because it needs to count up and down. |
| 88 | fn set_frequency(&mut self, frequency: Hertz) { | 88 | fn set_frequency(&self, frequency: Hertz) { |
| 89 | let f = frequency.0; | 89 | let f = frequency.0; |
| 90 | let timer_f = Self::frequency().0; | 90 | let timer_f = Self::frequency().0; |
| 91 | assert!(f > 0); | 91 | assert!(f > 0); |
| @@ -108,7 +108,7 @@ pub(crate) mod sealed { | |||
| 108 | /// Clear update interrupt. | 108 | /// Clear update interrupt. |
| 109 | /// | 109 | /// |
| 110 | /// Returns whether the update interrupt flag was set. | 110 | /// Returns whether the update interrupt flag was set. |
| 111 | fn clear_update_interrupt(&mut self) -> bool { | 111 | fn clear_update_interrupt(&self) -> bool { |
| 112 | let regs = Self::regs_core(); | 112 | let regs = Self::regs_core(); |
| 113 | let sr = regs.sr().read(); | 113 | let sr = regs.sr().read(); |
| 114 | if sr.uif() { | 114 | if sr.uif() { |
| @@ -122,12 +122,12 @@ pub(crate) mod sealed { | |||
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | /// Enable/disable the update interrupt. | 124 | /// Enable/disable the update interrupt. |
| 125 | fn enable_update_interrupt(&mut self, enable: bool) { | 125 | fn enable_update_interrupt(&self, enable: bool) { |
| 126 | Self::regs_core().dier().modify(|r| r.set_uie(enable)); | 126 | Self::regs_core().dier().modify(|r| r.set_uie(enable)); |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | /// Enable/disable autoreload preload. | 129 | /// Enable/disable autoreload preload. |
| 130 | fn set_autoreload_preload(&mut self, enable: bool) { | 130 | fn set_autoreload_preload(&self, enable: bool) { |
| 131 | Self::regs_core().cr1().modify(|r| r.set_arpe(enable)); | 131 | Self::regs_core().cr1().modify(|r| r.set_arpe(enable)); |
| 132 | } | 132 | } |
| 133 | 133 | ||
| @@ -154,7 +154,7 @@ pub(crate) mod sealed { | |||
| 154 | fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2; | 154 | fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2; |
| 155 | 155 | ||
| 156 | /// Enable/disable the update dma. | 156 | /// Enable/disable the update dma. |
| 157 | fn enable_update_dma(&mut self, enable: bool) { | 157 | fn enable_update_dma(&self, enable: bool) { |
| 158 | Self::regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable)); | 158 | Self::regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable)); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| @@ -186,7 +186,7 @@ pub(crate) mod sealed { | |||
| 186 | fn regs_1ch() -> crate::pac::timer::Tim1ch; | 186 | fn regs_1ch() -> crate::pac::timer::Tim1ch; |
| 187 | 187 | ||
| 188 | /// Set clock divider. | 188 | /// Set clock divider. |
| 189 | fn set_clock_division(&mut self, ckd: vals::Ckd) { | 189 | fn set_clock_division(&self, ckd: vals::Ckd) { |
| 190 | Self::regs_1ch().cr1().modify(|r| r.set_ckd(ckd)); | 190 | Self::regs_1ch().cr1().modify(|r| r.set_ckd(ckd)); |
| 191 | } | 191 | } |
| 192 | 192 | ||
| @@ -218,7 +218,7 @@ pub(crate) mod sealed { | |||
| 218 | fn regs_gp16() -> crate::pac::timer::TimGp16; | 218 | fn regs_gp16() -> crate::pac::timer::TimGp16; |
| 219 | 219 | ||
| 220 | /// Set counting mode. | 220 | /// Set counting mode. |
| 221 | fn set_counting_mode(&mut self, mode: CountingMode) { | 221 | fn set_counting_mode(&self, mode: CountingMode) { |
| 222 | let (cms, dir) = mode.into(); | 222 | let (cms, dir) = mode.into(); |
| 223 | 223 | ||
| 224 | let timer_enabled = Self::regs_core().cr1().read().cen(); | 224 | let timer_enabled = Self::regs_core().cr1().read().cen(); |
| @@ -237,7 +237,7 @@ pub(crate) mod sealed { | |||
| 237 | } | 237 | } |
| 238 | 238 | ||
| 239 | /// Set input capture filter. | 239 | /// Set input capture filter. |
| 240 | fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::FilterValue) { | 240 | fn set_input_capture_filter(&self, channel: Channel, icf: vals::FilterValue) { |
| 241 | let raw_channel = channel.index(); | 241 | let raw_channel = channel.index(); |
| 242 | Self::regs_gp16() | 242 | Self::regs_gp16() |
| 243 | .ccmr_input(raw_channel / 2) | 243 | .ccmr_input(raw_channel / 2) |
| @@ -245,17 +245,17 @@ pub(crate) mod sealed { | |||
| 245 | } | 245 | } |
| 246 | 246 | ||
| 247 | /// Clear input interrupt. | 247 | /// Clear input interrupt. |
| 248 | fn clear_input_interrupt(&mut self, channel: Channel) { | 248 | fn clear_input_interrupt(&self, channel: Channel) { |
| 249 | Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); | 249 | Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | /// Enable input interrupt. | 252 | /// Enable input interrupt. |
| 253 | fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { | 253 | fn enable_input_interrupt(&self, channel: Channel, enable: bool) { |
| 254 | Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); | 254 | Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | /// Set input capture prescaler. | 257 | /// Set input capture prescaler. |
| 258 | fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { | 258 | fn set_input_capture_prescaler(&self, channel: Channel, factor: u8) { |
| 259 | let raw_channel = channel.index(); | 259 | let raw_channel = channel.index(); |
| 260 | Self::regs_gp16() | 260 | Self::regs_gp16() |
| 261 | .ccmr_input(raw_channel / 2) | 261 | .ccmr_input(raw_channel / 2) |
| @@ -263,7 +263,7 @@ pub(crate) mod sealed { | |||
| 263 | } | 263 | } |
| 264 | 264 | ||
| 265 | /// Set input TI selection. | 265 | /// Set input TI selection. |
| 266 | fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { | 266 | fn set_input_ti_selection(&self, channel: Channel, tisel: InputTISelection) { |
| 267 | let raw_channel = channel.index(); | 267 | let raw_channel = channel.index(); |
| 268 | Self::regs_gp16() | 268 | Self::regs_gp16() |
| 269 | .ccmr_input(raw_channel / 2) | 269 | .ccmr_input(raw_channel / 2) |
| @@ -271,7 +271,7 @@ pub(crate) mod sealed { | |||
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | /// Set input capture mode. | 273 | /// Set input capture mode. |
| 274 | fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { | 274 | fn set_input_capture_mode(&self, channel: Channel, mode: InputCaptureMode) { |
| 275 | Self::regs_gp16().ccer().modify(|r| match mode { | 275 | Self::regs_gp16().ccer().modify(|r| match mode { |
| 276 | InputCaptureMode::Rising => { | 276 | InputCaptureMode::Rising => { |
| 277 | r.set_ccnp(channel.index(), false); | 277 | r.set_ccnp(channel.index(), false); |
| @@ -289,7 +289,7 @@ pub(crate) mod sealed { | |||
| 289 | } | 289 | } |
| 290 | 290 | ||
| 291 | /// Set output compare mode. | 291 | /// Set output compare mode. |
| 292 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { | 292 | fn set_output_compare_mode(&self, channel: Channel, mode: OutputCompareMode) { |
| 293 | let raw_channel: usize = channel.index(); | 293 | let raw_channel: usize = channel.index(); |
| 294 | Self::regs_gp16() | 294 | Self::regs_gp16() |
| 295 | .ccmr_output(raw_channel / 2) | 295 | .ccmr_output(raw_channel / 2) |
| @@ -297,14 +297,14 @@ pub(crate) mod sealed { | |||
| 297 | } | 297 | } |
| 298 | 298 | ||
| 299 | /// Set output polarity. | 299 | /// Set output polarity. |
| 300 | fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | 300 | fn set_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { |
| 301 | Self::regs_gp16() | 301 | Self::regs_gp16() |
| 302 | .ccer() | 302 | .ccer() |
| 303 | .modify(|w| w.set_ccp(channel.index(), polarity.into())); | 303 | .modify(|w| w.set_ccp(channel.index(), polarity.into())); |
| 304 | } | 304 | } |
| 305 | 305 | ||
| 306 | /// Enable/disable a channel. | 306 | /// Enable/disable a channel. |
| 307 | fn enable_channel(&mut self, channel: Channel, enable: bool) { | 307 | fn enable_channel(&self, channel: Channel, enable: bool) { |
| 308 | Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); | 308 | Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); |
| 309 | } | 309 | } |
| 310 | 310 | ||
| @@ -314,12 +314,12 @@ pub(crate) mod sealed { | |||
| 314 | } | 314 | } |
| 315 | 315 | ||
| 316 | /// Set compare value for a channel. | 316 | /// Set compare value for a channel. |
| 317 | fn set_compare_value(&mut self, channel: Channel, value: u16) { | 317 | fn set_compare_value(&self, channel: Channel, value: u16) { |
| 318 | Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); | 318 | Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); |
| 319 | } | 319 | } |
| 320 | 320 | ||
| 321 | /// Get capture value for a channel. | 321 | /// Get capture value for a channel. |
| 322 | fn get_capture_value(&mut self, channel: Channel) -> u16 { | 322 | fn get_capture_value(&self, channel: Channel) -> u16 { |
| 323 | Self::regs_gp16().ccr(channel.index()).read().ccr() | 323 | Self::regs_gp16().ccr(channel.index()).read().ccr() |
| 324 | } | 324 | } |
| 325 | 325 | ||
| @@ -329,7 +329,7 @@ pub(crate) mod sealed { | |||
| 329 | } | 329 | } |
| 330 | 330 | ||
| 331 | /// Set output compare preload. | 331 | /// Set output compare preload. |
| 332 | fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { | 332 | fn set_output_compare_preload(&self, channel: Channel, preload: bool) { |
| 333 | let channel_index = channel.index(); | 333 | let channel_index = channel.index(); |
| 334 | Self::regs_gp16() | 334 | Self::regs_gp16() |
| 335 | .ccmr_output(channel_index / 2) | 335 | .ccmr_output(channel_index / 2) |
| @@ -342,7 +342,7 @@ pub(crate) mod sealed { | |||
| 342 | } | 342 | } |
| 343 | 343 | ||
| 344 | /// Set capture compare DMA selection | 344 | /// Set capture compare DMA selection |
| 345 | fn set_cc_dma_selection(&mut self, ccds: super::vals::Ccds) { | 345 | fn set_cc_dma_selection(&self, ccds: super::vals::Ccds) { |
| 346 | Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds)) | 346 | Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds)) |
| 347 | } | 347 | } |
| 348 | 348 | ||
| @@ -352,7 +352,7 @@ pub(crate) mod sealed { | |||
| 352 | } | 352 | } |
| 353 | 353 | ||
| 354 | /// Set capture compare DMA enable state | 354 | /// Set capture compare DMA enable state |
| 355 | fn set_cc_dma_enable_state(&mut self, channel: Channel, ccde: bool) { | 355 | fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) { |
| 356 | Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) | 356 | Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) |
| 357 | } | 357 | } |
| 358 | } | 358 | } |
| @@ -369,7 +369,7 @@ pub(crate) mod sealed { | |||
| 369 | fn regs_gp32() -> crate::pac::timer::TimGp32; | 369 | fn regs_gp32() -> crate::pac::timer::TimGp32; |
| 370 | 370 | ||
| 371 | /// Set timer frequency. | 371 | /// Set timer frequency. |
| 372 | fn set_frequency(&mut self, frequency: Hertz) { | 372 | fn set_frequency(&self, frequency: Hertz) { |
| 373 | let f = frequency.0; | 373 | let f = frequency.0; |
| 374 | assert!(f > 0); | 374 | assert!(f > 0); |
| 375 | let timer_f = Self::frequency().0; | 375 | let timer_f = Self::frequency().0; |
| @@ -398,12 +398,12 @@ pub(crate) mod sealed { | |||
| 398 | } | 398 | } |
| 399 | 399 | ||
| 400 | /// Set comapre value for a channel. | 400 | /// Set comapre value for a channel. |
| 401 | fn set_compare_value(&mut self, channel: Channel, value: u32) { | 401 | fn set_compare_value(&self, channel: Channel, value: u32) { |
| 402 | Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value)); | 402 | Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value)); |
| 403 | } | 403 | } |
| 404 | 404 | ||
| 405 | /// Get capture value for a channel. | 405 | /// Get capture value for a channel. |
| 406 | fn get_capture_value(&mut self, channel: Channel) -> u32 { | 406 | fn get_capture_value(&self, channel: Channel) -> u32 { |
| 407 | Self::regs_gp32().ccr(channel.index()).read().ccr() | 407 | Self::regs_gp32().ccr(channel.index()).read().ccr() |
| 408 | } | 408 | } |
| 409 | 409 | ||
| @@ -430,17 +430,17 @@ pub(crate) mod sealed { | |||
| 430 | fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp; | 430 | fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp; |
| 431 | 431 | ||
| 432 | /// Set clock divider for the dead time. | 432 | /// Set clock divider for the dead time. |
| 433 | fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { | 433 | fn set_dead_time_clock_division(&self, value: vals::Ckd) { |
| 434 | Self::regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value)); | 434 | Self::regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value)); |
| 435 | } | 435 | } |
| 436 | 436 | ||
| 437 | /// Set dead time, as a fraction of the max duty value. | 437 | /// Set dead time, as a fraction of the max duty value. |
| 438 | fn set_dead_time_value(&mut self, value: u8) { | 438 | fn set_dead_time_value(&self, value: u8) { |
| 439 | Self::regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value)); | 439 | Self::regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value)); |
| 440 | } | 440 | } |
| 441 | 441 | ||
| 442 | /// Enable timer outputs. | 442 | /// Enable timer outputs. |
| 443 | fn enable_outputs(&mut self) { | 443 | fn enable_outputs(&self) { |
| 444 | Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true)); | 444 | Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true)); |
| 445 | } | 445 | } |
| 446 | } | 446 | } |
| @@ -468,14 +468,14 @@ pub(crate) mod sealed { | |||
| 468 | fn regs_advanced() -> crate::pac::timer::TimAdv; | 468 | fn regs_advanced() -> crate::pac::timer::TimAdv; |
| 469 | 469 | ||
| 470 | /// Set complementary output polarity. | 470 | /// Set complementary output polarity. |
| 471 | fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | 471 | fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) { |
| 472 | Self::regs_advanced() | 472 | Self::regs_advanced() |
| 473 | .ccer() | 473 | .ccer() |
| 474 | .modify(|w| w.set_ccnp(channel.index(), polarity.into())); | 474 | .modify(|w| w.set_ccnp(channel.index(), polarity.into())); |
| 475 | } | 475 | } |
| 476 | 476 | ||
| 477 | /// Enable/disable a complementary channel. | 477 | /// Enable/disable a complementary channel. |
| 478 | fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { | 478 | fn enable_complementary_channel(&self, channel: Channel, enable: bool) { |
| 479 | Self::regs_advanced() | 479 | Self::regs_advanced() |
| 480 | .ccer() | 480 | .ccer() |
| 481 | .modify(|w| w.set_ccne(channel.index(), enable)); | 481 | .modify(|w| w.set_ccne(channel.index(), enable)); |
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 34d6b52fd..be321a19b 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs | |||
| @@ -264,7 +264,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 264 | 264 | ||
| 265 | let regs = T::regs(); | 265 | let regs = T::regs(); |
| 266 | 266 | ||
| 267 | #[cfg(any(stm32l5, stm32wb))] | 267 | #[cfg(any(stm32l4, stm32l5, stm32wb))] |
| 268 | crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); | 268 | crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); |
| 269 | 269 | ||
| 270 | #[cfg(pwr_h5)] | 270 | #[cfg(pwr_h5)] |
