Port FDCAN HAL to use PAC directly instead of fdcan crate.
- Provide separate FDCAN capable and Classic CAN API's - Don't use fdcan crate dep anymore - Provide embedded-can traits.
This commit is contained in:
		
							parent
							
								
									377e58e408
								
							
						
					
					
						commit
						70b3c4374d
					
				| @ -55,10 +55,12 @@ embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["un | |||||||
| embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | ||||||
| embedded-hal-async = { version = "1.0" } | embedded-hal-async = { version = "1.0" } | ||||||
| embedded-hal-nb = { version = "1.0" } | embedded-hal-nb = { version = "1.0" } | ||||||
|  | embedded-can = "0.4" | ||||||
| 
 | 
 | ||||||
| embedded-storage = "0.3.1" | embedded-storage = "0.3.1" | ||||||
| embedded-storage-async = { version = "0.4.1" } | embedded-storage-async = { version = "0.4.1" } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| defmt = { version = "0.3", optional = true } | defmt = { version = "0.3", optional = true } | ||||||
| log = { version = "0.4.14", optional = true } | log = { version = "0.4.14", optional = true } | ||||||
| cortex-m-rt = ">=0.6.15,<0.8" | cortex-m-rt = ">=0.6.15,<0.8" | ||||||
| @ -80,7 +82,10 @@ chrono = { version = "^0.4", default-features = false, optional = true} | |||||||
| bit_field = "0.10.2" | bit_field = "0.10.2" | ||||||
| document-features = "0.2.7" | document-features = "0.2.7" | ||||||
| 
 | 
 | ||||||
| fdcan = { version = "0.2.0", optional = true } | static_assertions = { version = "1.1" } | ||||||
|  | volatile-register = { version = "0.2.1" } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| [dev-dependencies] | [dev-dependencies] | ||||||
| critical-section = { version = "1.1", features = ["std"] } | critical-section = { version = "1.1", features = ["std"] } | ||||||
| @ -695,373 +700,373 @@ stm32f779ai = [ "stm32-metapac/stm32f779ai" ] | |||||||
| stm32f779bi = [ "stm32-metapac/stm32f779bi" ] | stm32f779bi = [ "stm32-metapac/stm32f779bi" ] | ||||||
| stm32f779ii = [ "stm32-metapac/stm32f779ii" ] | stm32f779ii = [ "stm32-metapac/stm32f779ii" ] | ||||||
| stm32f779ni = [ "stm32-metapac/stm32f779ni" ] | stm32f779ni = [ "stm32-metapac/stm32f779ni" ] | ||||||
| stm32g030c6 = [ "stm32-metapac/stm32g030c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g030c6 = [ "stm32-metapac/stm32g030c6" ] | ||||||
| stm32g030c8 = [ "stm32-metapac/stm32g030c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g030c8 = [ "stm32-metapac/stm32g030c8" ] | ||||||
| stm32g030f6 = [ "stm32-metapac/stm32g030f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g030f6 = [ "stm32-metapac/stm32g030f6" ] | ||||||
| stm32g030j6 = [ "stm32-metapac/stm32g030j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g030j6 = [ "stm32-metapac/stm32g030j6" ] | ||||||
| stm32g030k6 = [ "stm32-metapac/stm32g030k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g030k6 = [ "stm32-metapac/stm32g030k6" ] | ||||||
| stm32g030k8 = [ "stm32-metapac/stm32g030k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g030k8 = [ "stm32-metapac/stm32g030k8" ] | ||||||
| stm32g031c4 = [ "stm32-metapac/stm32g031c4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g031c4 = [ "stm32-metapac/stm32g031c4" ] | ||||||
| stm32g031c6 = [ "stm32-metapac/stm32g031c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g031c6 = [ "stm32-metapac/stm32g031c6" ] | ||||||
| stm32g031c8 = [ "stm32-metapac/stm32g031c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g031c8 = [ "stm32-metapac/stm32g031c8" ] | ||||||
| stm32g031f4 = [ "stm32-metapac/stm32g031f4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g031f4 = [ "stm32-metapac/stm32g031f4" ] | ||||||
| stm32g031f6 = [ "stm32-metapac/stm32g031f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g031f6 = [ "stm32-metapac/stm32g031f6" ] | ||||||
| stm32g031f8 = [ "stm32-metapac/stm32g031f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g031f8 = [ "stm32-metapac/stm32g031f8" ] | ||||||
| stm32g031g4 = [ "stm32-metapac/stm32g031g4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g031g4 = [ "stm32-metapac/stm32g031g4" ] | ||||||
| stm32g031g6 = [ "stm32-metapac/stm32g031g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g031g6 = [ "stm32-metapac/stm32g031g6" ] | ||||||
| stm32g031g8 = [ "stm32-metapac/stm32g031g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g031g8 = [ "stm32-metapac/stm32g031g8" ] | ||||||
| stm32g031j4 = [ "stm32-metapac/stm32g031j4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g031j4 = [ "stm32-metapac/stm32g031j4" ] | ||||||
| stm32g031j6 = [ "stm32-metapac/stm32g031j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g031j6 = [ "stm32-metapac/stm32g031j6" ] | ||||||
| stm32g031k4 = [ "stm32-metapac/stm32g031k4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g031k4 = [ "stm32-metapac/stm32g031k4" ] | ||||||
| stm32g031k6 = [ "stm32-metapac/stm32g031k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g031k6 = [ "stm32-metapac/stm32g031k6" ] | ||||||
| stm32g031k8 = [ "stm32-metapac/stm32g031k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g031k8 = [ "stm32-metapac/stm32g031k8" ] | ||||||
| stm32g031y8 = [ "stm32-metapac/stm32g031y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g031y8 = [ "stm32-metapac/stm32g031y8" ] | ||||||
| stm32g041c6 = [ "stm32-metapac/stm32g041c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g041c6 = [ "stm32-metapac/stm32g041c6" ] | ||||||
| stm32g041c8 = [ "stm32-metapac/stm32g041c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g041c8 = [ "stm32-metapac/stm32g041c8" ] | ||||||
| stm32g041f6 = [ "stm32-metapac/stm32g041f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g041f6 = [ "stm32-metapac/stm32g041f6" ] | ||||||
| stm32g041f8 = [ "stm32-metapac/stm32g041f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g041f8 = [ "stm32-metapac/stm32g041f8" ] | ||||||
| stm32g041g6 = [ "stm32-metapac/stm32g041g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g041g6 = [ "stm32-metapac/stm32g041g6" ] | ||||||
| stm32g041g8 = [ "stm32-metapac/stm32g041g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g041g8 = [ "stm32-metapac/stm32g041g8" ] | ||||||
| stm32g041j6 = [ "stm32-metapac/stm32g041j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g041j6 = [ "stm32-metapac/stm32g041j6" ] | ||||||
| stm32g041k6 = [ "stm32-metapac/stm32g041k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g041k6 = [ "stm32-metapac/stm32g041k6" ] | ||||||
| stm32g041k8 = [ "stm32-metapac/stm32g041k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g041k8 = [ "stm32-metapac/stm32g041k8" ] | ||||||
| stm32g041y8 = [ "stm32-metapac/stm32g041y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g041y8 = [ "stm32-metapac/stm32g041y8" ] | ||||||
| stm32g050c6 = [ "stm32-metapac/stm32g050c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g050c6 = [ "stm32-metapac/stm32g050c6" ] | ||||||
| stm32g050c8 = [ "stm32-metapac/stm32g050c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g050c8 = [ "stm32-metapac/stm32g050c8" ] | ||||||
| stm32g050f6 = [ "stm32-metapac/stm32g050f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g050f6 = [ "stm32-metapac/stm32g050f6" ] | ||||||
| stm32g050k6 = [ "stm32-metapac/stm32g050k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g050k6 = [ "stm32-metapac/stm32g050k6" ] | ||||||
| stm32g050k8 = [ "stm32-metapac/stm32g050k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g050k8 = [ "stm32-metapac/stm32g050k8" ] | ||||||
| stm32g051c6 = [ "stm32-metapac/stm32g051c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g051c6 = [ "stm32-metapac/stm32g051c6" ] | ||||||
| stm32g051c8 = [ "stm32-metapac/stm32g051c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g051c8 = [ "stm32-metapac/stm32g051c8" ] | ||||||
| stm32g051f6 = [ "stm32-metapac/stm32g051f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g051f6 = [ "stm32-metapac/stm32g051f6" ] | ||||||
| stm32g051f8 = [ "stm32-metapac/stm32g051f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g051f8 = [ "stm32-metapac/stm32g051f8" ] | ||||||
| stm32g051g6 = [ "stm32-metapac/stm32g051g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g051g6 = [ "stm32-metapac/stm32g051g6" ] | ||||||
| stm32g051g8 = [ "stm32-metapac/stm32g051g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g051g8 = [ "stm32-metapac/stm32g051g8" ] | ||||||
| stm32g051k6 = [ "stm32-metapac/stm32g051k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g051k6 = [ "stm32-metapac/stm32g051k6" ] | ||||||
| stm32g051k8 = [ "stm32-metapac/stm32g051k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g051k8 = [ "stm32-metapac/stm32g051k8" ] | ||||||
| stm32g061c6 = [ "stm32-metapac/stm32g061c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g061c6 = [ "stm32-metapac/stm32g061c6" ] | ||||||
| stm32g061c8 = [ "stm32-metapac/stm32g061c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g061c8 = [ "stm32-metapac/stm32g061c8" ] | ||||||
| stm32g061f6 = [ "stm32-metapac/stm32g061f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g061f6 = [ "stm32-metapac/stm32g061f6" ] | ||||||
| stm32g061f8 = [ "stm32-metapac/stm32g061f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g061f8 = [ "stm32-metapac/stm32g061f8" ] | ||||||
| stm32g061g6 = [ "stm32-metapac/stm32g061g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g061g6 = [ "stm32-metapac/stm32g061g6" ] | ||||||
| stm32g061g8 = [ "stm32-metapac/stm32g061g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g061g8 = [ "stm32-metapac/stm32g061g8" ] | ||||||
| stm32g061k6 = [ "stm32-metapac/stm32g061k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g061k6 = [ "stm32-metapac/stm32g061k6" ] | ||||||
| stm32g061k8 = [ "stm32-metapac/stm32g061k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g061k8 = [ "stm32-metapac/stm32g061k8" ] | ||||||
| stm32g070cb = [ "stm32-metapac/stm32g070cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g070cb = [ "stm32-metapac/stm32g070cb" ] | ||||||
| stm32g070kb = [ "stm32-metapac/stm32g070kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g070kb = [ "stm32-metapac/stm32g070kb" ] | ||||||
| stm32g070rb = [ "stm32-metapac/stm32g070rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g070rb = [ "stm32-metapac/stm32g070rb" ] | ||||||
| stm32g071c6 = [ "stm32-metapac/stm32g071c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g071c6 = [ "stm32-metapac/stm32g071c6" ] | ||||||
| stm32g071c8 = [ "stm32-metapac/stm32g071c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g071c8 = [ "stm32-metapac/stm32g071c8" ] | ||||||
| stm32g071cb = [ "stm32-metapac/stm32g071cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g071cb = [ "stm32-metapac/stm32g071cb" ] | ||||||
| stm32g071eb = [ "stm32-metapac/stm32g071eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g071eb = [ "stm32-metapac/stm32g071eb" ] | ||||||
| stm32g071g6 = [ "stm32-metapac/stm32g071g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g071g6 = [ "stm32-metapac/stm32g071g6" ] | ||||||
| stm32g071g8 = [ "stm32-metapac/stm32g071g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g071g8 = [ "stm32-metapac/stm32g071g8" ] | ||||||
| stm32g071gb = [ "stm32-metapac/stm32g071gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g071gb = [ "stm32-metapac/stm32g071gb" ] | ||||||
| stm32g071k6 = [ "stm32-metapac/stm32g071k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g071k6 = [ "stm32-metapac/stm32g071k6" ] | ||||||
| stm32g071k8 = [ "stm32-metapac/stm32g071k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g071k8 = [ "stm32-metapac/stm32g071k8" ] | ||||||
| stm32g071kb = [ "stm32-metapac/stm32g071kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g071kb = [ "stm32-metapac/stm32g071kb" ] | ||||||
| stm32g071r6 = [ "stm32-metapac/stm32g071r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g071r6 = [ "stm32-metapac/stm32g071r6" ] | ||||||
| stm32g071r8 = [ "stm32-metapac/stm32g071r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g071r8 = [ "stm32-metapac/stm32g071r8" ] | ||||||
| stm32g071rb = [ "stm32-metapac/stm32g071rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g071rb = [ "stm32-metapac/stm32g071rb" ] | ||||||
| stm32g081cb = [ "stm32-metapac/stm32g081cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g081cb = [ "stm32-metapac/stm32g081cb" ] | ||||||
| stm32g081eb = [ "stm32-metapac/stm32g081eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g081eb = [ "stm32-metapac/stm32g081eb" ] | ||||||
| stm32g081gb = [ "stm32-metapac/stm32g081gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g081gb = [ "stm32-metapac/stm32g081gb" ] | ||||||
| stm32g081kb = [ "stm32-metapac/stm32g081kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g081kb = [ "stm32-metapac/stm32g081kb" ] | ||||||
| stm32g081rb = [ "stm32-metapac/stm32g081rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g081rb = [ "stm32-metapac/stm32g081rb" ] | ||||||
| stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce" ] | ||||||
| stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke" ] | ||||||
| stm32g0b0re = [ "stm32-metapac/stm32g0b0re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b0re = [ "stm32-metapac/stm32g0b0re" ] | ||||||
| stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve" ] | ||||||
| stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb" ] | ||||||
| stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc" ] | ||||||
| stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce" ] | ||||||
| stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb" ] | ||||||
| stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc" ] | ||||||
| stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke" ] | ||||||
| stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb" ] | ||||||
| stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc" ] | ||||||
| stm32g0b1me = [ "stm32-metapac/stm32g0b1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1me = [ "stm32-metapac/stm32g0b1me" ] | ||||||
| stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne" ] | ||||||
| stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb" ] | ||||||
| stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc" ] | ||||||
| stm32g0b1re = [ "stm32-metapac/stm32g0b1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1re = [ "stm32-metapac/stm32g0b1re" ] | ||||||
| stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb" ] | ||||||
| stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc" ] | ||||||
| stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve" ] | ||||||
| stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc" ] | ||||||
| stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce" ] | ||||||
| stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc" ] | ||||||
| stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke" ] | ||||||
| stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc" ] | ||||||
| stm32g0c1me = [ "stm32-metapac/stm32g0c1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0c1me = [ "stm32-metapac/stm32g0c1me" ] | ||||||
| stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne" ] | ||||||
| stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc" ] | ||||||
| stm32g0c1re = [ "stm32-metapac/stm32g0c1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0c1re = [ "stm32-metapac/stm32g0c1re" ] | ||||||
| stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc" ] | ||||||
| stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve" ] | ||||||
| stm32g431c6 = [ "stm32-metapac/stm32g431c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g431c6 = [ "stm32-metapac/stm32g431c6" ] | ||||||
| stm32g431c8 = [ "stm32-metapac/stm32g431c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g431c8 = [ "stm32-metapac/stm32g431c8" ] | ||||||
| stm32g431cb = [ "stm32-metapac/stm32g431cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g431cb = [ "stm32-metapac/stm32g431cb" ] | ||||||
| stm32g431k6 = [ "stm32-metapac/stm32g431k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g431k6 = [ "stm32-metapac/stm32g431k6" ] | ||||||
| stm32g431k8 = [ "stm32-metapac/stm32g431k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g431k8 = [ "stm32-metapac/stm32g431k8" ] | ||||||
| stm32g431kb = [ "stm32-metapac/stm32g431kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g431kb = [ "stm32-metapac/stm32g431kb" ] | ||||||
| stm32g431m6 = [ "stm32-metapac/stm32g431m6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g431m6 = [ "stm32-metapac/stm32g431m6" ] | ||||||
| stm32g431m8 = [ "stm32-metapac/stm32g431m8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g431m8 = [ "stm32-metapac/stm32g431m8" ] | ||||||
| stm32g431mb = [ "stm32-metapac/stm32g431mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g431mb = [ "stm32-metapac/stm32g431mb" ] | ||||||
| stm32g431r6 = [ "stm32-metapac/stm32g431r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g431r6 = [ "stm32-metapac/stm32g431r6" ] | ||||||
| stm32g431r8 = [ "stm32-metapac/stm32g431r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g431r8 = [ "stm32-metapac/stm32g431r8" ] | ||||||
| stm32g431rb = [ "stm32-metapac/stm32g431rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g431rb = [ "stm32-metapac/stm32g431rb" ] | ||||||
| stm32g431v6 = [ "stm32-metapac/stm32g431v6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g431v6 = [ "stm32-metapac/stm32g431v6" ] | ||||||
| stm32g431v8 = [ "stm32-metapac/stm32g431v8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g431v8 = [ "stm32-metapac/stm32g431v8" ] | ||||||
| stm32g431vb = [ "stm32-metapac/stm32g431vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g431vb = [ "stm32-metapac/stm32g431vb" ] | ||||||
| stm32g441cb = [ "stm32-metapac/stm32g441cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g441cb = [ "stm32-metapac/stm32g441cb" ] | ||||||
| stm32g441kb = [ "stm32-metapac/stm32g441kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g441kb = [ "stm32-metapac/stm32g441kb" ] | ||||||
| stm32g441mb = [ "stm32-metapac/stm32g441mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g441mb = [ "stm32-metapac/stm32g441mb" ] | ||||||
| stm32g441rb = [ "stm32-metapac/stm32g441rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g441rb = [ "stm32-metapac/stm32g441rb" ] | ||||||
| stm32g441vb = [ "stm32-metapac/stm32g441vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g441vb = [ "stm32-metapac/stm32g441vb" ] | ||||||
| stm32g471cc = [ "stm32-metapac/stm32g471cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g471cc = [ "stm32-metapac/stm32g471cc" ] | ||||||
| stm32g471ce = [ "stm32-metapac/stm32g471ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g471ce = [ "stm32-metapac/stm32g471ce" ] | ||||||
| stm32g471mc = [ "stm32-metapac/stm32g471mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g471mc = [ "stm32-metapac/stm32g471mc" ] | ||||||
| stm32g471me = [ "stm32-metapac/stm32g471me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g471me = [ "stm32-metapac/stm32g471me" ] | ||||||
| stm32g471qc = [ "stm32-metapac/stm32g471qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g471qc = [ "stm32-metapac/stm32g471qc" ] | ||||||
| stm32g471qe = [ "stm32-metapac/stm32g471qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g471qe = [ "stm32-metapac/stm32g471qe" ] | ||||||
| stm32g471rc = [ "stm32-metapac/stm32g471rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g471rc = [ "stm32-metapac/stm32g471rc" ] | ||||||
| stm32g471re = [ "stm32-metapac/stm32g471re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g471re = [ "stm32-metapac/stm32g471re" ] | ||||||
| stm32g471vc = [ "stm32-metapac/stm32g471vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g471vc = [ "stm32-metapac/stm32g471vc" ] | ||||||
| stm32g471ve = [ "stm32-metapac/stm32g471ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g471ve = [ "stm32-metapac/stm32g471ve" ] | ||||||
| stm32g473cb = [ "stm32-metapac/stm32g473cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473cb = [ "stm32-metapac/stm32g473cb" ] | ||||||
| stm32g473cc = [ "stm32-metapac/stm32g473cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473cc = [ "stm32-metapac/stm32g473cc" ] | ||||||
| stm32g473ce = [ "stm32-metapac/stm32g473ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473ce = [ "stm32-metapac/stm32g473ce" ] | ||||||
| stm32g473mb = [ "stm32-metapac/stm32g473mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473mb = [ "stm32-metapac/stm32g473mb" ] | ||||||
| stm32g473mc = [ "stm32-metapac/stm32g473mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473mc = [ "stm32-metapac/stm32g473mc" ] | ||||||
| stm32g473me = [ "stm32-metapac/stm32g473me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473me = [ "stm32-metapac/stm32g473me" ] | ||||||
| stm32g473pb = [ "stm32-metapac/stm32g473pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473pb = [ "stm32-metapac/stm32g473pb" ] | ||||||
| stm32g473pc = [ "stm32-metapac/stm32g473pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473pc = [ "stm32-metapac/stm32g473pc" ] | ||||||
| stm32g473pe = [ "stm32-metapac/stm32g473pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473pe = [ "stm32-metapac/stm32g473pe" ] | ||||||
| stm32g473qb = [ "stm32-metapac/stm32g473qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473qb = [ "stm32-metapac/stm32g473qb" ] | ||||||
| stm32g473qc = [ "stm32-metapac/stm32g473qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473qc = [ "stm32-metapac/stm32g473qc" ] | ||||||
| stm32g473qe = [ "stm32-metapac/stm32g473qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473qe = [ "stm32-metapac/stm32g473qe" ] | ||||||
| stm32g473rb = [ "stm32-metapac/stm32g473rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473rb = [ "stm32-metapac/stm32g473rb" ] | ||||||
| stm32g473rc = [ "stm32-metapac/stm32g473rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473rc = [ "stm32-metapac/stm32g473rc" ] | ||||||
| stm32g473re = [ "stm32-metapac/stm32g473re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473re = [ "stm32-metapac/stm32g473re" ] | ||||||
| stm32g473vb = [ "stm32-metapac/stm32g473vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473vb = [ "stm32-metapac/stm32g473vb" ] | ||||||
| stm32g473vc = [ "stm32-metapac/stm32g473vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473vc = [ "stm32-metapac/stm32g473vc" ] | ||||||
| stm32g473ve = [ "stm32-metapac/stm32g473ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g473ve = [ "stm32-metapac/stm32g473ve" ] | ||||||
| stm32g474cb = [ "stm32-metapac/stm32g474cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474cb = [ "stm32-metapac/stm32g474cb" ] | ||||||
| stm32g474cc = [ "stm32-metapac/stm32g474cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474cc = [ "stm32-metapac/stm32g474cc" ] | ||||||
| stm32g474ce = [ "stm32-metapac/stm32g474ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474ce = [ "stm32-metapac/stm32g474ce" ] | ||||||
| stm32g474mb = [ "stm32-metapac/stm32g474mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474mb = [ "stm32-metapac/stm32g474mb" ] | ||||||
| stm32g474mc = [ "stm32-metapac/stm32g474mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474mc = [ "stm32-metapac/stm32g474mc" ] | ||||||
| stm32g474me = [ "stm32-metapac/stm32g474me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474me = [ "stm32-metapac/stm32g474me" ] | ||||||
| stm32g474pb = [ "stm32-metapac/stm32g474pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474pb = [ "stm32-metapac/stm32g474pb" ] | ||||||
| stm32g474pc = [ "stm32-metapac/stm32g474pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474pc = [ "stm32-metapac/stm32g474pc" ] | ||||||
| stm32g474pe = [ "stm32-metapac/stm32g474pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474pe = [ "stm32-metapac/stm32g474pe" ] | ||||||
| stm32g474qb = [ "stm32-metapac/stm32g474qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474qb = [ "stm32-metapac/stm32g474qb" ] | ||||||
| stm32g474qc = [ "stm32-metapac/stm32g474qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474qc = [ "stm32-metapac/stm32g474qc" ] | ||||||
| stm32g474qe = [ "stm32-metapac/stm32g474qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474qe = [ "stm32-metapac/stm32g474qe" ] | ||||||
| stm32g474rb = [ "stm32-metapac/stm32g474rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474rb = [ "stm32-metapac/stm32g474rb" ] | ||||||
| stm32g474rc = [ "stm32-metapac/stm32g474rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474rc = [ "stm32-metapac/stm32g474rc" ] | ||||||
| stm32g474re = [ "stm32-metapac/stm32g474re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474re = [ "stm32-metapac/stm32g474re" ] | ||||||
| stm32g474vb = [ "stm32-metapac/stm32g474vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474vb = [ "stm32-metapac/stm32g474vb" ] | ||||||
| stm32g474vc = [ "stm32-metapac/stm32g474vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474vc = [ "stm32-metapac/stm32g474vc" ] | ||||||
| stm32g474ve = [ "stm32-metapac/stm32g474ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g474ve = [ "stm32-metapac/stm32g474ve" ] | ||||||
| stm32g483ce = [ "stm32-metapac/stm32g483ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g483ce = [ "stm32-metapac/stm32g483ce" ] | ||||||
| stm32g483me = [ "stm32-metapac/stm32g483me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g483me = [ "stm32-metapac/stm32g483me" ] | ||||||
| stm32g483pe = [ "stm32-metapac/stm32g483pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g483pe = [ "stm32-metapac/stm32g483pe" ] | ||||||
| stm32g483qe = [ "stm32-metapac/stm32g483qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g483qe = [ "stm32-metapac/stm32g483qe" ] | ||||||
| stm32g483re = [ "stm32-metapac/stm32g483re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g483re = [ "stm32-metapac/stm32g483re" ] | ||||||
| stm32g483ve = [ "stm32-metapac/stm32g483ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g483ve = [ "stm32-metapac/stm32g483ve" ] | ||||||
| stm32g484ce = [ "stm32-metapac/stm32g484ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g484ce = [ "stm32-metapac/stm32g484ce" ] | ||||||
| stm32g484me = [ "stm32-metapac/stm32g484me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g484me = [ "stm32-metapac/stm32g484me" ] | ||||||
| stm32g484pe = [ "stm32-metapac/stm32g484pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g484pe = [ "stm32-metapac/stm32g484pe" ] | ||||||
| stm32g484qe = [ "stm32-metapac/stm32g484qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g484qe = [ "stm32-metapac/stm32g484qe" ] | ||||||
| stm32g484re = [ "stm32-metapac/stm32g484re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g484re = [ "stm32-metapac/stm32g484re" ] | ||||||
| stm32g484ve = [ "stm32-metapac/stm32g484ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g484ve = [ "stm32-metapac/stm32g484ve" ] | ||||||
| stm32g491cc = [ "stm32-metapac/stm32g491cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g491cc = [ "stm32-metapac/stm32g491cc" ] | ||||||
| stm32g491ce = [ "stm32-metapac/stm32g491ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g491ce = [ "stm32-metapac/stm32g491ce" ] | ||||||
| stm32g491kc = [ "stm32-metapac/stm32g491kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g491kc = [ "stm32-metapac/stm32g491kc" ] | ||||||
| stm32g491ke = [ "stm32-metapac/stm32g491ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g491ke = [ "stm32-metapac/stm32g491ke" ] | ||||||
| stm32g491mc = [ "stm32-metapac/stm32g491mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g491mc = [ "stm32-metapac/stm32g491mc" ] | ||||||
| stm32g491me = [ "stm32-metapac/stm32g491me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g491me = [ "stm32-metapac/stm32g491me" ] | ||||||
| stm32g491rc = [ "stm32-metapac/stm32g491rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g491rc = [ "stm32-metapac/stm32g491rc" ] | ||||||
| stm32g491re = [ "stm32-metapac/stm32g491re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g491re = [ "stm32-metapac/stm32g491re" ] | ||||||
| stm32g491vc = [ "stm32-metapac/stm32g491vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g491vc = [ "stm32-metapac/stm32g491vc" ] | ||||||
| stm32g491ve = [ "stm32-metapac/stm32g491ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g491ve = [ "stm32-metapac/stm32g491ve" ] | ||||||
| stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce" ] | ||||||
| stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke" ] | ||||||
| stm32g4a1me = [ "stm32-metapac/stm32g4a1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g4a1me = [ "stm32-metapac/stm32g4a1me" ] | ||||||
| stm32g4a1re = [ "stm32-metapac/stm32g4a1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g4a1re = [ "stm32-metapac/stm32g4a1re" ] | ||||||
| stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve" ] | ||||||
| stm32h503cb = [ "stm32-metapac/stm32h503cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h503cb = [ "stm32-metapac/stm32h503cb" ] | ||||||
| stm32h503eb = [ "stm32-metapac/stm32h503eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h503eb = [ "stm32-metapac/stm32h503eb" ] | ||||||
| stm32h503kb = [ "stm32-metapac/stm32h503kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h503kb = [ "stm32-metapac/stm32h503kb" ] | ||||||
| stm32h503rb = [ "stm32-metapac/stm32h503rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h503rb = [ "stm32-metapac/stm32h503rb" ] | ||||||
| stm32h562ag = [ "stm32-metapac/stm32h562ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h562ag = [ "stm32-metapac/stm32h562ag" ] | ||||||
| stm32h562ai = [ "stm32-metapac/stm32h562ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h562ai = [ "stm32-metapac/stm32h562ai" ] | ||||||
| stm32h562ig = [ "stm32-metapac/stm32h562ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h562ig = [ "stm32-metapac/stm32h562ig" ] | ||||||
| stm32h562ii = [ "stm32-metapac/stm32h562ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h562ii = [ "stm32-metapac/stm32h562ii" ] | ||||||
| stm32h562rg = [ "stm32-metapac/stm32h562rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h562rg = [ "stm32-metapac/stm32h562rg" ] | ||||||
| stm32h562ri = [ "stm32-metapac/stm32h562ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h562ri = [ "stm32-metapac/stm32h562ri" ] | ||||||
| stm32h562vg = [ "stm32-metapac/stm32h562vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h562vg = [ "stm32-metapac/stm32h562vg" ] | ||||||
| stm32h562vi = [ "stm32-metapac/stm32h562vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h562vi = [ "stm32-metapac/stm32h562vi" ] | ||||||
| stm32h562zg = [ "stm32-metapac/stm32h562zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h562zg = [ "stm32-metapac/stm32h562zg" ] | ||||||
| stm32h562zi = [ "stm32-metapac/stm32h562zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h562zi = [ "stm32-metapac/stm32h562zi" ] | ||||||
| stm32h563ag = [ "stm32-metapac/stm32h563ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h563ag = [ "stm32-metapac/stm32h563ag" ] | ||||||
| stm32h563ai = [ "stm32-metapac/stm32h563ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h563ai = [ "stm32-metapac/stm32h563ai" ] | ||||||
| stm32h563ig = [ "stm32-metapac/stm32h563ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h563ig = [ "stm32-metapac/stm32h563ig" ] | ||||||
| stm32h563ii = [ "stm32-metapac/stm32h563ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h563ii = [ "stm32-metapac/stm32h563ii" ] | ||||||
| stm32h563mi = [ "stm32-metapac/stm32h563mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h563mi = [ "stm32-metapac/stm32h563mi" ] | ||||||
| stm32h563rg = [ "stm32-metapac/stm32h563rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h563rg = [ "stm32-metapac/stm32h563rg" ] | ||||||
| stm32h563ri = [ "stm32-metapac/stm32h563ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h563ri = [ "stm32-metapac/stm32h563ri" ] | ||||||
| stm32h563vg = [ "stm32-metapac/stm32h563vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h563vg = [ "stm32-metapac/stm32h563vg" ] | ||||||
| stm32h563vi = [ "stm32-metapac/stm32h563vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h563vi = [ "stm32-metapac/stm32h563vi" ] | ||||||
| stm32h563zg = [ "stm32-metapac/stm32h563zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h563zg = [ "stm32-metapac/stm32h563zg" ] | ||||||
| stm32h563zi = [ "stm32-metapac/stm32h563zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h563zi = [ "stm32-metapac/stm32h563zi" ] | ||||||
| stm32h573ai = [ "stm32-metapac/stm32h573ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h573ai = [ "stm32-metapac/stm32h573ai" ] | ||||||
| stm32h573ii = [ "stm32-metapac/stm32h573ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h573ii = [ "stm32-metapac/stm32h573ii" ] | ||||||
| stm32h573mi = [ "stm32-metapac/stm32h573mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h573mi = [ "stm32-metapac/stm32h573mi" ] | ||||||
| stm32h573ri = [ "stm32-metapac/stm32h573ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h573ri = [ "stm32-metapac/stm32h573ri" ] | ||||||
| stm32h573vi = [ "stm32-metapac/stm32h573vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h573vi = [ "stm32-metapac/stm32h573vi" ] | ||||||
| stm32h573zi = [ "stm32-metapac/stm32h573zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32h573zi = [ "stm32-metapac/stm32h573zi" ] | ||||||
| stm32h723ve = [ "stm32-metapac/stm32h723ve", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h723ve = [ "stm32-metapac/stm32h723ve" ] | ||||||
| stm32h723vg = [ "stm32-metapac/stm32h723vg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h723vg = [ "stm32-metapac/stm32h723vg" ] | ||||||
| stm32h723ze = [ "stm32-metapac/stm32h723ze", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h723ze = [ "stm32-metapac/stm32h723ze" ] | ||||||
| stm32h723zg = [ "stm32-metapac/stm32h723zg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h723zg = [ "stm32-metapac/stm32h723zg" ] | ||||||
| stm32h725ae = [ "stm32-metapac/stm32h725ae", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h725ae = [ "stm32-metapac/stm32h725ae" ] | ||||||
| stm32h725ag = [ "stm32-metapac/stm32h725ag", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h725ag = [ "stm32-metapac/stm32h725ag" ] | ||||||
| stm32h725ie = [ "stm32-metapac/stm32h725ie", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h725ie = [ "stm32-metapac/stm32h725ie" ] | ||||||
| stm32h725ig = [ "stm32-metapac/stm32h725ig", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h725ig = [ "stm32-metapac/stm32h725ig" ] | ||||||
| stm32h725re = [ "stm32-metapac/stm32h725re", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h725re = [ "stm32-metapac/stm32h725re" ] | ||||||
| stm32h725rg = [ "stm32-metapac/stm32h725rg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h725rg = [ "stm32-metapac/stm32h725rg" ] | ||||||
| stm32h725ve = [ "stm32-metapac/stm32h725ve", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h725ve = [ "stm32-metapac/stm32h725ve" ] | ||||||
| stm32h725vg = [ "stm32-metapac/stm32h725vg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h725vg = [ "stm32-metapac/stm32h725vg" ] | ||||||
| stm32h725ze = [ "stm32-metapac/stm32h725ze", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h725ze = [ "stm32-metapac/stm32h725ze" ] | ||||||
| stm32h725zg = [ "stm32-metapac/stm32h725zg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h725zg = [ "stm32-metapac/stm32h725zg" ] | ||||||
| stm32h730ab = [ "stm32-metapac/stm32h730ab", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h730ab = [ "stm32-metapac/stm32h730ab" ] | ||||||
| stm32h730ib = [ "stm32-metapac/stm32h730ib", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h730ib = [ "stm32-metapac/stm32h730ib" ] | ||||||
| stm32h730vb = [ "stm32-metapac/stm32h730vb", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h730vb = [ "stm32-metapac/stm32h730vb" ] | ||||||
| stm32h730zb = [ "stm32-metapac/stm32h730zb", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h730zb = [ "stm32-metapac/stm32h730zb" ] | ||||||
| stm32h733vg = [ "stm32-metapac/stm32h733vg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h733vg = [ "stm32-metapac/stm32h733vg" ] | ||||||
| stm32h733zg = [ "stm32-metapac/stm32h733zg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h733zg = [ "stm32-metapac/stm32h733zg" ] | ||||||
| stm32h735ag = [ "stm32-metapac/stm32h735ag", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h735ag = [ "stm32-metapac/stm32h735ag" ] | ||||||
| stm32h735ig = [ "stm32-metapac/stm32h735ig", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h735ig = [ "stm32-metapac/stm32h735ig" ] | ||||||
| stm32h735rg = [ "stm32-metapac/stm32h735rg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h735rg = [ "stm32-metapac/stm32h735rg" ] | ||||||
| stm32h735vg = [ "stm32-metapac/stm32h735vg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h735vg = [ "stm32-metapac/stm32h735vg" ] | ||||||
| stm32h735zg = [ "stm32-metapac/stm32h735zg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h735zg = [ "stm32-metapac/stm32h735zg" ] | ||||||
| stm32h742ag = [ "stm32-metapac/stm32h742ag", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h742ag = [ "stm32-metapac/stm32h742ag" ] | ||||||
| stm32h742ai = [ "stm32-metapac/stm32h742ai", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h742ai = [ "stm32-metapac/stm32h742ai" ] | ||||||
| stm32h742bg = [ "stm32-metapac/stm32h742bg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h742bg = [ "stm32-metapac/stm32h742bg" ] | ||||||
| stm32h742bi = [ "stm32-metapac/stm32h742bi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h742bi = [ "stm32-metapac/stm32h742bi" ] | ||||||
| stm32h742ig = [ "stm32-metapac/stm32h742ig", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h742ig = [ "stm32-metapac/stm32h742ig" ] | ||||||
| stm32h742ii = [ "stm32-metapac/stm32h742ii", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h742ii = [ "stm32-metapac/stm32h742ii" ] | ||||||
| stm32h742vg = [ "stm32-metapac/stm32h742vg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h742vg = [ "stm32-metapac/stm32h742vg" ] | ||||||
| stm32h742vi = [ "stm32-metapac/stm32h742vi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h742vi = [ "stm32-metapac/stm32h742vi" ] | ||||||
| stm32h742xg = [ "stm32-metapac/stm32h742xg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h742xg = [ "stm32-metapac/stm32h742xg" ] | ||||||
| stm32h742xi = [ "stm32-metapac/stm32h742xi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h742xi = [ "stm32-metapac/stm32h742xi" ] | ||||||
| stm32h742zg = [ "stm32-metapac/stm32h742zg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h742zg = [ "stm32-metapac/stm32h742zg" ] | ||||||
| stm32h742zi = [ "stm32-metapac/stm32h742zi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h742zi = [ "stm32-metapac/stm32h742zi" ] | ||||||
| stm32h743ag = [ "stm32-metapac/stm32h743ag", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h743ag = [ "stm32-metapac/stm32h743ag" ] | ||||||
| stm32h743ai = [ "stm32-metapac/stm32h743ai", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h743ai = [ "stm32-metapac/stm32h743ai" ] | ||||||
| stm32h743bg = [ "stm32-metapac/stm32h743bg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h743bg = [ "stm32-metapac/stm32h743bg" ] | ||||||
| stm32h743bi = [ "stm32-metapac/stm32h743bi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h743bi = [ "stm32-metapac/stm32h743bi" ] | ||||||
| stm32h743ig = [ "stm32-metapac/stm32h743ig", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h743ig = [ "stm32-metapac/stm32h743ig" ] | ||||||
| stm32h743ii = [ "stm32-metapac/stm32h743ii", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h743ii = [ "stm32-metapac/stm32h743ii" ] | ||||||
| stm32h743vg = [ "stm32-metapac/stm32h743vg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h743vg = [ "stm32-metapac/stm32h743vg" ] | ||||||
| stm32h743vi = [ "stm32-metapac/stm32h743vi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h743vi = [ "stm32-metapac/stm32h743vi" ] | ||||||
| stm32h743xg = [ "stm32-metapac/stm32h743xg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h743xg = [ "stm32-metapac/stm32h743xg" ] | ||||||
| stm32h743xi = [ "stm32-metapac/stm32h743xi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h743xi = [ "stm32-metapac/stm32h743xi" ] | ||||||
| stm32h743zg = [ "stm32-metapac/stm32h743zg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h743zg = [ "stm32-metapac/stm32h743zg" ] | ||||||
| stm32h743zi = [ "stm32-metapac/stm32h743zi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h743zi = [ "stm32-metapac/stm32h743zi" ] | ||||||
| stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7" ] | ||||||
| stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4" ] | ||||||
| stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7" ] | ||||||
| stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4" ] | ||||||
| stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7" ] | ||||||
| stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4" ] | ||||||
| stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7" ] | ||||||
| stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4" ] | ||||||
| stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7" ] | ||||||
| stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4" ] | ||||||
| stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7" ] | ||||||
| stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4" ] | ||||||
| stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7" ] | ||||||
| stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4" ] | ||||||
| stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7" ] | ||||||
| stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4" ] | ||||||
| stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7" ] | ||||||
| stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4" ] | ||||||
| stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7" ] | ||||||
| stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4" ] | ||||||
| stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7" ] | ||||||
| stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4" ] | ||||||
| stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7" ] | ||||||
| stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4" ] | ||||||
| stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7" ] | ||||||
| stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4" ] | ||||||
| stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7" ] | ||||||
| stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4" ] | ||||||
| stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7" ] | ||||||
| stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4" ] | ||||||
| stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7" ] | ||||||
| stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4" ] | ||||||
| stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7" ] | ||||||
| stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4" ] | ||||||
| stm32h750ib = [ "stm32-metapac/stm32h750ib", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h750ib = [ "stm32-metapac/stm32h750ib" ] | ||||||
| stm32h750vb = [ "stm32-metapac/stm32h750vb", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h750vb = [ "stm32-metapac/stm32h750vb" ] | ||||||
| stm32h750xb = [ "stm32-metapac/stm32h750xb", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h750xb = [ "stm32-metapac/stm32h750xb" ] | ||||||
| stm32h750zb = [ "stm32-metapac/stm32h750zb", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h750zb = [ "stm32-metapac/stm32h750zb" ] | ||||||
| stm32h753ai = [ "stm32-metapac/stm32h753ai", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h753ai = [ "stm32-metapac/stm32h753ai" ] | ||||||
| stm32h753bi = [ "stm32-metapac/stm32h753bi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h753bi = [ "stm32-metapac/stm32h753bi" ] | ||||||
| stm32h753ii = [ "stm32-metapac/stm32h753ii", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h753ii = [ "stm32-metapac/stm32h753ii" ] | ||||||
| stm32h753vi = [ "stm32-metapac/stm32h753vi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h753vi = [ "stm32-metapac/stm32h753vi" ] | ||||||
| stm32h753xi = [ "stm32-metapac/stm32h753xi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h753xi = [ "stm32-metapac/stm32h753xi" ] | ||||||
| stm32h753zi = [ "stm32-metapac/stm32h753zi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h753zi = [ "stm32-metapac/stm32h753zi" ] | ||||||
| stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7" ] | ||||||
| stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4" ] | ||||||
| stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7" ] | ||||||
| stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4" ] | ||||||
| stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7" ] | ||||||
| stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4" ] | ||||||
| stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7" ] | ||||||
| stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4" ] | ||||||
| stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7" ] | ||||||
| stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4" ] | ||||||
| stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7" ] | ||||||
| stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4" ] | ||||||
| stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7" ] | ||||||
| stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4" ] | ||||||
| stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7" ] | ||||||
| stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4" ] | ||||||
| stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7" ] | ||||||
| stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4" ] | ||||||
| stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag" ] | ||||||
| stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai" ] | ||||||
| stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig" ] | ||||||
| stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii" ] | ||||||
| stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg" ] | ||||||
| stm32h7a3li = [ "stm32-metapac/stm32h7a3li", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7a3li = [ "stm32-metapac/stm32h7a3li" ] | ||||||
| stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng" ] | ||||||
| stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni" ] | ||||||
| stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi" ] | ||||||
| stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg" ] | ||||||
| stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri" ] | ||||||
| stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg" ] | ||||||
| stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi" ] | ||||||
| stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg" ] | ||||||
| stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi" ] | ||||||
| stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab" ] | ||||||
| stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib" ] | ||||||
| stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb" ] | ||||||
| stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb" ] | ||||||
| stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb" ] | ||||||
| stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai" ] | ||||||
| stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii" ] | ||||||
| stm32h7b3li = [ "stm32-metapac/stm32h7b3li", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7b3li = [ "stm32-metapac/stm32h7b3li" ] | ||||||
| stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni" ] | ||||||
| stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi" ] | ||||||
| stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri" ] | ||||||
| stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi" ] | ||||||
| stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi", "dep:fdcan", "fdcan/fdcan_h7" ] | stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi" ] | ||||||
| stm32l010c6 = [ "stm32-metapac/stm32l010c6" ] | stm32l010c6 = [ "stm32-metapac/stm32l010c6" ] | ||||||
| stm32l010f4 = [ "stm32-metapac/stm32l010f4" ] | stm32l010f4 = [ "stm32-metapac/stm32l010f4" ] | ||||||
| stm32l010k4 = [ "stm32-metapac/stm32l010k4" ] | stm32l010k4 = [ "stm32-metapac/stm32l010k4" ] | ||||||
| @ -1388,86 +1393,86 @@ stm32l4s7zi = [ "stm32-metapac/stm32l4s7zi" ] | |||||||
| stm32l4s9ai = [ "stm32-metapac/stm32l4s9ai" ] | stm32l4s9ai = [ "stm32-metapac/stm32l4s9ai" ] | ||||||
| stm32l4s9vi = [ "stm32-metapac/stm32l4s9vi" ] | stm32l4s9vi = [ "stm32-metapac/stm32l4s9vi" ] | ||||||
| stm32l4s9zi = [ "stm32-metapac/stm32l4s9zi" ] | stm32l4s9zi = [ "stm32-metapac/stm32l4s9zi" ] | ||||||
| stm32l552cc = [ "stm32-metapac/stm32l552cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l552cc = [ "stm32-metapac/stm32l552cc" ] | ||||||
| stm32l552ce = [ "stm32-metapac/stm32l552ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l552ce = [ "stm32-metapac/stm32l552ce" ] | ||||||
| stm32l552me = [ "stm32-metapac/stm32l552me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l552me = [ "stm32-metapac/stm32l552me" ] | ||||||
| stm32l552qc = [ "stm32-metapac/stm32l552qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l552qc = [ "stm32-metapac/stm32l552qc" ] | ||||||
| stm32l552qe = [ "stm32-metapac/stm32l552qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l552qe = [ "stm32-metapac/stm32l552qe" ] | ||||||
| stm32l552rc = [ "stm32-metapac/stm32l552rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l552rc = [ "stm32-metapac/stm32l552rc" ] | ||||||
| stm32l552re = [ "stm32-metapac/stm32l552re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l552re = [ "stm32-metapac/stm32l552re" ] | ||||||
| stm32l552vc = [ "stm32-metapac/stm32l552vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l552vc = [ "stm32-metapac/stm32l552vc" ] | ||||||
| stm32l552ve = [ "stm32-metapac/stm32l552ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l552ve = [ "stm32-metapac/stm32l552ve" ] | ||||||
| stm32l552zc = [ "stm32-metapac/stm32l552zc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l552zc = [ "stm32-metapac/stm32l552zc" ] | ||||||
| stm32l552ze = [ "stm32-metapac/stm32l552ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l552ze = [ "stm32-metapac/stm32l552ze" ] | ||||||
| stm32l562ce = [ "stm32-metapac/stm32l562ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l562ce = [ "stm32-metapac/stm32l562ce" ] | ||||||
| stm32l562me = [ "stm32-metapac/stm32l562me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l562me = [ "stm32-metapac/stm32l562me" ] | ||||||
| stm32l562qe = [ "stm32-metapac/stm32l562qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l562qe = [ "stm32-metapac/stm32l562qe" ] | ||||||
| stm32l562re = [ "stm32-metapac/stm32l562re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l562re = [ "stm32-metapac/stm32l562re" ] | ||||||
| stm32l562ve = [ "stm32-metapac/stm32l562ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l562ve = [ "stm32-metapac/stm32l562ve" ] | ||||||
| stm32l562ze = [ "stm32-metapac/stm32l562ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32l562ze = [ "stm32-metapac/stm32l562ze" ] | ||||||
| stm32u535cb = [ "stm32-metapac/stm32u535cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u535cb = [ "stm32-metapac/stm32u535cb" ] | ||||||
| stm32u535cc = [ "stm32-metapac/stm32u535cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u535cc = [ "stm32-metapac/stm32u535cc" ] | ||||||
| stm32u535ce = [ "stm32-metapac/stm32u535ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u535ce = [ "stm32-metapac/stm32u535ce" ] | ||||||
| stm32u535je = [ "stm32-metapac/stm32u535je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u535je = [ "stm32-metapac/stm32u535je" ] | ||||||
| stm32u535nc = [ "stm32-metapac/stm32u535nc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u535nc = [ "stm32-metapac/stm32u535nc" ] | ||||||
| stm32u535ne = [ "stm32-metapac/stm32u535ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u535ne = [ "stm32-metapac/stm32u535ne" ] | ||||||
| stm32u535rb = [ "stm32-metapac/stm32u535rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u535rb = [ "stm32-metapac/stm32u535rb" ] | ||||||
| stm32u535rc = [ "stm32-metapac/stm32u535rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u535rc = [ "stm32-metapac/stm32u535rc" ] | ||||||
| stm32u535re = [ "stm32-metapac/stm32u535re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u535re = [ "stm32-metapac/stm32u535re" ] | ||||||
| stm32u535vc = [ "stm32-metapac/stm32u535vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u535vc = [ "stm32-metapac/stm32u535vc" ] | ||||||
| stm32u535ve = [ "stm32-metapac/stm32u535ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u535ve = [ "stm32-metapac/stm32u535ve" ] | ||||||
| stm32u545ce = [ "stm32-metapac/stm32u545ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u545ce = [ "stm32-metapac/stm32u545ce" ] | ||||||
| stm32u545je = [ "stm32-metapac/stm32u545je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u545je = [ "stm32-metapac/stm32u545je" ] | ||||||
| stm32u545ne = [ "stm32-metapac/stm32u545ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u545ne = [ "stm32-metapac/stm32u545ne" ] | ||||||
| stm32u545re = [ "stm32-metapac/stm32u545re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u545re = [ "stm32-metapac/stm32u545re" ] | ||||||
| stm32u545ve = [ "stm32-metapac/stm32u545ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u545ve = [ "stm32-metapac/stm32u545ve" ] | ||||||
| stm32u575ag = [ "stm32-metapac/stm32u575ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u575ag = [ "stm32-metapac/stm32u575ag" ] | ||||||
| stm32u575ai = [ "stm32-metapac/stm32u575ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u575ai = [ "stm32-metapac/stm32u575ai" ] | ||||||
| stm32u575cg = [ "stm32-metapac/stm32u575cg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u575cg = [ "stm32-metapac/stm32u575cg" ] | ||||||
| stm32u575ci = [ "stm32-metapac/stm32u575ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u575ci = [ "stm32-metapac/stm32u575ci" ] | ||||||
| stm32u575og = [ "stm32-metapac/stm32u575og", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u575og = [ "stm32-metapac/stm32u575og" ] | ||||||
| stm32u575oi = [ "stm32-metapac/stm32u575oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u575oi = [ "stm32-metapac/stm32u575oi" ] | ||||||
| stm32u575qg = [ "stm32-metapac/stm32u575qg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u575qg = [ "stm32-metapac/stm32u575qg" ] | ||||||
| stm32u575qi = [ "stm32-metapac/stm32u575qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u575qi = [ "stm32-metapac/stm32u575qi" ] | ||||||
| stm32u575rg = [ "stm32-metapac/stm32u575rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u575rg = [ "stm32-metapac/stm32u575rg" ] | ||||||
| stm32u575ri = [ "stm32-metapac/stm32u575ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u575ri = [ "stm32-metapac/stm32u575ri" ] | ||||||
| stm32u575vg = [ "stm32-metapac/stm32u575vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u575vg = [ "stm32-metapac/stm32u575vg" ] | ||||||
| stm32u575vi = [ "stm32-metapac/stm32u575vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u575vi = [ "stm32-metapac/stm32u575vi" ] | ||||||
| stm32u575zg = [ "stm32-metapac/stm32u575zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u575zg = [ "stm32-metapac/stm32u575zg" ] | ||||||
| stm32u575zi = [ "stm32-metapac/stm32u575zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u575zi = [ "stm32-metapac/stm32u575zi" ] | ||||||
| stm32u585ai = [ "stm32-metapac/stm32u585ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u585ai = [ "stm32-metapac/stm32u585ai" ] | ||||||
| stm32u585ci = [ "stm32-metapac/stm32u585ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u585ci = [ "stm32-metapac/stm32u585ci" ] | ||||||
| stm32u585oi = [ "stm32-metapac/stm32u585oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u585oi = [ "stm32-metapac/stm32u585oi" ] | ||||||
| stm32u585qi = [ "stm32-metapac/stm32u585qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u585qi = [ "stm32-metapac/stm32u585qi" ] | ||||||
| stm32u585ri = [ "stm32-metapac/stm32u585ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u585ri = [ "stm32-metapac/stm32u585ri" ] | ||||||
| stm32u585vi = [ "stm32-metapac/stm32u585vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u585vi = [ "stm32-metapac/stm32u585vi" ] | ||||||
| stm32u585zi = [ "stm32-metapac/stm32u585zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u585zi = [ "stm32-metapac/stm32u585zi" ] | ||||||
| stm32u595ai = [ "stm32-metapac/stm32u595ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u595ai = [ "stm32-metapac/stm32u595ai" ] | ||||||
| stm32u595aj = [ "stm32-metapac/stm32u595aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u595aj = [ "stm32-metapac/stm32u595aj" ] | ||||||
| stm32u595qi = [ "stm32-metapac/stm32u595qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u595qi = [ "stm32-metapac/stm32u595qi" ] | ||||||
| stm32u595qj = [ "stm32-metapac/stm32u595qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u595qj = [ "stm32-metapac/stm32u595qj" ] | ||||||
| stm32u595ri = [ "stm32-metapac/stm32u595ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u595ri = [ "stm32-metapac/stm32u595ri" ] | ||||||
| stm32u595rj = [ "stm32-metapac/stm32u595rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u595rj = [ "stm32-metapac/stm32u595rj" ] | ||||||
| stm32u595vi = [ "stm32-metapac/stm32u595vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u595vi = [ "stm32-metapac/stm32u595vi" ] | ||||||
| stm32u595vj = [ "stm32-metapac/stm32u595vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u595vj = [ "stm32-metapac/stm32u595vj" ] | ||||||
| stm32u595zi = [ "stm32-metapac/stm32u595zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u595zi = [ "stm32-metapac/stm32u595zi" ] | ||||||
| stm32u595zj = [ "stm32-metapac/stm32u595zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u595zj = [ "stm32-metapac/stm32u595zj" ] | ||||||
| stm32u599bj = [ "stm32-metapac/stm32u599bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u599bj = [ "stm32-metapac/stm32u599bj" ] | ||||||
| stm32u599ni = [ "stm32-metapac/stm32u599ni", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u599ni = [ "stm32-metapac/stm32u599ni" ] | ||||||
| stm32u599nj = [ "stm32-metapac/stm32u599nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u599nj = [ "stm32-metapac/stm32u599nj" ] | ||||||
| stm32u599vi = [ "stm32-metapac/stm32u599vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u599vi = [ "stm32-metapac/stm32u599vi" ] | ||||||
| stm32u599vj = [ "stm32-metapac/stm32u599vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u599vj = [ "stm32-metapac/stm32u599vj" ] | ||||||
| stm32u599zi = [ "stm32-metapac/stm32u599zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u599zi = [ "stm32-metapac/stm32u599zi" ] | ||||||
| stm32u599zj = [ "stm32-metapac/stm32u599zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u599zj = [ "stm32-metapac/stm32u599zj" ] | ||||||
| stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj" ] | ||||||
| stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj" ] | ||||||
| stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj" ] | ||||||
| stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj" ] | ||||||
| stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj" ] | ||||||
| stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj" ] | ||||||
| stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj" ] | ||||||
| stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj" ] | ||||||
| stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ] | stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj" ] | ||||||
| stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ] | stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ] | ||||||
| stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ] | stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ] | ||||||
| stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ] | stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ] | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| //! Enums shared between CAN controller types.
 | //! Enums shared between CAN controller types.
 | ||||||
|  | use core::convert::TryFrom; | ||||||
| 
 | 
 | ||||||
| /// Bus error
 | /// Bus error
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| @ -28,3 +29,19 @@ pub enum BusError { | |||||||
|     ///  At least one of error counter has reached the Error_Warning limit of 96.
 |     ///  At least one of error counter has reached the Error_Warning limit of 96.
 | ||||||
|     BusWarning, |     BusWarning, | ||||||
| } | } | ||||||
|  | impl TryFrom<u8> for BusError { | ||||||
|  |     type Error = (); | ||||||
|  |     fn try_from(value: u8) -> Result<Self, Self::Error> { | ||||||
|  |         match value { | ||||||
|  |             //0b000 => None,
 | ||||||
|  |             0b001 => Ok(Self::Stuff), | ||||||
|  |             0b010 => Ok(Self::Form), | ||||||
|  |             0b011 => Ok(Self::Acknowledge), | ||||||
|  |             0b100 => Ok(Self::BitRecessive), | ||||||
|  |             0b101 => Ok(Self::BitDominant), | ||||||
|  |             0b110 => Ok(Self::Crc), | ||||||
|  |             //0b111 => Ok(Self::NoError),
 | ||||||
|  |             _ => Err(()), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										438
									
								
								embassy-stm32/src/can/fd/config.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										438
									
								
								embassy-stm32/src/can/fd/config.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,438 @@ | |||||||
|  | //! Configuration for FDCAN Module
 | ||||||
|  | //! Note: This file is copied and modified from fdcan crate by Richard Meadows
 | ||||||
|  | 
 | ||||||
|  | use core::num::{NonZeroU16, NonZeroU8}; | ||||||
|  | 
 | ||||||
|  | /// Configures the bit timings.
 | ||||||
|  | ///
 | ||||||
|  | /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
 | ||||||
|  | /// parameters as follows:
 | ||||||
|  | ///
 | ||||||
|  | /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
 | ||||||
|  | ///   This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
 | ||||||
|  | /// - *Sample Point*: Should normally be left at the default value of 87.5%.
 | ||||||
|  | /// - *SJW*: Should normally be left at the default value of 1.
 | ||||||
|  | ///
 | ||||||
|  | /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
 | ||||||
|  | /// parameter to this method.
 | ||||||
|  | #[derive(Clone, Copy, Debug)] | ||||||
|  | pub struct NominalBitTiming { | ||||||
|  |     /// Value by which the oscillator frequency is divided for generating the bit time quanta. The bit
 | ||||||
|  |     /// time is built up from a multiple of this quanta. Valid values are 1 to 512.
 | ||||||
|  |     pub prescaler: NonZeroU16, | ||||||
|  |     /// Valid values are 1 to 128.
 | ||||||
|  |     pub seg1: NonZeroU8, | ||||||
|  |     /// Valid values are 1 to 255.
 | ||||||
|  |     pub seg2: NonZeroU8, | ||||||
|  |     /// Valid values are 1 to 128.
 | ||||||
|  |     pub sync_jump_width: NonZeroU8, | ||||||
|  | } | ||||||
|  | impl NominalBitTiming { | ||||||
|  |     #[inline] | ||||||
|  |     pub(crate) fn nbrp(&self) -> u16 { | ||||||
|  |         u16::from(self.prescaler) & 0x1FF | ||||||
|  |     } | ||||||
|  |     #[inline] | ||||||
|  |     pub(crate) fn ntseg1(&self) -> u8 { | ||||||
|  |         u8::from(self.seg1) | ||||||
|  |     } | ||||||
|  |     #[inline] | ||||||
|  |     pub(crate) fn ntseg2(&self) -> u8 { | ||||||
|  |         u8::from(self.seg2) & 0x7F | ||||||
|  |     } | ||||||
|  |     #[inline] | ||||||
|  |     pub(crate) fn nsjw(&self) -> u8 { | ||||||
|  |         u8::from(self.sync_jump_width) & 0x7F | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Default for NominalBitTiming { | ||||||
|  |     #[inline] | ||||||
|  |     fn default() -> Self { | ||||||
|  |         // Kernel Clock 8MHz, Bit rate: 500kbit/s. Corresponds to a NBTP
 | ||||||
|  |         // register value of 0x0600_0A03
 | ||||||
|  |         Self { | ||||||
|  |             prescaler: NonZeroU16::new(1).unwrap(), | ||||||
|  |             seg1: NonZeroU8::new(11).unwrap(), | ||||||
|  |             seg2: NonZeroU8::new(4).unwrap(), | ||||||
|  |             sync_jump_width: NonZeroU8::new(4).unwrap(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Configures the data bit timings for the FdCan Variable Bitrates.
 | ||||||
|  | /// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS.
 | ||||||
|  | #[derive(Clone, Copy, Debug)] | ||||||
|  | pub struct DataBitTiming { | ||||||
|  |     /// Tranceiver Delay Compensation
 | ||||||
|  |     pub transceiver_delay_compensation: bool, | ||||||
|  |     ///  The value by which the oscillator frequency is divided to generate the bit time quanta. The bit
 | ||||||
|  |     ///  time is built up from a multiple of this quanta. Valid values for the Baud Rate Prescaler are 1
 | ||||||
|  |     ///  to 31.
 | ||||||
|  |     pub prescaler: NonZeroU16, | ||||||
|  |     /// Valid values are 1 to 31.
 | ||||||
|  |     pub seg1: NonZeroU8, | ||||||
|  |     /// Valid values are 1 to 15.
 | ||||||
|  |     pub seg2: NonZeroU8, | ||||||
|  |     /// Must always be smaller than DTSEG2, valid values are 1 to 15.
 | ||||||
|  |     pub sync_jump_width: NonZeroU8, | ||||||
|  | } | ||||||
|  | impl DataBitTiming { | ||||||
|  |     // #[inline]
 | ||||||
|  |     // fn tdc(&self) -> u8 {
 | ||||||
|  |     //     let tsd = self.transceiver_delay_compensation as u8;
 | ||||||
|  |     //     //TODO: stm32g4 does not export the TDC field
 | ||||||
|  |     //     todo!()
 | ||||||
|  |     // }
 | ||||||
|  |     #[inline] | ||||||
|  |     pub(crate) fn dbrp(&self) -> u8 { | ||||||
|  |         (u16::from(self.prescaler) & 0x001F) as u8 | ||||||
|  |     } | ||||||
|  |     #[inline] | ||||||
|  |     pub(crate) fn dtseg1(&self) -> u8 { | ||||||
|  |         u8::from(self.seg1) & 0x1F | ||||||
|  |     } | ||||||
|  |     #[inline] | ||||||
|  |     pub(crate) fn dtseg2(&self) -> u8 { | ||||||
|  |         u8::from(self.seg2) & 0x0F | ||||||
|  |     } | ||||||
|  |     #[inline] | ||||||
|  |     pub(crate) fn dsjw(&self) -> u8 { | ||||||
|  |         u8::from(self.sync_jump_width) & 0x0F | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Default for DataBitTiming { | ||||||
|  |     #[inline] | ||||||
|  |     fn default() -> Self { | ||||||
|  |         // Kernel Clock 8MHz, Bit rate: 500kbit/s. Corresponds to a DBTP
 | ||||||
|  |         // register value of 0x0000_0A33
 | ||||||
|  |         Self { | ||||||
|  |             transceiver_delay_compensation: false, | ||||||
|  |             prescaler: NonZeroU16::new(1).unwrap(), | ||||||
|  |             seg1: NonZeroU8::new(11).unwrap(), | ||||||
|  |             seg2: NonZeroU8::new(4).unwrap(), | ||||||
|  |             sync_jump_width: NonZeroU8::new(4).unwrap(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Configures which modes to use
 | ||||||
|  | /// Individual headers can contain a desire to be send via FdCan
 | ||||||
|  | /// or use Bit rate switching. But if this general setting does not allow
 | ||||||
|  | /// that, only classic CAN is used instead.
 | ||||||
|  | #[derive(Clone, Copy, Debug)] | ||||||
|  | pub enum FrameTransmissionConfig { | ||||||
|  |     /// Only allow Classic CAN message Frames
 | ||||||
|  |     ClassicCanOnly, | ||||||
|  |     /// Allow (non-brs) FdCAN Message Frames
 | ||||||
|  |     AllowFdCan, | ||||||
|  |     /// Allow FdCAN Message Frames and allow Bit Rate Switching
 | ||||||
|  |     AllowFdCanAndBRS, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ///
 | ||||||
|  | #[derive(Clone, Copy, Debug)] | ||||||
|  | pub enum ClockDivider { | ||||||
|  |     /// Divide by 1
 | ||||||
|  |     _1 = 0b0000, | ||||||
|  |     /// Divide by 2
 | ||||||
|  |     _2 = 0b0001, | ||||||
|  |     /// Divide by 4
 | ||||||
|  |     _4 = 0b0010, | ||||||
|  |     /// Divide by 6
 | ||||||
|  |     _6 = 0b0011, | ||||||
|  |     /// Divide by 8
 | ||||||
|  |     _8 = 0b0100, | ||||||
|  |     /// Divide by 10
 | ||||||
|  |     _10 = 0b0101, | ||||||
|  |     /// Divide by 12
 | ||||||
|  |     _12 = 0b0110, | ||||||
|  |     /// Divide by 14
 | ||||||
|  |     _14 = 0b0111, | ||||||
|  |     /// Divide by 16
 | ||||||
|  |     _16 = 0b1000, | ||||||
|  |     /// Divide by 18
 | ||||||
|  |     _18 = 0b1001, | ||||||
|  |     /// Divide by 20
 | ||||||
|  |     _20 = 0b1010, | ||||||
|  |     /// Divide by 22
 | ||||||
|  |     _22 = 0b1011, | ||||||
|  |     /// Divide by 24
 | ||||||
|  |     _24 = 0b1100, | ||||||
|  |     /// Divide by 26
 | ||||||
|  |     _26 = 0b1101, | ||||||
|  |     /// Divide by 28
 | ||||||
|  |     _28 = 0b1110, | ||||||
|  |     /// Divide by 30
 | ||||||
|  |     _30 = 0b1111, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Prescaler of the Timestamp counter
 | ||||||
|  | #[derive(Clone, Copy, Debug)] | ||||||
|  | pub enum TimestampPrescaler { | ||||||
|  |     /// 1
 | ||||||
|  |     _1 = 1, | ||||||
|  |     /// 2
 | ||||||
|  |     _2 = 2, | ||||||
|  |     /// 3
 | ||||||
|  |     _3 = 3, | ||||||
|  |     /// 4
 | ||||||
|  |     _4 = 4, | ||||||
|  |     /// 5
 | ||||||
|  |     _5 = 5, | ||||||
|  |     /// 6
 | ||||||
|  |     _6 = 6, | ||||||
|  |     /// 7
 | ||||||
|  |     _7 = 7, | ||||||
|  |     /// 8
 | ||||||
|  |     _8 = 8, | ||||||
|  |     /// 9
 | ||||||
|  |     _9 = 9, | ||||||
|  |     /// 10
 | ||||||
|  |     _10 = 10, | ||||||
|  |     /// 11
 | ||||||
|  |     _11 = 11, | ||||||
|  |     /// 12
 | ||||||
|  |     _12 = 12, | ||||||
|  |     /// 13
 | ||||||
|  |     _13 = 13, | ||||||
|  |     /// 14
 | ||||||
|  |     _14 = 14, | ||||||
|  |     /// 15
 | ||||||
|  |     _15 = 15, | ||||||
|  |     /// 16
 | ||||||
|  |     _16 = 16, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Selects the source of the Timestamp counter
 | ||||||
|  | #[derive(Clone, Copy, Debug)] | ||||||
|  | pub enum TimestampSource { | ||||||
|  |     /// The Timestamp counter is disabled
 | ||||||
|  |     None, | ||||||
|  |     /// Using the FdCan input clock as the Timstamp counter's source,
 | ||||||
|  |     /// and using a specific prescaler
 | ||||||
|  |     Prescaler(TimestampPrescaler), | ||||||
|  |     /// Using TIM3 as a source
 | ||||||
|  |     FromTIM3, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// How to handle frames in the global filter
 | ||||||
|  | #[derive(Clone, Copy, Debug)] | ||||||
|  | pub enum NonMatchingFilter { | ||||||
|  |     /// Frames will go to Fifo0 when they do no match any specific filter
 | ||||||
|  |     IntoRxFifo0 = 0b00, | ||||||
|  |     /// Frames will go to Fifo1 when they do no match any specific filter
 | ||||||
|  |     IntoRxFifo1 = 0b01, | ||||||
|  |     /// Frames will be rejected when they do not match any specific filter
 | ||||||
|  |     Reject = 0b11, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// How to handle frames which do not match a specific filter
 | ||||||
|  | #[derive(Clone, Copy, Debug)] | ||||||
|  | pub struct GlobalFilter { | ||||||
|  |     /// How to handle non-matching standard frames
 | ||||||
|  |     pub handle_standard_frames: NonMatchingFilter, | ||||||
|  | 
 | ||||||
|  |     /// How to handle non-matching extended frames
 | ||||||
|  |     pub handle_extended_frames: NonMatchingFilter, | ||||||
|  | 
 | ||||||
|  |     /// How to handle remote standard frames
 | ||||||
|  |     pub reject_remote_standard_frames: bool, | ||||||
|  | 
 | ||||||
|  |     /// How to handle remote extended frames
 | ||||||
|  |     pub reject_remote_extended_frames: bool, | ||||||
|  | } | ||||||
|  | impl GlobalFilter { | ||||||
|  |     /// Reject all non-matching and remote frames
 | ||||||
|  |     pub const fn reject_all() -> Self { | ||||||
|  |         Self { | ||||||
|  |             handle_standard_frames: NonMatchingFilter::Reject, | ||||||
|  |             handle_extended_frames: NonMatchingFilter::Reject, | ||||||
|  |             reject_remote_standard_frames: true, | ||||||
|  |             reject_remote_extended_frames: true, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// How to handle non-matching standard frames
 | ||||||
|  |     pub const fn set_handle_standard_frames(mut self, filter: NonMatchingFilter) -> Self { | ||||||
|  |         self.handle_standard_frames = filter; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  |     /// How to handle non-matching exteded frames
 | ||||||
|  |     pub const fn set_handle_extended_frames(mut self, filter: NonMatchingFilter) -> Self { | ||||||
|  |         self.handle_extended_frames = filter; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  |     /// How to handle remote standard frames
 | ||||||
|  |     pub const fn set_reject_remote_standard_frames(mut self, filter: bool) -> Self { | ||||||
|  |         self.reject_remote_standard_frames = filter; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  |     /// How to handle remote extended frames
 | ||||||
|  |     pub const fn set_reject_remote_extended_frames(mut self, filter: bool) -> Self { | ||||||
|  |         self.reject_remote_extended_frames = filter; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | impl Default for GlobalFilter { | ||||||
|  |     #[inline] | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self { | ||||||
|  |             handle_standard_frames: NonMatchingFilter::IntoRxFifo0, | ||||||
|  |             handle_extended_frames: NonMatchingFilter::IntoRxFifo0, | ||||||
|  |             reject_remote_standard_frames: false, | ||||||
|  |             reject_remote_extended_frames: false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// FdCan Config Struct
 | ||||||
|  | #[derive(Clone, Copy, Debug)] | ||||||
|  | pub struct FdCanConfig { | ||||||
|  |     /// Nominal Bit Timings
 | ||||||
|  |     pub nbtr: NominalBitTiming, | ||||||
|  |     /// (Variable) Data Bit Timings
 | ||||||
|  |     pub dbtr: DataBitTiming, | ||||||
|  |     /// Enables or disables automatic retransmission of messages
 | ||||||
|  |     ///
 | ||||||
|  |     /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
 | ||||||
|  |     /// util it can be sent. Otherwise, it will try only once to send each frame.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Automatic retransmission is enabled by default.
 | ||||||
|  |     pub automatic_retransmit: bool, | ||||||
|  |     /// Enabled or disables the pausing between transmissions
 | ||||||
|  |     ///
 | ||||||
|  |     /// This feature looses up burst transmissions coming from a single node and it protects against
 | ||||||
|  |     /// "babbling idiot" scenarios where the application program erroneously requests too many
 | ||||||
|  |     /// transmissions.
 | ||||||
|  |     pub transmit_pause: bool, | ||||||
|  |     /// Enabled or disables the pausing between transmissions
 | ||||||
|  |     ///
 | ||||||
|  |     /// This feature looses up burst transmissions coming from a single node and it protects against
 | ||||||
|  |     /// "babbling idiot" scenarios where the application program erroneously requests too many
 | ||||||
|  |     /// transmissions.
 | ||||||
|  |     pub frame_transmit: FrameTransmissionConfig, | ||||||
|  |     /// Non Isoe Mode
 | ||||||
|  |     /// If this is set, the FDCAN uses the CAN FD frame format as specified by the Bosch CAN
 | ||||||
|  |     /// FD Specification V1.0.
 | ||||||
|  |     pub non_iso_mode: bool, | ||||||
|  |     /// Edge Filtering: Two consecutive dominant tq required to detect an edge for hard synchronization
 | ||||||
|  |     pub edge_filtering: bool, | ||||||
|  |     /// Enables protocol exception handling
 | ||||||
|  |     pub protocol_exception_handling: bool, | ||||||
|  |     /// Sets the general clock divider for this FdCAN instance
 | ||||||
|  |     pub clock_divider: ClockDivider, | ||||||
|  |     /// Sets the timestamp source
 | ||||||
|  |     pub timestamp_source: TimestampSource, | ||||||
|  |     /// Configures the Global Filter
 | ||||||
|  |     pub global_filter: GlobalFilter, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl FdCanConfig { | ||||||
|  |     /// Configures the bit timings.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub const fn set_nominal_bit_timing(mut self, btr: NominalBitTiming) -> Self { | ||||||
|  |         self.nbtr = btr; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Configures the bit timings.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub const fn set_data_bit_timing(mut self, btr: DataBitTiming) -> Self { | ||||||
|  |         self.dbtr = btr; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Enables or disables automatic retransmission of messages
 | ||||||
|  |     ///
 | ||||||
|  |     /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
 | ||||||
|  |     /// util it can be sent. Otherwise, it will try only once to send each frame.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Automatic retransmission is enabled by default.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub const fn set_automatic_retransmit(mut self, enabled: bool) -> Self { | ||||||
|  |         self.automatic_retransmit = enabled; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Enabled or disables the pausing between transmissions
 | ||||||
|  |     ///
 | ||||||
|  |     /// This feature looses up burst transmissions coming from a single node and it protects against
 | ||||||
|  |     /// "babbling idiot" scenarios where the application program erroneously requests too many
 | ||||||
|  |     /// transmissions.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub const fn set_transmit_pause(mut self, enabled: bool) -> Self { | ||||||
|  |         self.transmit_pause = enabled; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// If this is set, the FDCAN uses the CAN FD frame format as specified by the Bosch CAN
 | ||||||
|  |     /// FD Specification V1.0.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub const fn set_non_iso_mode(mut self, enabled: bool) -> Self { | ||||||
|  |         self.non_iso_mode = enabled; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Two consecutive dominant tq required to detect an edge for hard synchronization
 | ||||||
|  |     #[inline] | ||||||
|  |     pub const fn set_edge_filtering(mut self, enabled: bool) -> Self { | ||||||
|  |         self.edge_filtering = enabled; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Sets the allowed transmission types for messages.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub const fn set_frame_transmit(mut self, fts: FrameTransmissionConfig) -> Self { | ||||||
|  |         self.frame_transmit = fts; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Enables protocol exception handling
 | ||||||
|  |     #[inline] | ||||||
|  |     pub const fn set_protocol_exception_handling(mut self, peh: bool) -> Self { | ||||||
|  |         self.protocol_exception_handling = peh; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Sets the general clock divider for this FdCAN instance
 | ||||||
|  |     #[inline] | ||||||
|  |     pub const fn set_clock_divider(mut self, div: ClockDivider) -> Self { | ||||||
|  |         self.clock_divider = div; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Sets the timestamp source
 | ||||||
|  |     #[inline] | ||||||
|  |     pub const fn set_timestamp_source(mut self, tss: TimestampSource) -> Self { | ||||||
|  |         self.timestamp_source = tss; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Sets the global filter settings
 | ||||||
|  |     #[inline] | ||||||
|  |     pub const fn set_global_filter(mut self, filter: GlobalFilter) -> Self { | ||||||
|  |         self.global_filter = filter; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Default for FdCanConfig { | ||||||
|  |     #[inline] | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self { | ||||||
|  |             nbtr: NominalBitTiming::default(), | ||||||
|  |             dbtr: DataBitTiming::default(), | ||||||
|  |             automatic_retransmit: true, | ||||||
|  |             transmit_pause: false, | ||||||
|  |             frame_transmit: FrameTransmissionConfig::ClassicCanOnly, | ||||||
|  |             non_iso_mode: false, | ||||||
|  |             edge_filtering: false, | ||||||
|  |             protocol_exception_handling: true, | ||||||
|  |             clock_divider: ClockDivider::_1, | ||||||
|  |             timestamp_source: TimestampSource::None, | ||||||
|  |             global_filter: GlobalFilter::default(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										379
									
								
								embassy-stm32/src/can/fd/filter.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										379
									
								
								embassy-stm32/src/can/fd/filter.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,379 @@ | |||||||
|  | //! Definition of Filter structs for FDCAN Module
 | ||||||
|  | //! Note: This file is copied and modified from fdcan crate by Richard Meadows
 | ||||||
|  | 
 | ||||||
|  | use embedded_can::{ExtendedId, StandardId}; | ||||||
|  | 
 | ||||||
|  | use crate::can::fd::message_ram; | ||||||
|  | pub use crate::can::fd::message_ram::{EXTENDED_FILTER_MAX, STANDARD_FILTER_MAX}; | ||||||
|  | 
 | ||||||
|  | /// A Standard Filter
 | ||||||
|  | pub type StandardFilter = Filter<StandardId, u16>; | ||||||
|  | /// An Extended Filter
 | ||||||
|  | pub type ExtendedFilter = Filter<ExtendedId, u32>; | ||||||
|  | 
 | ||||||
|  | impl Default for StandardFilter { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         StandardFilter::disable() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | impl Default for ExtendedFilter { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         ExtendedFilter::disable() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl StandardFilter { | ||||||
|  |     /// Accept all messages in FIFO 0
 | ||||||
|  |     pub fn accept_all_into_fifo0() -> StandardFilter { | ||||||
|  |         StandardFilter { | ||||||
|  |             filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, | ||||||
|  |             action: Action::StoreInFifo0, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Accept all messages in FIFO 1
 | ||||||
|  |     pub fn accept_all_into_fifo1() -> StandardFilter { | ||||||
|  |         StandardFilter { | ||||||
|  |             filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, | ||||||
|  |             action: Action::StoreInFifo1, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Reject all messages
 | ||||||
|  |     pub fn reject_all() -> StandardFilter { | ||||||
|  |         StandardFilter { | ||||||
|  |             filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, | ||||||
|  |             action: Action::Reject, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Disable the filter
 | ||||||
|  |     pub fn disable() -> StandardFilter { | ||||||
|  |         StandardFilter { | ||||||
|  |             filter: FilterType::Disabled, | ||||||
|  |             action: Action::Disable, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ExtendedFilter { | ||||||
|  |     /// Accept all messages in FIFO 0
 | ||||||
|  |     pub fn accept_all_into_fifo0() -> ExtendedFilter { | ||||||
|  |         ExtendedFilter { | ||||||
|  |             filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, | ||||||
|  |             action: Action::StoreInFifo0, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Accept all messages in FIFO 1
 | ||||||
|  |     pub fn accept_all_into_fifo1() -> ExtendedFilter { | ||||||
|  |         ExtendedFilter { | ||||||
|  |             filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, | ||||||
|  |             action: Action::StoreInFifo1, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Reject all messages
 | ||||||
|  |     pub fn reject_all() -> ExtendedFilter { | ||||||
|  |         ExtendedFilter { | ||||||
|  |             filter: FilterType::BitMask { filter: 0x0, mask: 0x0 }, | ||||||
|  |             action: Action::Reject, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Disable the filter
 | ||||||
|  |     pub fn disable() -> ExtendedFilter { | ||||||
|  |         ExtendedFilter { | ||||||
|  |             filter: FilterType::Disabled, | ||||||
|  |             action: Action::Disable, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Filter Type
 | ||||||
|  | #[derive(Clone, Copy, Debug)] | ||||||
|  | pub enum FilterType<ID, UNIT> | ||||||
|  | where | ||||||
|  |     ID: Copy + Clone + core::fmt::Debug, | ||||||
|  |     UNIT: Copy + Clone + core::fmt::Debug, | ||||||
|  | { | ||||||
|  |     /// Match with a range between two messages
 | ||||||
|  |     Range { | ||||||
|  |         /// First Id of the range
 | ||||||
|  |         from: ID, | ||||||
|  |         /// Last Id of the range
 | ||||||
|  |         to: ID, | ||||||
|  |     }, | ||||||
|  |     /// Match with a bitmask
 | ||||||
|  |     BitMask { | ||||||
|  |         /// Filter of the bitmask
 | ||||||
|  |         filter: UNIT, | ||||||
|  |         /// Mask of the bitmask
 | ||||||
|  |         mask: UNIT, | ||||||
|  |     }, | ||||||
|  |     /// Match with a single ID
 | ||||||
|  |     DedicatedSingle(ID), | ||||||
|  |     /// Match with one of two ID's
 | ||||||
|  |     DedicatedDual(ID, ID), | ||||||
|  |     /// Filter is disabled
 | ||||||
|  |     Disabled, | ||||||
|  | } | ||||||
|  | impl<ID, UNIT> From<FilterType<ID, UNIT>> for message_ram::enums::FilterType | ||||||
|  | where | ||||||
|  |     ID: Copy + Clone + core::fmt::Debug, | ||||||
|  |     UNIT: Copy + Clone + core::fmt::Debug, | ||||||
|  | { | ||||||
|  |     fn from(f: FilterType<ID, UNIT>) -> Self { | ||||||
|  |         match f { | ||||||
|  |             FilterType::Range { to: _, from: _ } => Self::RangeFilter, | ||||||
|  |             FilterType::BitMask { filter: _, mask: _ } => Self::ClassicFilter, | ||||||
|  |             FilterType::DedicatedSingle(_) => Self::DualIdFilter, | ||||||
|  |             FilterType::DedicatedDual(_, _) => Self::DualIdFilter, | ||||||
|  |             FilterType::Disabled => Self::FilterDisabled, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Filter Action
 | ||||||
|  | #[derive(Clone, Copy, Debug)] | ||||||
|  | pub enum Action { | ||||||
|  |     /// No Action
 | ||||||
|  |     Disable = 0b000, | ||||||
|  |     /// Store an matching message in FIFO 0
 | ||||||
|  |     StoreInFifo0 = 0b001, | ||||||
|  |     /// Store an matching message in FIFO 1
 | ||||||
|  |     StoreInFifo1 = 0b010, | ||||||
|  |     /// Reject an matching message
 | ||||||
|  |     Reject = 0b011, | ||||||
|  |     /// Flag a matching message (But not store?!?)
 | ||||||
|  |     FlagHighPrio = 0b100, | ||||||
|  |     /// Flag a matching message as a High Priority message and store it in FIFO 0
 | ||||||
|  |     FlagHighPrioAndStoreInFifo0 = 0b101, | ||||||
|  |     /// Flag a matching message as a High Priority message and store it in FIFO 1
 | ||||||
|  |     FlagHighPrioAndStoreInFifo1 = 0b110, | ||||||
|  | } | ||||||
|  | impl From<Action> for message_ram::enums::FilterElementConfig { | ||||||
|  |     fn from(a: Action) -> Self { | ||||||
|  |         match a { | ||||||
|  |             Action::Disable => Self::DisableFilterElement, | ||||||
|  |             Action::StoreInFifo0 => Self::StoreInFifo0, | ||||||
|  |             Action::StoreInFifo1 => Self::StoreInFifo1, | ||||||
|  |             Action::Reject => Self::Reject, | ||||||
|  |             Action::FlagHighPrio => Self::SetPriority, | ||||||
|  |             Action::FlagHighPrioAndStoreInFifo0 => Self::SetPriorityAndStoreInFifo0, | ||||||
|  |             Action::FlagHighPrioAndStoreInFifo1 => Self::SetPriorityAndStoreInFifo1, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Filter
 | ||||||
|  | #[derive(Clone, Copy, Debug)] | ||||||
|  | pub struct Filter<ID, UNIT> | ||||||
|  | where | ||||||
|  |     ID: Copy + Clone + core::fmt::Debug, | ||||||
|  |     UNIT: Copy + Clone + core::fmt::Debug, | ||||||
|  | { | ||||||
|  |     /// How to match an incoming message
 | ||||||
|  |     pub filter: FilterType<ID, UNIT>, | ||||||
|  |     /// What to do with a matching message
 | ||||||
|  |     pub action: Action, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Standard Filter Slot
 | ||||||
|  | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||||||
|  | pub enum StandardFilterSlot { | ||||||
|  |     /// 0
 | ||||||
|  |     _0 = 0, | ||||||
|  |     /// 1
 | ||||||
|  |     _1 = 1, | ||||||
|  |     /// 2
 | ||||||
|  |     _2 = 2, | ||||||
|  |     /// 3
 | ||||||
|  |     _3 = 3, | ||||||
|  |     /// 4
 | ||||||
|  |     _4 = 4, | ||||||
|  |     /// 5
 | ||||||
|  |     _5 = 5, | ||||||
|  |     /// 6
 | ||||||
|  |     _6 = 6, | ||||||
|  |     /// 7
 | ||||||
|  |     _7 = 7, | ||||||
|  |     /// 8
 | ||||||
|  |     _8 = 8, | ||||||
|  |     /// 9
 | ||||||
|  |     _9 = 9, | ||||||
|  |     /// 10
 | ||||||
|  |     _10 = 10, | ||||||
|  |     /// 11
 | ||||||
|  |     _11 = 11, | ||||||
|  |     /// 12
 | ||||||
|  |     _12 = 12, | ||||||
|  |     /// 13
 | ||||||
|  |     _13 = 13, | ||||||
|  |     /// 14
 | ||||||
|  |     _14 = 14, | ||||||
|  |     /// 15
 | ||||||
|  |     _15 = 15, | ||||||
|  |     /// 16
 | ||||||
|  |     _16 = 16, | ||||||
|  |     /// 17
 | ||||||
|  |     _17 = 17, | ||||||
|  |     /// 18
 | ||||||
|  |     _18 = 18, | ||||||
|  |     /// 19
 | ||||||
|  |     _19 = 19, | ||||||
|  |     /// 20
 | ||||||
|  |     _20 = 20, | ||||||
|  |     /// 21
 | ||||||
|  |     _21 = 21, | ||||||
|  |     /// 22
 | ||||||
|  |     _22 = 22, | ||||||
|  |     /// 23
 | ||||||
|  |     _23 = 23, | ||||||
|  |     /// 24
 | ||||||
|  |     _24 = 24, | ||||||
|  |     /// 25
 | ||||||
|  |     _25 = 25, | ||||||
|  |     /// 26
 | ||||||
|  |     _26 = 26, | ||||||
|  |     /// 27
 | ||||||
|  |     _27 = 27, | ||||||
|  | } | ||||||
|  | impl From<u8> for StandardFilterSlot { | ||||||
|  |     fn from(u: u8) -> Self { | ||||||
|  |         match u { | ||||||
|  |             0 => StandardFilterSlot::_0, | ||||||
|  |             1 => StandardFilterSlot::_1, | ||||||
|  |             2 => StandardFilterSlot::_2, | ||||||
|  |             3 => StandardFilterSlot::_3, | ||||||
|  |             4 => StandardFilterSlot::_4, | ||||||
|  |             5 => StandardFilterSlot::_5, | ||||||
|  |             6 => StandardFilterSlot::_6, | ||||||
|  |             7 => StandardFilterSlot::_7, | ||||||
|  |             8 => StandardFilterSlot::_8, | ||||||
|  |             9 => StandardFilterSlot::_9, | ||||||
|  |             10 => StandardFilterSlot::_10, | ||||||
|  |             11 => StandardFilterSlot::_11, | ||||||
|  |             12 => StandardFilterSlot::_12, | ||||||
|  |             13 => StandardFilterSlot::_13, | ||||||
|  |             14 => StandardFilterSlot::_14, | ||||||
|  |             15 => StandardFilterSlot::_15, | ||||||
|  |             16 => StandardFilterSlot::_16, | ||||||
|  |             17 => StandardFilterSlot::_17, | ||||||
|  |             18 => StandardFilterSlot::_18, | ||||||
|  |             19 => StandardFilterSlot::_19, | ||||||
|  |             20 => StandardFilterSlot::_20, | ||||||
|  |             21 => StandardFilterSlot::_21, | ||||||
|  |             22 => StandardFilterSlot::_22, | ||||||
|  |             23 => StandardFilterSlot::_23, | ||||||
|  |             24 => StandardFilterSlot::_24, | ||||||
|  |             25 => StandardFilterSlot::_25, | ||||||
|  |             26 => StandardFilterSlot::_26, | ||||||
|  |             27 => StandardFilterSlot::_27, | ||||||
|  |             _ => panic!("Standard Filter Slot Too High!"), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Extended Filter Slot
 | ||||||
|  | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||||||
|  | pub enum ExtendedFilterSlot { | ||||||
|  |     /// 0
 | ||||||
|  |     _0 = 0, | ||||||
|  |     /// 1
 | ||||||
|  |     _1 = 1, | ||||||
|  |     /// 2
 | ||||||
|  |     _2 = 2, | ||||||
|  |     /// 3
 | ||||||
|  |     _3 = 3, | ||||||
|  |     /// 4
 | ||||||
|  |     _4 = 4, | ||||||
|  |     /// 5
 | ||||||
|  |     _5 = 5, | ||||||
|  |     /// 6
 | ||||||
|  |     _6 = 6, | ||||||
|  |     /// 7
 | ||||||
|  |     _7 = 7, | ||||||
|  | } | ||||||
|  | impl From<u8> for ExtendedFilterSlot { | ||||||
|  |     fn from(u: u8) -> Self { | ||||||
|  |         match u { | ||||||
|  |             0 => ExtendedFilterSlot::_0, | ||||||
|  |             1 => ExtendedFilterSlot::_1, | ||||||
|  |             2 => ExtendedFilterSlot::_2, | ||||||
|  |             3 => ExtendedFilterSlot::_3, | ||||||
|  |             4 => ExtendedFilterSlot::_4, | ||||||
|  |             5 => ExtendedFilterSlot::_5, | ||||||
|  |             6 => ExtendedFilterSlot::_6, | ||||||
|  |             7 => ExtendedFilterSlot::_7, | ||||||
|  |             _ => panic!("Extended Filter Slot Too High!"), // Should be unreachable
 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Enum over both Standard and Extended Filter ID's
 | ||||||
|  | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||||||
|  | pub enum FilterId { | ||||||
|  |     /// Standard Filter Slots
 | ||||||
|  |     Standard(StandardFilterSlot), | ||||||
|  |     /// Extended Filter Slots
 | ||||||
|  |     Extended(ExtendedFilterSlot), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) trait ActivateFilter<ID, UNIT> | ||||||
|  | where | ||||||
|  |     ID: Copy + Clone + core::fmt::Debug, | ||||||
|  |     UNIT: Copy + Clone + core::fmt::Debug, | ||||||
|  | { | ||||||
|  |     fn activate(&mut self, f: Filter<ID, UNIT>); | ||||||
|  |     // fn read(&self) -> Filter<ID, UNIT>;
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ActivateFilter<StandardId, u16> for message_ram::StandardFilter { | ||||||
|  |     fn activate(&mut self, f: Filter<StandardId, u16>) { | ||||||
|  |         let sft = f.filter.into(); | ||||||
|  | 
 | ||||||
|  |         let (sfid1, sfid2) = match f.filter { | ||||||
|  |             FilterType::Range { to, from } => (to.as_raw(), from.as_raw()), | ||||||
|  |             FilterType::DedicatedSingle(id) => (id.as_raw(), id.as_raw()), | ||||||
|  |             FilterType::DedicatedDual(id1, id2) => (id1.as_raw(), id2.as_raw()), | ||||||
|  |             FilterType::BitMask { filter, mask } => (filter, mask), | ||||||
|  |             FilterType::Disabled => (0x0, 0x0), | ||||||
|  |         }; | ||||||
|  |         let sfec = f.action.into(); | ||||||
|  |         self.write(|w| { | ||||||
|  |             unsafe { w.sfid1().bits(sfid1).sfid2().bits(sfid2) } | ||||||
|  |                 .sft() | ||||||
|  |                 .set_filter_type(sft) | ||||||
|  |                 .sfec() | ||||||
|  |                 .set_filter_element_config(sfec) | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |     // fn read(&self) -> Filter<StandardId, u16> {
 | ||||||
|  |     //     todo!()
 | ||||||
|  |     // }
 | ||||||
|  | } | ||||||
|  | impl ActivateFilter<ExtendedId, u32> for message_ram::ExtendedFilter { | ||||||
|  |     fn activate(&mut self, f: Filter<ExtendedId, u32>) { | ||||||
|  |         let eft = f.filter.into(); | ||||||
|  | 
 | ||||||
|  |         let (efid1, efid2) = match f.filter { | ||||||
|  |             FilterType::Range { to, from } => (to.as_raw(), from.as_raw()), | ||||||
|  |             FilterType::DedicatedSingle(id) => (id.as_raw(), id.as_raw()), | ||||||
|  |             FilterType::DedicatedDual(id1, id2) => (id1.as_raw(), id2.as_raw()), | ||||||
|  |             FilterType::BitMask { filter, mask } => (filter, mask), | ||||||
|  |             FilterType::Disabled => (0x0, 0x0), | ||||||
|  |         }; | ||||||
|  |         let efec = f.action.into(); | ||||||
|  |         self.write(|w| { | ||||||
|  |             unsafe { w.efid1().bits(efid1).efid2().bits(efid2) } | ||||||
|  |                 .eft() | ||||||
|  |                 .set_filter_type(eft) | ||||||
|  |                 .efec() | ||||||
|  |                 .set_filter_element_config(efec) | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |     // fn read(&self) -> Filter<ExtendedId, u32> {
 | ||||||
|  |     //     todo!()
 | ||||||
|  |     // }
 | ||||||
|  | } | ||||||
							
								
								
									
										134
									
								
								embassy-stm32/src/can/fd/message_ram/common.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								embassy-stm32/src/can/fd/message_ram/common.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,134 @@ | |||||||
|  | // Note: This file is copied and modified from fdcan crate by Richard Meadows
 | ||||||
|  | #![allow(non_camel_case_types)] | ||||||
|  | #![allow(non_snake_case)] | ||||||
|  | #![allow(unused)] | ||||||
|  | 
 | ||||||
|  | use super::enums::{ | ||||||
|  |     BitRateSwitching, ErrorStateIndicator, FilterElementConfig, FilterType, FrameFormat, IdType, | ||||||
|  |     RemoteTransmissionRequest, | ||||||
|  | }; | ||||||
|  | use super::generic; | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `ID`"] | ||||||
|  | pub type ID_R = generic::R<u32, u32>; | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `RTR`"] | ||||||
|  | pub type RTR_R = generic::R<bool, RemoteTransmissionRequest>; | ||||||
|  | impl RTR_R { | ||||||
|  |     pub fn rtr(&self) -> RemoteTransmissionRequest { | ||||||
|  |         match self.bits { | ||||||
|  |             false => RemoteTransmissionRequest::TransmitDataFrame, | ||||||
|  |             true => RemoteTransmissionRequest::TransmitRemoteFrame, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn is_transmit_remote_frame(&self) -> bool { | ||||||
|  |         *self == RemoteTransmissionRequest::TransmitRemoteFrame | ||||||
|  |     } | ||||||
|  |     pub fn is_transmit_data_frame(&self) -> bool { | ||||||
|  |         *self == RemoteTransmissionRequest::TransmitDataFrame | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `XTD`"] | ||||||
|  | pub type XTD_R = generic::R<bool, IdType>; | ||||||
|  | impl XTD_R { | ||||||
|  |     pub fn id_type(&self) -> IdType { | ||||||
|  |         match self.bits() { | ||||||
|  |             false => IdType::StandardId, | ||||||
|  |             true => IdType::ExtendedId, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn is_standard_id(&self) -> bool { | ||||||
|  |         *self == IdType::StandardId | ||||||
|  |     } | ||||||
|  |     pub fn is_exteded_id(&self) -> bool { | ||||||
|  |         *self == IdType::ExtendedId | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `ESI`"] | ||||||
|  | pub type ESI_R = generic::R<bool, ErrorStateIndicator>; | ||||||
|  | impl ESI_R { | ||||||
|  |     pub fn error_state(&self) -> ErrorStateIndicator { | ||||||
|  |         match self.bits() { | ||||||
|  |             false => ErrorStateIndicator::ErrorActive, | ||||||
|  |             true => ErrorStateIndicator::ErrorPassive, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn is_error_active(&self) -> bool { | ||||||
|  |         *self == ErrorStateIndicator::ErrorActive | ||||||
|  |     } | ||||||
|  |     pub fn is_error_passive(&self) -> bool { | ||||||
|  |         *self == ErrorStateIndicator::ErrorPassive | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `DLC`"] | ||||||
|  | pub type DLC_R = generic::R<u8, u8>; | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `BRS`"] | ||||||
|  | pub type BRS_R = generic::R<bool, BitRateSwitching>; | ||||||
|  | impl BRS_R { | ||||||
|  |     pub fn bit_rate_switching(&self) -> BitRateSwitching { | ||||||
|  |         match self.bits() { | ||||||
|  |             true => BitRateSwitching::WithBRS, | ||||||
|  |             false => BitRateSwitching::WithoutBRS, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn is_with_brs(&self) -> bool { | ||||||
|  |         *self == BitRateSwitching::WithBRS | ||||||
|  |     } | ||||||
|  |     pub fn is_without_brs(&self) -> bool { | ||||||
|  |         *self == BitRateSwitching::WithoutBRS | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `FDF`"] | ||||||
|  | pub type FDF_R = generic::R<bool, FrameFormat>; | ||||||
|  | impl FDF_R { | ||||||
|  |     pub fn frame_format(&self) -> FrameFormat { | ||||||
|  |         match self.bits() { | ||||||
|  |             false => FrameFormat::Standard, | ||||||
|  |             true => FrameFormat::Fdcan, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn is_standard_format(&self) -> bool { | ||||||
|  |         *self == FrameFormat::Standard | ||||||
|  |     } | ||||||
|  |     pub fn is_fdcan_format(&self) -> bool { | ||||||
|  |         *self == FrameFormat::Fdcan | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `(X|S)FT`"] | ||||||
|  | pub type ESFT_R = generic::R<u8, FilterType>; | ||||||
|  | impl ESFT_R { | ||||||
|  |     #[doc = r"Gets the Filtertype"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn to_filter_type(&self) -> FilterType { | ||||||
|  |         match self.bits() { | ||||||
|  |             0b00 => FilterType::RangeFilter, | ||||||
|  |             0b01 => FilterType::DualIdFilter, | ||||||
|  |             0b10 => FilterType::ClassicFilter, | ||||||
|  |             0b11 => FilterType::FilterDisabled, | ||||||
|  |             _ => unreachable!(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `(E|S)FEC`"] | ||||||
|  | pub type ESFEC_R = generic::R<u8, FilterElementConfig>; | ||||||
|  | impl ESFEC_R { | ||||||
|  |     pub fn to_filter_element_config(&self) -> FilterElementConfig { | ||||||
|  |         match self.bits() { | ||||||
|  |             0b000 => FilterElementConfig::DisableFilterElement, | ||||||
|  |             0b001 => FilterElementConfig::StoreInFifo0, | ||||||
|  |             0b010 => FilterElementConfig::StoreInFifo1, | ||||||
|  |             0b011 => FilterElementConfig::Reject, | ||||||
|  |             0b100 => FilterElementConfig::SetPriority, | ||||||
|  |             0b101 => FilterElementConfig::SetPriorityAndStoreInFifo0, | ||||||
|  |             0b110 => FilterElementConfig::SetPriorityAndStoreInFifo1, | ||||||
|  |             _ => unimplemented!(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										233
									
								
								embassy-stm32/src/can/fd/message_ram/enums.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								embassy-stm32/src/can/fd/message_ram/enums.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,233 @@ | |||||||
|  | // Note: This file is copied and modified from fdcan crate by Richard Meadows
 | ||||||
|  | 
 | ||||||
|  | /// Datalength is the message length generalised over
 | ||||||
|  | /// the Standard (Classic) and FDCAN message types
 | ||||||
|  | 
 | ||||||
|  | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
|  | pub enum DataLength { | ||||||
|  |     Standard(u8), | ||||||
|  |     Fdcan(u8), | ||||||
|  | } | ||||||
|  | impl DataLength { | ||||||
|  |     /// Creates a DataLength type
 | ||||||
|  |     ///
 | ||||||
|  |     /// Uses the byte length and Type of frame as input
 | ||||||
|  |     pub fn new(len: u8, ff: FrameFormat) -> DataLength { | ||||||
|  |         match ff { | ||||||
|  |             FrameFormat::Standard => match len { | ||||||
|  |                 0..=8 => DataLength::Standard(len), | ||||||
|  |                 _ => panic!("DataLength > 8"), | ||||||
|  |             }, | ||||||
|  |             FrameFormat::Fdcan => match len { | ||||||
|  |                 0..=64 => DataLength::Fdcan(len), | ||||||
|  |                 _ => panic!("DataLength > 64"), | ||||||
|  |             }, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     /// Specialised function to create standard frames
 | ||||||
|  |     pub fn new_standard(len: u8) -> DataLength { | ||||||
|  |         Self::new(len, FrameFormat::Standard) | ||||||
|  |     } | ||||||
|  |     /// Specialised function to create FDCAN frames
 | ||||||
|  |     pub fn new_fdcan(len: u8) -> DataLength { | ||||||
|  |         Self::new(len, FrameFormat::Fdcan) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// returns the length in bytes
 | ||||||
|  |     pub fn len(&self) -> u8 { | ||||||
|  |         match self { | ||||||
|  |             DataLength::Standard(l) | DataLength::Fdcan(l) => *l, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub(crate) fn dlc(&self) -> u8 { | ||||||
|  |         match self { | ||||||
|  |             DataLength::Standard(l) => *l, | ||||||
|  |             // See RM0433 Rev 7 Table 475. DLC coding
 | ||||||
|  |             DataLength::Fdcan(l) => match l { | ||||||
|  |                 0..=8 => *l, | ||||||
|  |                 9..=12 => 9, | ||||||
|  |                 13..=16 => 10, | ||||||
|  |                 17..=20 => 11, | ||||||
|  |                 21..=24 => 12, | ||||||
|  |                 25..=32 => 13, | ||||||
|  |                 33..=48 => 14, | ||||||
|  |                 49..=64 => 15, | ||||||
|  |                 _ => panic!("DataLength > 64"), | ||||||
|  |             }, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | impl From<DataLength> for FrameFormat { | ||||||
|  |     fn from(dl: DataLength) -> FrameFormat { | ||||||
|  |         match dl { | ||||||
|  |             DataLength::Standard(_) => FrameFormat::Standard, | ||||||
|  |             DataLength::Fdcan(_) => FrameFormat::Fdcan, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Wheter or not to generate an Tx Event
 | ||||||
|  | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
|  | pub enum Event { | ||||||
|  |     /// Do not generate an Tx Event
 | ||||||
|  |     NoEvent, | ||||||
|  |     /// Generate an Tx Event with a specified ID
 | ||||||
|  |     Event(u8), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<Event> for EventControl { | ||||||
|  |     fn from(e: Event) -> Self { | ||||||
|  |         match e { | ||||||
|  |             Event::NoEvent => EventControl::DoNotStore, | ||||||
|  |             Event::Event(_) => EventControl::Store, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<Option<u8>> for Event { | ||||||
|  |     fn from(mm: Option<u8>) -> Self { | ||||||
|  |         match mm { | ||||||
|  |             None => Event::NoEvent, | ||||||
|  |             Some(mm) => Event::Event(mm), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<Event> for Option<u8> { | ||||||
|  |     fn from(e: Event) -> Option<u8> { | ||||||
|  |         match e { | ||||||
|  |             Event::NoEvent => None, | ||||||
|  |             Event::Event(mm) => Some(mm), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// TODO
 | ||||||
|  | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
|  | pub enum ErrorStateIndicator { | ||||||
|  |     /// TODO
 | ||||||
|  |     ErrorActive = 0, | ||||||
|  |     /// TODO
 | ||||||
|  |     ErrorPassive = 1, | ||||||
|  | } | ||||||
|  | impl From<ErrorStateIndicator> for bool { | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn from(e: ErrorStateIndicator) -> Self { | ||||||
|  |         e as u8 != 0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Type of frame, standard (classic) or FdCAN
 | ||||||
|  | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
|  | pub enum FrameFormat { | ||||||
|  |     Standard = 0, | ||||||
|  |     Fdcan = 1, | ||||||
|  | } | ||||||
|  | impl From<FrameFormat> for bool { | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn from(e: FrameFormat) -> Self { | ||||||
|  |         e as u8 != 0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Type of Id, Standard or Extended
 | ||||||
|  | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
|  | pub enum IdType { | ||||||
|  |     /// Standard ID
 | ||||||
|  |     StandardId = 0, | ||||||
|  |     /// Extended ID
 | ||||||
|  |     ExtendedId = 1, | ||||||
|  | } | ||||||
|  | impl From<IdType> for bool { | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn from(e: IdType) -> Self { | ||||||
|  |         e as u8 != 0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Whether the frame contains data or requests data
 | ||||||
|  | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
|  | pub enum RemoteTransmissionRequest { | ||||||
|  |     /// Frame contains data
 | ||||||
|  |     TransmitDataFrame = 0, | ||||||
|  |     /// frame does not contain data
 | ||||||
|  |     TransmitRemoteFrame = 1, | ||||||
|  | } | ||||||
|  | impl From<RemoteTransmissionRequest> for bool { | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn from(e: RemoteTransmissionRequest) -> Self { | ||||||
|  |         e as u8 != 0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Whether BitRateSwitching should be or was enabled
 | ||||||
|  | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
|  | pub enum BitRateSwitching { | ||||||
|  |     /// disable bit rate switching
 | ||||||
|  |     WithoutBRS = 0, | ||||||
|  |     /// enable bit rate switching
 | ||||||
|  |     WithBRS = 1, | ||||||
|  | } | ||||||
|  | impl From<BitRateSwitching> for bool { | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn from(e: BitRateSwitching) -> Self { | ||||||
|  |         e as u8 != 0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Whether to store transmit Events
 | ||||||
|  | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
|  | pub enum EventControl { | ||||||
|  |     /// do not store an tx event
 | ||||||
|  |     DoNotStore, | ||||||
|  |     /// store transmit events
 | ||||||
|  |     Store, | ||||||
|  | } | ||||||
|  | impl From<EventControl> for bool { | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn from(e: EventControl) -> Self { | ||||||
|  |         e as u8 != 0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// If an received message matched any filters
 | ||||||
|  | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
|  | pub enum FilterFrameMatch { | ||||||
|  |     /// This did match filter <id>
 | ||||||
|  |     DidMatch(u8), | ||||||
|  |     /// This received frame did not match any specific filters
 | ||||||
|  |     DidNotMatch, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Type of filter to be used
 | ||||||
|  | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
|  | pub enum FilterType { | ||||||
|  |     /// Filter uses the range between two id's
 | ||||||
|  |     RangeFilter = 0b00, | ||||||
|  |     /// The filter matches on two specific id's (or one ID checked twice)
 | ||||||
|  |     DualIdFilter = 0b01, | ||||||
|  |     /// Filter is using a bitmask
 | ||||||
|  |     ClassicFilter = 0b10, | ||||||
|  |     /// Filter is disabled
 | ||||||
|  |     FilterDisabled = 0b11, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
|  | pub enum FilterElementConfig { | ||||||
|  |     /// Filter is disabled
 | ||||||
|  |     DisableFilterElement = 0b000, | ||||||
|  |     /// Store a matching message in FIFO 0
 | ||||||
|  |     StoreInFifo0 = 0b001, | ||||||
|  |     /// Store a matching message in FIFO 1
 | ||||||
|  |     StoreInFifo1 = 0b010, | ||||||
|  |     /// Reject a matching message
 | ||||||
|  |     Reject = 0b011, | ||||||
|  |     /// Flag that a priority message has been received, *But do note store!*??
 | ||||||
|  |     SetPriority = 0b100, | ||||||
|  |     /// Flag and store message in FIFO 0
 | ||||||
|  |     SetPriorityAndStoreInFifo0 = 0b101, | ||||||
|  |     /// Flag and store message in FIFO 1
 | ||||||
|  |     SetPriorityAndStoreInFifo1 = 0b110, | ||||||
|  |     //_Unused = 0b111,
 | ||||||
|  | } | ||||||
							
								
								
									
										136
									
								
								embassy-stm32/src/can/fd/message_ram/extended_filter.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								embassy-stm32/src/can/fd/message_ram/extended_filter.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,136 @@ | |||||||
|  | // Note: This file is copied and modified from fdcan crate by Richard Meadows
 | ||||||
|  | 
 | ||||||
|  | #![allow(non_camel_case_types)] | ||||||
|  | #![allow(non_snake_case)] | ||||||
|  | #![allow(unused)] | ||||||
|  | 
 | ||||||
|  | use super::common::{ESFEC_R, ESFT_R}; | ||||||
|  | use super::enums::{FilterElementConfig, FilterType}; | ||||||
|  | use super::generic; | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of register ExtendedFilter"] | ||||||
|  | pub(crate) type R = generic::R<super::ExtendedFilterType, super::ExtendedFilter>; | ||||||
|  | #[doc = "Writer for register ExtendedFilter"] | ||||||
|  | pub(crate) type W = generic::W<super::ExtendedFilterType, super::ExtendedFilter>; | ||||||
|  | #[doc = "Register ExtendedFilter `reset()`'s"] | ||||||
|  | impl generic::ResetValue for super::ExtendedFilter { | ||||||
|  |     type Type = super::ExtendedFilterType; | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn reset_value() -> Self::Type { | ||||||
|  |         // Sets filter element to Disabled
 | ||||||
|  |         [0x0, 0x0] | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `EFID2`"] | ||||||
|  | pub(crate) type EFID2_R = generic::R<u32, u32>; | ||||||
|  | #[doc = "Write proxy for field `EFID2`"] | ||||||
|  | pub(crate) struct EFID2_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> EFID2_W<'a> { | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub unsafe fn bits(self, value: u32) -> &'a mut W { | ||||||
|  |         self.w.bits[1] = (self.w.bits[1] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `EFID1`"] | ||||||
|  | pub(crate) type EFID1_R = generic::R<u32, u32>; | ||||||
|  | #[doc = "Write proxy for field `EFID1`"] | ||||||
|  | pub(crate) struct EFID1_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> EFID1_W<'a> { | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub unsafe fn bits(self, value: u32) -> &'a mut W { | ||||||
|  |         self.w.bits[0] = (self.w.bits[0] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Write proxy for field `EFEC`"] | ||||||
|  | pub(crate) struct EFEC_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> EFEC_W<'a> { | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub unsafe fn bits(self, value: u8) -> &'a mut W { | ||||||
|  |         self.w.bits[0] = (self.w.bits[0] & !(0x07 << 29)) | (((value as u32) & 0x07) << 29); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  |     #[doc = r"Sets the field according to FilterElementConfig"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn set_filter_element_config(self, fec: FilterElementConfig) -> &'a mut W { | ||||||
|  |         //SAFETY: FilterElementConfig only be valid options
 | ||||||
|  |         unsafe { self.bits(fec as u8) } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Write proxy for field `EFT`"] | ||||||
|  | pub(crate) struct EFT_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> EFT_W<'a> { | ||||||
|  |     #[doc = r"Sets the field according the FilterType"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn set_filter_type(self, filter: FilterType) -> &'a mut W { | ||||||
|  |         //SAFETY: FilterType only be valid options
 | ||||||
|  |         unsafe { self.bits(filter as u8) } | ||||||
|  |     } | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub unsafe fn bits(self, value: u8) -> &'a mut W { | ||||||
|  |         self.w.bits[1] = (self.w.bits[1] & !(0x03 << 30)) | (((value as u32) & 0x03) << 30); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl R { | ||||||
|  |     #[doc = "Byte 0 - Bits 0:28 - EFID1"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn sfid1(&self) -> EFID1_R { | ||||||
|  |         EFID1_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 0 - Bits 29:31 - EFEC"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn efec(&self) -> ESFEC_R { | ||||||
|  |         ESFEC_R::new(((self.bits[0] >> 29) & 0x07) as u8) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 0:28 - EFID2"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn sfid2(&self) -> EFID2_R { | ||||||
|  |         EFID2_R::new(((self.bits[1]) & 0x1FFFFFFF) as u32) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 30:31 - EFT"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn eft(&self) -> ESFT_R { | ||||||
|  |         ESFT_R::new(((self.bits[1] >> 30) & 0x03) as u8) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | impl W { | ||||||
|  |     #[doc = "Byte 0 - Bits 0:28 - EFID1"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn efid1(&mut self) -> EFID1_W { | ||||||
|  |         EFID1_W { w: self } | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 0 - Bits 29:31 - EFEC"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn efec(&mut self) -> EFEC_W { | ||||||
|  |         EFEC_W { w: self } | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 0:28 - EFID2"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn efid2(&mut self) -> EFID2_W { | ||||||
|  |         EFID2_W { w: self } | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 30:31 - EFT"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn eft(&mut self) -> EFT_W { | ||||||
|  |         EFT_W { w: self } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										168
									
								
								embassy-stm32/src/can/fd/message_ram/generic.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								embassy-stm32/src/can/fd/message_ram/generic.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,168 @@ | |||||||
|  | // Note: This file is copied and modified from fdcan crate by Richard Meadows
 | ||||||
|  | 
 | ||||||
|  | use core::marker; | ||||||
|  | 
 | ||||||
|  | ///This trait shows that register has `read` method
 | ||||||
|  | ///
 | ||||||
|  | ///Registers marked with `Writable` can be also `modify`'ed
 | ||||||
|  | pub trait Readable {} | ||||||
|  | 
 | ||||||
|  | ///This trait shows that register has `write`, `write_with_zero` and `reset` method
 | ||||||
|  | ///
 | ||||||
|  | ///Registers marked with `Readable` can be also `modify`'ed
 | ||||||
|  | pub trait Writable {} | ||||||
|  | 
 | ||||||
|  | ///Reset value of the register
 | ||||||
|  | ///
 | ||||||
|  | ///This value is initial value for `write` method.
 | ||||||
|  | ///It can be also directly writed to register by `reset` method.
 | ||||||
|  | pub trait ResetValue { | ||||||
|  |     ///Register size
 | ||||||
|  |     type Type; | ||||||
|  |     ///Reset value of the register
 | ||||||
|  |     fn reset_value() -> Self::Type; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ///This structure provides volatile access to register
 | ||||||
|  | pub struct Reg<U, REG> { | ||||||
|  |     register: vcell::VolatileCell<U>, | ||||||
|  |     _marker: marker::PhantomData<REG>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | unsafe impl<U: Send, REG> Send for Reg<U, REG> {} | ||||||
|  | 
 | ||||||
|  | impl<U, REG> Reg<U, REG> | ||||||
|  | where | ||||||
|  |     Self: Readable, | ||||||
|  |     U: Copy, | ||||||
|  | { | ||||||
|  |     ///Reads the contents of `Readable` register
 | ||||||
|  |     ///
 | ||||||
|  |     ///You can read the contents of a register in such way:
 | ||||||
|  |     ///```ignore
 | ||||||
|  |     ///let bits = periph.reg.read().bits();
 | ||||||
|  |     ///```
 | ||||||
|  |     ///or get the content of a particular field of a register.
 | ||||||
|  |     ///```ignore
 | ||||||
|  |     ///let reader = periph.reg.read();
 | ||||||
|  |     ///let bits = reader.field1().bits();
 | ||||||
|  |     ///let flag = reader.field2().bit_is_set();
 | ||||||
|  |     ///```
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn read(&self) -> R<U, Self> { | ||||||
|  |         R { | ||||||
|  |             bits: self.register.get(), | ||||||
|  |             _reg: marker::PhantomData, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<U, REG> Reg<U, REG> | ||||||
|  | where | ||||||
|  |     Self: ResetValue<Type = U> + Writable, | ||||||
|  |     U: Copy, | ||||||
|  | { | ||||||
|  |     ///Writes the reset value to `Writable` register
 | ||||||
|  |     ///
 | ||||||
|  |     ///Resets the register to its initial state
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn reset(&self) { | ||||||
|  |         self.register.set(Self::reset_value()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<U, REG> Reg<U, REG> | ||||||
|  | where | ||||||
|  |     Self: ResetValue<Type = U> + Writable, | ||||||
|  |     U: Copy, | ||||||
|  | { | ||||||
|  |     ///Writes bits to `Writable` register
 | ||||||
|  |     ///
 | ||||||
|  |     ///You can write raw bits into a register:
 | ||||||
|  |     ///```ignore
 | ||||||
|  |     ///periph.reg.write(|w| unsafe { w.bits(rawbits) });
 | ||||||
|  |     ///```
 | ||||||
|  |     ///or write only the fields you need:
 | ||||||
|  |     ///```ignore
 | ||||||
|  |     ///periph.reg.write(|w| w
 | ||||||
|  |     ///    .field1().bits(newfield1bits)
 | ||||||
|  |     ///    .field2().set_bit()
 | ||||||
|  |     ///    .field3().variant(VARIANT)
 | ||||||
|  |     ///);
 | ||||||
|  |     ///```
 | ||||||
|  |     ///Other fields will have reset value.
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn write<F>(&self, f: F) | ||||||
|  |     where | ||||||
|  |         F: FnOnce(&mut W<U, Self>) -> &mut W<U, Self>, | ||||||
|  |     { | ||||||
|  |         self.register.set( | ||||||
|  |             f(&mut W { | ||||||
|  |                 bits: Self::reset_value(), | ||||||
|  |                 _reg: marker::PhantomData, | ||||||
|  |             }) | ||||||
|  |             .bits, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ///Register/field reader
 | ||||||
|  | ///
 | ||||||
|  | ///Result of the [`read`](Reg::read) method of a register.
 | ||||||
|  | ///Also it can be used in the [`modify`](Reg::read) method
 | ||||||
|  | pub struct R<U, T> { | ||||||
|  |     pub(crate) bits: U, | ||||||
|  |     _reg: marker::PhantomData<T>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<U, T> R<U, T> | ||||||
|  | where | ||||||
|  |     U: Copy, | ||||||
|  | { | ||||||
|  |     ///Create new instance of reader
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub(crate) fn new(bits: U) -> Self { | ||||||
|  |         Self { | ||||||
|  |             bits, | ||||||
|  |             _reg: marker::PhantomData, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     ///Read raw bits from register/field
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn bits(&self) -> U { | ||||||
|  |         self.bits | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<U, T, FI> PartialEq<FI> for R<U, T> | ||||||
|  | where | ||||||
|  |     U: PartialEq, | ||||||
|  |     FI: Copy + Into<U>, | ||||||
|  | { | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn eq(&self, other: &FI) -> bool { | ||||||
|  |         self.bits.eq(&(*other).into()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<FI> R<bool, FI> { | ||||||
|  |     ///Value of the field as raw bits
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn bit(&self) -> bool { | ||||||
|  |         self.bits | ||||||
|  |     } | ||||||
|  |     ///Returns `true` if the bit is clear (0)
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn bit_is_clear(&self) -> bool { | ||||||
|  |         !self.bit() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ///Register writer
 | ||||||
|  | ///
 | ||||||
|  | ///Used as an argument to the closures in the [`write`](Reg::write) and [`modify`](Reg::modify) methods of the register
 | ||||||
|  | pub struct W<U, REG> { | ||||||
|  |     ///Writable bits
 | ||||||
|  |     pub(crate) bits: U, | ||||||
|  |     _reg: marker::PhantomData<REG>, | ||||||
|  | } | ||||||
							
								
								
									
										170
									
								
								embassy-stm32/src/can/fd/message_ram/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								embassy-stm32/src/can/fd/message_ram/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,170 @@ | |||||||
|  | // Note: This file is copied and modified from fdcan crate by Richard Meadows
 | ||||||
|  | 
 | ||||||
|  | use volatile_register::RW; | ||||||
|  | 
 | ||||||
|  | pub(crate) mod common; | ||||||
|  | pub(crate) mod enums; | ||||||
|  | pub(crate) mod generic; | ||||||
|  | 
 | ||||||
|  | /// Number of Receive Fifos configured by this module
 | ||||||
|  | pub const RX_FIFOS_MAX: u8 = 2; | ||||||
|  | /// Number of Receive Messages per RxFifo configured by this module
 | ||||||
|  | pub const RX_FIFO_MAX: u8 = 3; | ||||||
|  | /// Number of Transmit Messages configured by this module
 | ||||||
|  | pub const TX_FIFO_MAX: u8 = 3; | ||||||
|  | /// Number of Transmit Events configured by this module
 | ||||||
|  | pub const TX_EVENT_MAX: u8 = 3; | ||||||
|  | /// Number of Standard Filters configured by this module
 | ||||||
|  | pub const STANDARD_FILTER_MAX: u8 = 28; | ||||||
|  | /// Number of Extended Filters configured by this module
 | ||||||
|  | pub const EXTENDED_FILTER_MAX: u8 = 8; | ||||||
|  | 
 | ||||||
|  | /// MessageRam Overlay
 | ||||||
|  | #[repr(C)] | ||||||
|  | pub struct RegisterBlock { | ||||||
|  |     pub(crate) filters: Filters, | ||||||
|  |     pub(crate) receive: [Receive; RX_FIFOS_MAX as usize], | ||||||
|  |     pub(crate) transmit: Transmit, | ||||||
|  | } | ||||||
|  | impl RegisterBlock { | ||||||
|  |     pub fn reset(&mut self) { | ||||||
|  |         self.filters.reset(); | ||||||
|  |         self.receive[0].reset(); | ||||||
|  |         self.receive[1].reset(); | ||||||
|  |         self.transmit.reset(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[repr(C)] | ||||||
|  | pub(crate) struct Filters { | ||||||
|  |     pub(crate) flssa: [StandardFilter; STANDARD_FILTER_MAX as usize], | ||||||
|  |     pub(crate) flesa: [ExtendedFilter; EXTENDED_FILTER_MAX as usize], | ||||||
|  | } | ||||||
|  | impl Filters { | ||||||
|  |     pub fn reset(&mut self) { | ||||||
|  |         for sf in &mut self.flssa { | ||||||
|  |             sf.reset(); | ||||||
|  |         } | ||||||
|  |         for ef in &mut self.flesa { | ||||||
|  |             ef.reset(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[repr(C)] | ||||||
|  | pub(crate) struct Receive { | ||||||
|  |     pub(crate) fxsa: [RxFifoElement; RX_FIFO_MAX as usize], | ||||||
|  | } | ||||||
|  | impl Receive { | ||||||
|  |     pub fn reset(&mut self) { | ||||||
|  |         for fe in &mut self.fxsa { | ||||||
|  |             fe.reset(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[repr(C)] | ||||||
|  | pub(crate) struct Transmit { | ||||||
|  |     pub(crate) efsa: [TxEventElement; TX_EVENT_MAX as usize], | ||||||
|  |     pub(crate) tbsa: [TxBufferElement; TX_FIFO_MAX as usize], | ||||||
|  | } | ||||||
|  | impl Transmit { | ||||||
|  |     pub fn reset(&mut self) { | ||||||
|  |         for ee in &mut self.efsa { | ||||||
|  |             ee.reset(); | ||||||
|  |         } | ||||||
|  |         for be in &mut self.tbsa { | ||||||
|  |             be.reset(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) mod standard_filter; | ||||||
|  | pub(crate) type StandardFilterType = u32; | ||||||
|  | pub(crate) type StandardFilter = generic::Reg<StandardFilterType, _StandardFilter>; | ||||||
|  | pub(crate) struct _StandardFilter; | ||||||
|  | impl generic::Readable for StandardFilter {} | ||||||
|  | impl generic::Writable for StandardFilter {} | ||||||
|  | 
 | ||||||
|  | pub(crate) mod extended_filter; | ||||||
|  | pub(crate) type ExtendedFilterType = [u32; 2]; | ||||||
|  | pub(crate) type ExtendedFilter = generic::Reg<ExtendedFilterType, _ExtendedFilter>; | ||||||
|  | pub(crate) struct _ExtendedFilter; | ||||||
|  | impl generic::Readable for ExtendedFilter {} | ||||||
|  | impl generic::Writable for ExtendedFilter {} | ||||||
|  | 
 | ||||||
|  | pub(crate) mod txevent_element; | ||||||
|  | pub(crate) type TxEventElementType = [u32; 2]; | ||||||
|  | pub(crate) type TxEventElement = generic::Reg<TxEventElementType, _TxEventElement>; | ||||||
|  | pub(crate) struct _TxEventElement; | ||||||
|  | impl generic::Readable for TxEventElement {} | ||||||
|  | impl generic::Writable for TxEventElement {} | ||||||
|  | 
 | ||||||
|  | pub(crate) mod rxfifo_element; | ||||||
|  | #[repr(C)] | ||||||
|  | pub(crate) struct RxFifoElement { | ||||||
|  |     pub(crate) header: RxFifoElementHeader, | ||||||
|  |     pub(crate) data: [RW<u32>; 16], | ||||||
|  | } | ||||||
|  | impl RxFifoElement { | ||||||
|  |     pub(crate) fn reset(&mut self) { | ||||||
|  |         self.header.reset(); | ||||||
|  |         for byte in self.data.iter_mut() { | ||||||
|  |             unsafe { byte.write(0) }; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | pub(crate) type RxFifoElementHeaderType = [u32; 2]; | ||||||
|  | pub(crate) type RxFifoElementHeader = generic::Reg<RxFifoElementHeaderType, _RxFifoElement>; | ||||||
|  | pub(crate) struct _RxFifoElement; | ||||||
|  | impl generic::Readable for RxFifoElementHeader {} | ||||||
|  | impl generic::Writable for RxFifoElementHeader {} | ||||||
|  | 
 | ||||||
|  | pub(crate) mod txbuffer_element; | ||||||
|  | #[repr(C)] | ||||||
|  | pub(crate) struct TxBufferElement { | ||||||
|  |     pub(crate) header: TxBufferElementHeader, | ||||||
|  |     pub(crate) data: [RW<u32>; 16], | ||||||
|  | } | ||||||
|  | impl TxBufferElement { | ||||||
|  |     pub(crate) fn reset(&mut self) { | ||||||
|  |         self.header.reset(); | ||||||
|  |         for byte in self.data.iter_mut() { | ||||||
|  |             unsafe { byte.write(0) }; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | pub(crate) type TxBufferElementHeader = generic::Reg<TxBufferElementHeaderType, _TxBufferElement>; | ||||||
|  | pub(crate) type TxBufferElementHeaderType = [u32; 2]; | ||||||
|  | pub(crate) struct _TxBufferElement; | ||||||
|  | impl generic::Readable for TxBufferElementHeader {} | ||||||
|  | impl generic::Writable for TxBufferElementHeader {} | ||||||
|  | 
 | ||||||
|  | /// FdCan Message RAM instance.
 | ||||||
|  | ///
 | ||||||
|  | /// # Safety
 | ||||||
|  | ///
 | ||||||
|  | /// It is only safe to implement this trait, when:
 | ||||||
|  | ///
 | ||||||
|  | /// * The implementing type has ownership of the Message RAM, preventing any
 | ||||||
|  | ///   other accesses to the register block.
 | ||||||
|  | /// * `MSG_RAM` is a pointer to the Message RAM block and can be safely accessed
 | ||||||
|  | /// for as long as ownership or a borrow of the implementing type is present.
 | ||||||
|  | pub unsafe trait Instance { | ||||||
|  |     const MSG_RAM: *mut RegisterBlock; | ||||||
|  |     fn msg_ram(&self) -> &RegisterBlock { | ||||||
|  |         unsafe { &*Self::MSG_RAM } | ||||||
|  |     } | ||||||
|  |     fn msg_ram_mut(&mut self) -> &mut RegisterBlock { | ||||||
|  |         unsafe { &mut *Self::MSG_RAM } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Ensure the RegisterBlock is the same size as on pg 1957 of RM0440.
 | ||||||
|  | static_assertions::assert_eq_size!(Filters, [u32; 28 + 16]); | ||||||
|  | static_assertions::assert_eq_size!(Receive, [u32; 54]); | ||||||
|  | static_assertions::assert_eq_size!(Transmit, [u32; 6 + 54]); | ||||||
|  | static_assertions::assert_eq_size!( | ||||||
|  |     RegisterBlock, | ||||||
|  |     [u32; 28 /*Standard Filters*/ +16 /*Extended Filters*/ +54 /*RxFifo0*/ +54 /*RxFifo1*/ +6 /*TxEvent*/ +54 /*TxFifo */] | ||||||
|  | ); | ||||||
							
								
								
									
										122
									
								
								embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								embassy-stm32/src/can/fd/message_ram/rxfifo_element.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,122 @@ | |||||||
|  | // Note: This file is copied and modified from fdcan crate by Richard Meadows
 | ||||||
|  | 
 | ||||||
|  | #![allow(non_camel_case_types)] | ||||||
|  | #![allow(non_snake_case)] | ||||||
|  | #![allow(unused)] | ||||||
|  | 
 | ||||||
|  | use super::common::{BRS_R, DLC_R, ESI_R, FDF_R, ID_R, RTR_R, XTD_R}; | ||||||
|  | use super::enums::{DataLength, FilterFrameMatch, FrameFormat}; | ||||||
|  | use super::generic; | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of register RxFifoElement"] | ||||||
|  | pub(crate) type R = generic::R<super::RxFifoElementHeaderType, super::RxFifoElementHeader>; | ||||||
|  | // #[doc = "Writer for register ExtendedFilter"]
 | ||||||
|  | // pub(crate) type W = generic::W<super::RxFifoElementHeaderType, super::RxFifoElementHeader>;
 | ||||||
|  | #[doc = "Register ExtendedFilter `reset()`'s"] | ||||||
|  | impl generic::ResetValue for super::RxFifoElementHeader { | ||||||
|  |     type Type = super::RxFifoElementHeaderType; | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn reset_value() -> Self::Type { | ||||||
|  |         [0x0, 0x0] | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `RXTS`"] | ||||||
|  | pub(crate) type RXTS_R = generic::R<u16, u16>; | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `FIDX`"] | ||||||
|  | pub(crate) type FIDX_R = generic::R<u8, u8>; | ||||||
|  | 
 | ||||||
|  | pub(crate) struct _ANMF; | ||||||
|  | #[doc = "Reader of field `ANMF`"] | ||||||
|  | pub(crate) type ANMF_R = generic::R<bool, _ANMF>; | ||||||
|  | impl ANMF_R { | ||||||
|  |     pub fn is_matching_frame(&self) -> bool { | ||||||
|  |         self.bit_is_clear() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl R { | ||||||
|  |     #[doc = "Byte 0 - Bits 0:28 - ID"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn id(&self) -> ID_R { | ||||||
|  |         ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 0 - Bit 29 - RTR"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn rtr(&self) -> RTR_R { | ||||||
|  |         RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 0 - Bit 30 - XTD"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn xtd(&self) -> XTD_R { | ||||||
|  |         XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 0 - Bit 30 - ESI"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn esi(&self) -> ESI_R { | ||||||
|  |         ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 0:15 - RXTS"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn txts(&self) -> RXTS_R { | ||||||
|  |         RXTS_R::new(((self.bits[1]) & 0xFFFF) as u16) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 16:19 - DLC"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn dlc(&self) -> DLC_R { | ||||||
|  |         DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 20 - BRS"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn brs(&self) -> BRS_R { | ||||||
|  |         BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 20 - FDF"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn fdf(&self) -> FDF_R { | ||||||
|  |         FDF_R::new(((self.bits[1] >> 21) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 24:30 - FIDX"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn fidx(&self) -> FIDX_R { | ||||||
|  |         FIDX_R::new(((self.bits[1] >> 24) & 0xFF) as u8) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 31 - ANMF"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn anmf(&self) -> ANMF_R { | ||||||
|  |         ANMF_R::new(((self.bits[1] >> 31) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     pub fn to_data_length(&self) -> DataLength { | ||||||
|  |         let dlc = self.dlc().bits(); | ||||||
|  |         let ff = self.fdf().frame_format(); | ||||||
|  |         let len = if ff == FrameFormat::Fdcan { | ||||||
|  |             // See RM0433 Rev 7 Table 475. DLC coding
 | ||||||
|  |             match dlc { | ||||||
|  |                 0..=8 => dlc, | ||||||
|  |                 9 => 12, | ||||||
|  |                 10 => 16, | ||||||
|  |                 11 => 20, | ||||||
|  |                 12 => 24, | ||||||
|  |                 13 => 32, | ||||||
|  |                 14 => 48, | ||||||
|  |                 15 => 64, | ||||||
|  |                 _ => panic!("DLC > 15"), | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             match dlc { | ||||||
|  |                 0..=8 => dlc, | ||||||
|  |                 9..=15 => 8, | ||||||
|  |                 _ => panic!("DLC > 15"), | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |         DataLength::new(len, ff) | ||||||
|  |     } | ||||||
|  |     pub fn to_filter_match(&self) -> FilterFrameMatch { | ||||||
|  |         if self.anmf().is_matching_frame() { | ||||||
|  |             FilterFrameMatch::DidMatch(self.fidx().bits()) | ||||||
|  |         } else { | ||||||
|  |             FilterFrameMatch::DidNotMatch | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										136
									
								
								embassy-stm32/src/can/fd/message_ram/standard_filter.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								embassy-stm32/src/can/fd/message_ram/standard_filter.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,136 @@ | |||||||
|  | // Note: This file is copied and modified from fdcan crate by Richard Meadows
 | ||||||
|  | 
 | ||||||
|  | #![allow(non_camel_case_types)] | ||||||
|  | #![allow(non_snake_case)] | ||||||
|  | #![allow(unused)] | ||||||
|  | 
 | ||||||
|  | use super::common::{ESFEC_R, ESFT_R}; | ||||||
|  | use super::enums::{FilterElementConfig, FilterType}; | ||||||
|  | use super::generic; | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of register StandardFilter"] | ||||||
|  | pub(crate) type R = generic::R<super::StandardFilterType, super::StandardFilter>; | ||||||
|  | #[doc = "Writer for register StandardFilter"] | ||||||
|  | pub(crate) type W = generic::W<super::StandardFilterType, super::StandardFilter>; | ||||||
|  | #[doc = "Register StandardFilter `reset()`'s with value 0xC0000"] | ||||||
|  | impl generic::ResetValue for super::StandardFilter { | ||||||
|  |     type Type = super::StandardFilterType; | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn reset_value() -> Self::Type { | ||||||
|  |         // Sets filter element to Disabled
 | ||||||
|  |         0xC000 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `SFID2`"] | ||||||
|  | pub(crate) type SFID2_R = generic::R<u16, u16>; | ||||||
|  | #[doc = "Write proxy for field `SFID2`"] | ||||||
|  | pub(crate) struct SFID2_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> SFID2_W<'a> { | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub unsafe fn bits(self, value: u16) -> &'a mut W { | ||||||
|  |         self.w.bits = (self.w.bits & !(0x07ff)) | ((value as u32) & 0x07ff); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `SFID1`"] | ||||||
|  | pub(crate) type SFID1_R = generic::R<u16, u16>; | ||||||
|  | #[doc = "Write proxy for field `SFID1`"] | ||||||
|  | pub(crate) struct SFID1_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> SFID1_W<'a> { | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub unsafe fn bits(self, value: u16) -> &'a mut W { | ||||||
|  |         self.w.bits = (self.w.bits & !(0x07ff << 16)) | (((value as u32) & 0x07ff) << 16); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Write proxy for field `SFEC`"] | ||||||
|  | pub(crate) struct SFEC_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> SFEC_W<'a> { | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub unsafe fn bits(self, value: u8) -> &'a mut W { | ||||||
|  |         self.w.bits = (self.w.bits & !(0x07 << 27)) | (((value as u32) & 0x07) << 27); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  |     #[doc = r"Sets the field according to FilterElementConfig"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn set_filter_element_config(self, fec: FilterElementConfig) -> &'a mut W { | ||||||
|  |         //SAFETY: FilterElementConfig only be valid options
 | ||||||
|  |         unsafe { self.bits(fec as u8) } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Write proxy for field `SFT`"] | ||||||
|  | pub(crate) struct SFT_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> SFT_W<'a> { | ||||||
|  |     #[doc = r"Sets the field according the FilterType"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn set_filter_type(self, filter: FilterType) -> &'a mut W { | ||||||
|  |         //SAFETY: FilterType only be valid options
 | ||||||
|  |         unsafe { self.bits(filter as u8) } | ||||||
|  |     } | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub unsafe fn bits(self, value: u8) -> &'a mut W { | ||||||
|  |         self.w.bits = (self.w.bits & !(0x03 << 30)) | (((value as u32) & 0x03) << 30); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl R { | ||||||
|  |     #[doc = "Bits 0:10 - SFID2"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn sfid2(&self) -> SFID2_R { | ||||||
|  |         SFID2_R::new((self.bits & 0x07ff) as u16) | ||||||
|  |     } | ||||||
|  |     #[doc = "Bits 16:26 - SFID1"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn sfid1(&self) -> SFID1_R { | ||||||
|  |         SFID1_R::new(((self.bits >> 16) & 0x07ff) as u16) | ||||||
|  |     } | ||||||
|  |     #[doc = "Bits 27:29 - SFEC"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn sfec(&self) -> ESFEC_R { | ||||||
|  |         ESFEC_R::new(((self.bits >> 27) & 0x07) as u8) | ||||||
|  |     } | ||||||
|  |     #[doc = "Bits 30:31 - SFT"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn sft(&self) -> ESFT_R { | ||||||
|  |         ESFT_R::new(((self.bits >> 30) & 0x03) as u8) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | impl W { | ||||||
|  |     #[doc = "Bits 0:10 - SFID2"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn sfid2(&mut self) -> SFID2_W { | ||||||
|  |         SFID2_W { w: self } | ||||||
|  |     } | ||||||
|  |     #[doc = "Bits 16:26 - SFID1"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn sfid1(&mut self) -> SFID1_W { | ||||||
|  |         SFID1_W { w: self } | ||||||
|  |     } | ||||||
|  |     #[doc = "Bits 27:29 - SFEC"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn sfec(&mut self) -> SFEC_W { | ||||||
|  |         SFEC_W { w: self } | ||||||
|  |     } | ||||||
|  |     #[doc = "Bits 30:31 - SFT"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn sft(&mut self) -> SFT_W { | ||||||
|  |         SFT_W { w: self } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										433
									
								
								embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										433
									
								
								embassy-stm32/src/can/fd/message_ram/txbuffer_element.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,433 @@ | |||||||
|  | // Note: This file is copied and modified from fdcan crate by Richard Meadows
 | ||||||
|  | 
 | ||||||
|  | #![allow(non_camel_case_types)] | ||||||
|  | #![allow(non_snake_case)] | ||||||
|  | #![allow(unused)] | ||||||
|  | 
 | ||||||
|  | use super::common::{BRS_R, DLC_R, ESI_R, FDF_R, ID_R, RTR_R, XTD_R}; | ||||||
|  | use super::enums::{ | ||||||
|  |     BitRateSwitching, DataLength, ErrorStateIndicator, Event, EventControl, FrameFormat, IdType, | ||||||
|  |     RemoteTransmissionRequest, | ||||||
|  | }; | ||||||
|  | use super::generic; | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of register TxBufferElement"] | ||||||
|  | pub(crate) type R = generic::R<super::TxBufferElementHeaderType, super::TxBufferElementHeader>; | ||||||
|  | #[doc = "Writer for register TxBufferElement"] | ||||||
|  | pub(crate) type W = generic::W<super::TxBufferElementHeaderType, super::TxBufferElementHeader>; | ||||||
|  | impl generic::ResetValue for super::TxBufferElementHeader { | ||||||
|  |     type Type = super::TxBufferElementHeaderType; | ||||||
|  | 
 | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn reset_value() -> Self::Type { | ||||||
|  |         [0; 2] | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Write proxy for field `ESI`"] | ||||||
|  | pub(crate) struct ESI_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> ESI_W<'a> { | ||||||
|  |     #[doc = r"Writes `variant` to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn set_error_indicator(self, esi: ErrorStateIndicator) -> &'a mut W { | ||||||
|  |         self.bit(esi as u8 != 0) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[doc = r"Sets the field bit"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn set_bit(self) -> &'a mut W { | ||||||
|  |         self.bit(true) | ||||||
|  |     } | ||||||
|  |     #[doc = r"Clears the field bit"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn clear_bit(self) -> &'a mut W { | ||||||
|  |         self.bit(false) | ||||||
|  |     } | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn bit(self, value: bool) -> &'a mut W { | ||||||
|  |         self.w.bits[0] = (self.w.bits[0] & !(0x01 << 31)) | (((value as u32) & 0x01) << 31); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Write proxy for field `XTD`"] | ||||||
|  | pub(crate) struct XTD_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> XTD_W<'a> { | ||||||
|  |     #[doc = r"Writes `variant` to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn set_id_type(self, idt: IdType) -> &'a mut W { | ||||||
|  |         self.bit(idt as u8 != 0) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[doc = r"Sets the field bit"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn set_bit(self) -> &'a mut W { | ||||||
|  |         self.bit(true) | ||||||
|  |     } | ||||||
|  |     #[doc = r"Clears the field bit"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn clear_bit(self) -> &'a mut W { | ||||||
|  |         self.bit(false) | ||||||
|  |     } | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn bit(self, value: bool) -> &'a mut W { | ||||||
|  |         self.w.bits[0] = (self.w.bits[0] & !(0x01 << 30)) | (((value as u32) & 0x01) << 30); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Write proxy for field `RTR`"] | ||||||
|  | pub(crate) struct RTR_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> RTR_W<'a> { | ||||||
|  |     #[doc = r"Writes `variant` to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn set_rtr(self, rtr: RemoteTransmissionRequest) -> &'a mut W { | ||||||
|  |         self.bit(rtr as u8 != 0) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[doc = r"Sets the field bit"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn set_bit(self) -> &'a mut W { | ||||||
|  |         self.bit(true) | ||||||
|  |     } | ||||||
|  |     #[doc = r"Clears the field bit"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn clear_bit(self) -> &'a mut W { | ||||||
|  |         self.bit(false) | ||||||
|  |     } | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn bit(self, value: bool) -> &'a mut W { | ||||||
|  |         self.w.bits[0] = (self.w.bits[0] & !(0x01 << 29)) | (((value as u32) & 0x01) << 29); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Write proxy for field `ID`"] | ||||||
|  | pub(crate) struct ID_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> ID_W<'a> { | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub unsafe fn bits(self, value: u32) -> &'a mut W { | ||||||
|  |         self.w.bits[0] = (self.w.bits[0] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Write proxy for field `DLC`"] | ||||||
|  | pub(crate) struct DLC_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> DLC_W<'a> { | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub unsafe fn bits(self, value: u8) -> &'a mut W { | ||||||
|  |         self.w.bits[1] = (self.w.bits[1] & !(0x0F << 16)) | (((value as u32) & 0x0F) << 16); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Write proxy for field `BRS`"] | ||||||
|  | pub(crate) struct BRS_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> BRS_W<'a> { | ||||||
|  |     #[doc = r"Writes `variant` to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn set_brs(self, brs: BitRateSwitching) -> &'a mut W { | ||||||
|  |         self.bit(brs as u8 != 0) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[doc = r"Sets the field bit"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn set_bit(self) -> &'a mut W { | ||||||
|  |         self.bit(true) | ||||||
|  |     } | ||||||
|  |     #[doc = r"Clears the field bit"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn clear_bit(self) -> &'a mut W { | ||||||
|  |         self.bit(false) | ||||||
|  |     } | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn bit(self, value: bool) -> &'a mut W { | ||||||
|  |         self.w.bits[1] = (self.w.bits[1] & !(0x01 << 20)) | (((value as u32) & 0x01) << 20); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Write proxy for field `FDF`"] | ||||||
|  | pub(crate) struct FDF_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> FDF_W<'a> { | ||||||
|  |     #[doc = r"Writes `variant` to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn set_format(self, fdf: FrameFormat) -> &'a mut W { | ||||||
|  |         self.bit(fdf as u8 != 0) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[doc = r"Sets the field bit"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn set_bit(self) -> &'a mut W { | ||||||
|  |         self.bit(true) | ||||||
|  |     } | ||||||
|  |     #[doc = r"Clears the field bit"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn clear_bit(self) -> &'a mut W { | ||||||
|  |         self.bit(false) | ||||||
|  |     } | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn bit(self, value: bool) -> &'a mut W { | ||||||
|  |         self.w.bits[1] = (self.w.bits[1] & !(0x01 << 21)) | (((value as u32) & 0x01) << 21); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `EFC`"] | ||||||
|  | pub(crate) type EFC_R = generic::R<bool, EventControl>; | ||||||
|  | impl EFC_R { | ||||||
|  |     pub fn to_event_control(&self) -> EventControl { | ||||||
|  |         match self.bit() { | ||||||
|  |             false => EventControl::DoNotStore, | ||||||
|  |             true => EventControl::Store, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | #[doc = "Write proxy for field `EFC`"] | ||||||
|  | pub(crate) struct EFC_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> EFC_W<'a> { | ||||||
|  |     #[doc = r"Writes `variant` to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn set_event_control(self, efc: EventControl) -> &'a mut W { | ||||||
|  |         self.bit(match efc { | ||||||
|  |             EventControl::DoNotStore => false, | ||||||
|  |             EventControl::Store => true, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[doc = r"Sets the field bit"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn set_bit(self) -> &'a mut W { | ||||||
|  |         self.bit(true) | ||||||
|  |     } | ||||||
|  |     #[doc = r"Clears the field bit"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn clear_bit(self) -> &'a mut W { | ||||||
|  |         self.bit(false) | ||||||
|  |     } | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     pub fn bit(self, value: bool) -> &'a mut W { | ||||||
|  |         self.w.bits[1] = (self.w.bits[1] & !(0x01 << 23)) | (((value as u32) & 0x01) << 23); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct Marker(u8); | ||||||
|  | impl From<Event> for Marker { | ||||||
|  |     fn from(e: Event) -> Marker { | ||||||
|  |         match e { | ||||||
|  |             Event::NoEvent => Marker(0), | ||||||
|  |             Event::Event(mm) => Marker(mm), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `MM`"] | ||||||
|  | pub(crate) type MM_R = generic::R<u8, u8>; | ||||||
|  | #[doc = "Write proxy for field `MM`"] | ||||||
|  | pub(crate) struct MM_W<'a> { | ||||||
|  |     w: &'a mut W, | ||||||
|  | } | ||||||
|  | impl<'a> MM_W<'a> { | ||||||
|  |     #[doc = r"Writes raw bits to the field"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub unsafe fn bits(self, value: u8) -> &'a mut W { | ||||||
|  |         self.w.bits[1] = (self.w.bits[1] & !(0x7F << 24)) | (((value as u32) & 0x7F) << 24); | ||||||
|  |         self.w | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn set_message_marker(self, mm: Marker) -> &'a mut W { | ||||||
|  |         unsafe { self.bits(mm.0) } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl R { | ||||||
|  |     #[doc = "Byte 0 - Bits 0:28 - ID"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn id(&self) -> ID_R { | ||||||
|  |         ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 0 - Bit 29 - RTR"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn rtr(&self) -> RTR_R { | ||||||
|  |         RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 0 - Bit 30 - XTD"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn xtd(&self) -> XTD_R { | ||||||
|  |         XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 0 - Bit 30 - ESI"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn esi(&self) -> ESI_R { | ||||||
|  |         ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 16:19 - DLC"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn dlc(&self) -> DLC_R { | ||||||
|  |         DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 20 - BRS"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn brs(&self) -> BRS_R { | ||||||
|  |         BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 20 - FDF"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn fdf(&self) -> FDF_R { | ||||||
|  |         FDF_R::new(((self.bits[1] >> 21) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 23 - EFC"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn efc(&self) -> EFC_R { | ||||||
|  |         EFC_R::new(((self.bits[1] >> 23) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 24:31 - MM"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn mm(&self) -> MM_R { | ||||||
|  |         MM_R::new(((self.bits[1] >> 24) & 0xFF) as u8) | ||||||
|  |     } | ||||||
|  |     pub fn to_data_length(&self) -> DataLength { | ||||||
|  |         let dlc = self.dlc().bits(); | ||||||
|  |         let ff = self.fdf().frame_format(); | ||||||
|  |         let len = if ff == FrameFormat::Fdcan { | ||||||
|  |             // See RM0433 Rev 7 Table 475. DLC coding
 | ||||||
|  |             match dlc { | ||||||
|  |                 0..=8 => dlc, | ||||||
|  |                 9 => 12, | ||||||
|  |                 10 => 16, | ||||||
|  |                 11 => 20, | ||||||
|  |                 12 => 24, | ||||||
|  |                 13 => 32, | ||||||
|  |                 14 => 48, | ||||||
|  |                 15 => 64, | ||||||
|  |                 _ => panic!("DLC > 15"), | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             match dlc { | ||||||
|  |                 0..=8 => dlc, | ||||||
|  |                 9..=15 => 8, | ||||||
|  |                 _ => panic!("DLC > 15"), | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |         DataLength::new(len, ff) | ||||||
|  |     } | ||||||
|  |     pub fn to_event(&self) -> Event { | ||||||
|  |         let mm = self.mm().bits(); | ||||||
|  |         let efc = self.efc().to_event_control(); | ||||||
|  |         match efc { | ||||||
|  |             EventControl::DoNotStore => Event::NoEvent, | ||||||
|  |             EventControl::Store => Event::Event(mm), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | impl W { | ||||||
|  |     #[doc = "Byte 0 - Bits 0:28 - ID"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn id(&mut self) -> ID_W { | ||||||
|  |         ID_W { w: self } | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 0 - Bit 29 - RTR"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn rtr(&mut self) -> RTR_W { | ||||||
|  |         RTR_W { w: self } | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 0 - Bit 30 - XTD"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn xtd(&mut self) -> XTD_W { | ||||||
|  |         XTD_W { w: self } | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 0 - Bit 31 - ESI"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn esi(&mut self) -> ESI_W { | ||||||
|  |         ESI_W { w: self } | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bit 16:19 - DLC"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn dlc(&mut self) -> DLC_W { | ||||||
|  |         DLC_W { w: self } | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bit 20 - BRS"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn brs(&mut self) -> BRS_W { | ||||||
|  |         BRS_W { w: self } | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bit 21 - FDF"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn fdf(&mut self) -> FDF_W { | ||||||
|  |         FDF_W { w: self } | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bit 23 - EFC"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn efc(&mut self) -> EFC_W { | ||||||
|  |         EFC_W { w: self } | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bit 24:31 - MM"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn mm(&mut self) -> MM_W { | ||||||
|  |         MM_W { w: self } | ||||||
|  |     } | ||||||
|  |     #[doc = "Convenience function for setting the data length and frame format"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn set_len(&mut self, dl: impl Into<DataLength>) -> &mut Self { | ||||||
|  |         let dl: DataLength = dl.into(); | ||||||
|  |         self.fdf().set_format(dl.into()); | ||||||
|  |         unsafe { self.dlc().bits(dl.dlc()) } | ||||||
|  |     } | ||||||
|  |     pub fn set_event(&mut self, event: Event) -> &mut Self { | ||||||
|  |         self.mm().set_message_marker(event.into()); | ||||||
|  |         self.efc().set_event_control(event.into()) | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										138
									
								
								embassy-stm32/src/can/fd/message_ram/txevent_element.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								embassy-stm32/src/can/fd/message_ram/txevent_element.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,138 @@ | |||||||
|  | // Note: This file is copied and modified from fdcan crate by Richard Meadows
 | ||||||
|  | 
 | ||||||
|  | #![allow(non_camel_case_types)] | ||||||
|  | #![allow(non_snake_case)] | ||||||
|  | #![allow(unused)] | ||||||
|  | 
 | ||||||
|  | use super::common::{BRS_R, DLC_R, ESI_R, RTR_R, XTD_R}; | ||||||
|  | use super::generic; | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of register TxEventElement"] | ||||||
|  | pub(crate) type R = generic::R<super::TxEventElementType, super::TxEventElement>; | ||||||
|  | // #[doc = "Writer for register TxEventElement"]
 | ||||||
|  | // pub(crate) type W = generic::W<super::TxEventElementType, super::TxEventElement>;
 | ||||||
|  | #[doc = "Register TxEventElement `reset()`'s"] | ||||||
|  | impl generic::ResetValue for super::TxEventElement { | ||||||
|  |     type Type = super::TxEventElementType; | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn reset_value() -> Self::Type { | ||||||
|  |         [0, 0] | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `ID`"] | ||||||
|  | pub(crate) type ID_R = generic::R<u32, u32>; | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `TXTS`"] | ||||||
|  | pub(crate) type TXTS_R = generic::R<u16, u16>; | ||||||
|  | 
 | ||||||
|  | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
|  | pub(crate) enum DataLengthFormat { | ||||||
|  |     StandardLength = 0, | ||||||
|  |     FDCANLength = 1, | ||||||
|  | } | ||||||
|  | impl From<DataLengthFormat> for bool { | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn from(dlf: DataLengthFormat) -> Self { | ||||||
|  |         dlf as u8 != 0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `EDL`"] | ||||||
|  | pub(crate) type EDL_R = generic::R<bool, DataLengthFormat>; | ||||||
|  | impl EDL_R { | ||||||
|  |     pub fn data_length_format(&self) -> DataLengthFormat { | ||||||
|  |         match self.bits() { | ||||||
|  |             false => DataLengthFormat::StandardLength, | ||||||
|  |             true => DataLengthFormat::FDCANLength, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn is_standard_length(&self) -> bool { | ||||||
|  |         *self == DataLengthFormat::StandardLength | ||||||
|  |     } | ||||||
|  |     pub fn is_fdcan_length(&self) -> bool { | ||||||
|  |         *self == DataLengthFormat::FDCANLength | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
|  | pub(crate) enum EventType { | ||||||
|  |     //_Reserved = 0b00,
 | ||||||
|  |     TxEvent = 0b01, | ||||||
|  |     TxDespiteAbort = 0b10, | ||||||
|  |     //_Reserved = 0b10,
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `EFC`"] | ||||||
|  | pub(crate) type EFC_R = generic::R<u8, EventType>; | ||||||
|  | impl EFC_R { | ||||||
|  |     pub fn event_type(&self) -> EventType { | ||||||
|  |         match self.bits() { | ||||||
|  |             0b01 => EventType::TxEvent, | ||||||
|  |             0b10 => EventType::TxDespiteAbort, | ||||||
|  |             _ => unimplemented!(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn is_tx_event(&self) -> bool { | ||||||
|  |         self.event_type() == EventType::TxEvent | ||||||
|  |     } | ||||||
|  |     pub fn is_despite_abort(&self) -> bool { | ||||||
|  |         self.event_type() == EventType::TxDespiteAbort | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[doc = "Reader of field `MM`"] | ||||||
|  | pub(crate) type MM_R = generic::R<u8, u8>; | ||||||
|  | 
 | ||||||
|  | impl R { | ||||||
|  |     #[doc = "Byte 0 - Bits 0:28 - ID"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn id(&self) -> ID_R { | ||||||
|  |         ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 0 - Bit 29 - RTR"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn rtr(&self) -> RTR_R { | ||||||
|  |         RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 0 - Bit 30 - XTD"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn xtd(&self) -> XTD_R { | ||||||
|  |         XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 0 - Bit 30 - ESI"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn esi(&self) -> ESI_R { | ||||||
|  |         ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 0:15 - TXTS"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn txts(&self) -> TXTS_R { | ||||||
|  |         TXTS_R::new(((self.bits[1]) & 0xFFFF) as u16) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 16:19 - DLC"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn dlc(&self) -> DLC_R { | ||||||
|  |         DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 20 - BRS"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn brs(&self) -> BRS_R { | ||||||
|  |         BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 21 - EDL"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn edl(&self) -> EDL_R { | ||||||
|  |         EDL_R::new(((self.bits[1] >> 21) & 0x01) != 0) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 22:23 - EFC"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn efc(&self) -> EFC_R { | ||||||
|  |         EFC_R::new(((self.bits[1] >> 22) & 0x03) as u8) | ||||||
|  |     } | ||||||
|  |     #[doc = "Byte 1 - Bits 24:31 - MM"] | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn mm(&self) -> MM_R { | ||||||
|  |         MM_R::new(((self.bits[1] >> 24) & 0xFF) as u8) | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								embassy-stm32/src/can/fd/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								embassy-stm32/src/can/fd/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | //! Module containing that which is speciffic to fdcan hardware variant
 | ||||||
|  | 
 | ||||||
|  | pub mod config; | ||||||
|  | pub mod filter; | ||||||
|  | pub(crate) mod message_ram; | ||||||
|  | pub(crate) mod peripheral; | ||||||
							
								
								
									
										776
									
								
								embassy-stm32/src/can/fd/peripheral.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										776
									
								
								embassy-stm32/src/can/fd/peripheral.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,776 @@ | |||||||
|  | // Note: This file is copied and modified from fdcan crate by Richard Meadows
 | ||||||
|  | 
 | ||||||
|  | use core::convert::Infallible; | ||||||
|  | use core::slice; | ||||||
|  | 
 | ||||||
|  | use crate::can::fd::config::*; | ||||||
|  | use crate::can::fd::message_ram::enums::*; | ||||||
|  | use crate::can::fd::message_ram::{RegisterBlock, RxFifoElement, TxBufferElement}; | ||||||
|  | use crate::can::frame::*; | ||||||
|  | 
 | ||||||
|  | /// Loopback Mode
 | ||||||
|  | #[derive(Clone, Copy, Debug)] | ||||||
|  | enum LoopbackMode { | ||||||
|  |     None, | ||||||
|  |     Internal, | ||||||
|  |     External, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct Registers { | ||||||
|  |     pub regs: &'static crate::pac::can::Fdcan, | ||||||
|  |     pub msgram: &'static crate::pac::fdcanram::Fdcanram, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Registers { | ||||||
|  |     fn tx_buffer_element(&self, bufidx: usize) -> &mut TxBufferElement { | ||||||
|  |         &mut self.msg_ram_mut().transmit.tbsa[bufidx] | ||||||
|  |     } | ||||||
|  |     pub fn msg_ram_mut(&self) -> &mut RegisterBlock { | ||||||
|  |         let ptr = self.msgram.as_ptr() as *mut RegisterBlock; | ||||||
|  |         unsafe { &mut (*ptr) } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn rx_fifo_element(&self, fifonr: usize, bufnum: usize) -> &mut RxFifoElement { | ||||||
|  |         &mut self.msg_ram_mut().receive[fifonr].fxsa[bufnum] | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn read_classic(&self, fifonr: usize) -> Option<(ClassicFrame, u16)> { | ||||||
|  |         // Fill level - do we have a msg?
 | ||||||
|  |         if self.regs.rxfs(fifonr).read().ffl() < 1 { | ||||||
|  |             return None; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let read_idx = self.regs.rxfs(fifonr).read().fgi(); | ||||||
|  |         let mailbox = self.rx_fifo_element(fifonr, read_idx as usize); | ||||||
|  | 
 | ||||||
|  |         let mut buffer: [u8; 8] = [0; 8]; | ||||||
|  |         let maybe_header = extract_frame(mailbox, &mut buffer); | ||||||
|  | 
 | ||||||
|  |         // Clear FIFO, reduces count and increments read buf
 | ||||||
|  |         self.regs.rxfa(fifonr).modify(|w| w.set_fai(read_idx)); | ||||||
|  | 
 | ||||||
|  |         match maybe_header { | ||||||
|  |             Some((header, ts)) => { | ||||||
|  |                 let data = ClassicData::new(&buffer[0..header.len() as usize]); | ||||||
|  |                 Some((ClassicFrame::new(header, data.unwrap()), ts)) | ||||||
|  |             } | ||||||
|  |             None => None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn read_fd(&self, fifonr: usize) -> Option<(FdFrame, u16)> { | ||||||
|  |         // Fill level - do we have a msg?
 | ||||||
|  |         if self.regs.rxfs(fifonr).read().ffl() < 1 { | ||||||
|  |             return None; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let read_idx = self.regs.rxfs(fifonr).read().fgi(); | ||||||
|  |         let mailbox = self.rx_fifo_element(fifonr, read_idx as usize); | ||||||
|  | 
 | ||||||
|  |         let mut buffer: [u8; 64] = [0; 64]; | ||||||
|  |         let maybe_header = extract_frame(mailbox, &mut buffer); | ||||||
|  | 
 | ||||||
|  |         // Clear FIFO, reduces count and increments read buf
 | ||||||
|  |         self.regs.rxfa(fifonr).modify(|w| w.set_fai(read_idx)); | ||||||
|  | 
 | ||||||
|  |         match maybe_header { | ||||||
|  |             Some((header, ts)) => { | ||||||
|  |                 let data = FdData::new(&buffer[0..header.len() as usize]); | ||||||
|  |                 Some((FdFrame::new(header, data.unwrap()), ts)) | ||||||
|  |             } | ||||||
|  |             None => None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) { | ||||||
|  |         // Fill level - do we have a msg?
 | ||||||
|  |         //if self.regs.rxfs(fifonr).read().ffl() < 1 { return None; }
 | ||||||
|  | 
 | ||||||
|  |         //let read_idx = self.regs.rxfs(fifonr).read().fgi();
 | ||||||
|  | 
 | ||||||
|  |         let mailbox = self.tx_buffer_element(bufidx); | ||||||
|  | 
 | ||||||
|  |         mailbox.reset(); | ||||||
|  |         put_tx_header(mailbox, header); | ||||||
|  |         put_tx_data(mailbox, &buffer[..header.len() as usize]); | ||||||
|  | 
 | ||||||
|  |         // Set <idx as Mailbox> as ready to transmit
 | ||||||
|  |         self.regs.txbar().modify(|w| w.set_ar(bufidx, true)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns if the tx queue is able to accept new messages without having to cancel an existing one
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn tx_queue_is_full(&self) -> bool { | ||||||
|  |         self.regs.txfqs().read().tfqf() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn has_pending_frame(&self, idx: usize) -> bool { | ||||||
|  |         self.regs.txbrp().read().trp(idx) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns `Ok` when the mailbox is free or if it contains pending frame with a
 | ||||||
|  |     /// lower priority (higher ID) than the identifier `id`.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn is_available(&self, bufidx: usize, id: &embedded_can::Id) -> bool { | ||||||
|  |         if self.has_pending_frame(bufidx) { | ||||||
|  |             let mailbox = self.tx_buffer_element(bufidx); | ||||||
|  | 
 | ||||||
|  |             let header_reg = mailbox.header.read(); | ||||||
|  |             let old_id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); | ||||||
|  | 
 | ||||||
|  |             *id > old_id | ||||||
|  |         } else { | ||||||
|  |             true | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Attempts to abort the sending of a frame that is pending in a mailbox.
 | ||||||
|  |     ///
 | ||||||
|  |     /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be
 | ||||||
|  |     /// aborted, this function has no effect and returns `false`.
 | ||||||
|  |     ///
 | ||||||
|  |     /// If there is a frame in the provided mailbox, and it is canceled successfully, this function
 | ||||||
|  |     /// returns `true`.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn abort(&self, bufidx: usize) -> bool { | ||||||
|  |         let can = self.regs; | ||||||
|  | 
 | ||||||
|  |         // Check if there is a request pending to abort
 | ||||||
|  |         if self.has_pending_frame(bufidx) { | ||||||
|  |             // Abort Request
 | ||||||
|  |             can.txbcr().write(|w| w.set_cr(bufidx, true)); | ||||||
|  | 
 | ||||||
|  |             // Wait for the abort request to be finished.
 | ||||||
|  |             loop { | ||||||
|  |                 if can.txbcf().read().cf(bufidx) { | ||||||
|  |                     // Return false when a transmission has occured
 | ||||||
|  |                     break can.txbto().read().to(bufidx) == false; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             false | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     //fn abort_pending_mailbox<PTX, R>(&mut self, idx: Mailbox, pending: PTX) -> Option<R>
 | ||||||
|  |     pub fn abort_pending_mailbox(&self, bufidx: usize) -> Option<ClassicFrame> | ||||||
|  | //where
 | ||||||
|  |     //    PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R,
 | ||||||
|  |     { | ||||||
|  |         if self.abort(bufidx) { | ||||||
|  |             let mailbox = self.tx_buffer_element(bufidx); | ||||||
|  | 
 | ||||||
|  |             let header_reg = mailbox.header.read(); | ||||||
|  |             let id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); | ||||||
|  | 
 | ||||||
|  |             let len = match header_reg.to_data_length() { | ||||||
|  |                 DataLength::Fdcan(len) => len, | ||||||
|  |                 DataLength::Standard(len) => len, | ||||||
|  |             }; | ||||||
|  |             if len as usize > ClassicFrame::MAX_DATA_LEN { | ||||||
|  |                 return None; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             //let tx_ram = self.tx_msg_ram();
 | ||||||
|  |             let mut data = [0u8; 64]; | ||||||
|  |             data_from_tx_buffer(&mut data, mailbox, len as usize); | ||||||
|  | 
 | ||||||
|  |             let cd = ClassicData::new(&data).unwrap(); | ||||||
|  |             Some(ClassicFrame::new(Header::new(id, len, header_reg.rtr().bit()), cd)) | ||||||
|  |         } else { | ||||||
|  |             // Abort request failed because the frame was already sent (or being sent) on
 | ||||||
|  |             // the bus. All mailboxes are now free. This can happen for small prescaler
 | ||||||
|  |             // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR
 | ||||||
|  |             // has preempted the execution.
 | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     //fn abort_pending_mailbox<PTX, R>(&mut self, idx: Mailbox, pending: PTX) -> Option<R>
 | ||||||
|  |     pub fn abort_pending_fd_mailbox(&self, bufidx: usize) -> Option<FdFrame> | ||||||
|  | //where
 | ||||||
|  |     //    PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R,
 | ||||||
|  |     { | ||||||
|  |         if self.abort(bufidx) { | ||||||
|  |             let mailbox = self.tx_buffer_element(bufidx); | ||||||
|  | 
 | ||||||
|  |             let header_reg = mailbox.header.read(); | ||||||
|  |             let id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); | ||||||
|  | 
 | ||||||
|  |             let len = match header_reg.to_data_length() { | ||||||
|  |                 DataLength::Fdcan(len) => len, | ||||||
|  |                 DataLength::Standard(len) => len, | ||||||
|  |             }; | ||||||
|  |             if len as usize > FdFrame::MAX_DATA_LEN { | ||||||
|  |                 return None; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             //let tx_ram = self.tx_msg_ram();
 | ||||||
|  |             let mut data = [0u8; 64]; | ||||||
|  |             data_from_tx_buffer(&mut data, mailbox, len as usize); | ||||||
|  | 
 | ||||||
|  |             let cd = FdData::new(&data).unwrap(); | ||||||
|  | 
 | ||||||
|  |             let header = if header_reg.fdf().frame_format() == FrameFormat::Fdcan { | ||||||
|  |                 Header::new_fd(id, len, header_reg.rtr().bit(), header_reg.brs().bit()) | ||||||
|  |             } else { | ||||||
|  |                 Header::new(id, len, header_reg.rtr().bit()) | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             Some(FdFrame::new(header, cd)) | ||||||
|  |         } else { | ||||||
|  |             // Abort request failed because the frame was already sent (or being sent) on
 | ||||||
|  |             // the bus. All mailboxes are now free. This can happen for small prescaler
 | ||||||
|  |             // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR
 | ||||||
|  |             // has preempted the execution.
 | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can
 | ||||||
|  |     /// be preserved.
 | ||||||
|  |     //pub fn transmit_preserve<PTX, P>(
 | ||||||
|  |     pub fn write_classic(&self, frame: &ClassicFrame) -> nb::Result<Option<ClassicFrame>, Infallible> { | ||||||
|  |         let queue_is_full = self.tx_queue_is_full(); | ||||||
|  | 
 | ||||||
|  |         let id = frame.header().id(); | ||||||
|  | 
 | ||||||
|  |         // If the queue is full,
 | ||||||
|  |         // Discard the first slot with a lower priority message
 | ||||||
|  |         let (idx, pending_frame) = if queue_is_full { | ||||||
|  |             if self.is_available(0, id) { | ||||||
|  |                 (0, self.abort_pending_mailbox(0)) | ||||||
|  |             } else if self.is_available(1, id) { | ||||||
|  |                 (1, self.abort_pending_mailbox(1)) | ||||||
|  |             } else if self.is_available(2, id) { | ||||||
|  |                 (2, self.abort_pending_mailbox(2)) | ||||||
|  |             } else { | ||||||
|  |                 // For now we bail when there is no lower priority slot available
 | ||||||
|  |                 // Can this lead to priority inversion?
 | ||||||
|  |                 return Err(nb::Error::WouldBlock); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             // Read the Write Pointer
 | ||||||
|  |             let idx = self.regs.txfqs().read().tfqpi(); | ||||||
|  | 
 | ||||||
|  |             (idx, None) | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         self.put_tx_frame(idx as usize, frame.header(), frame.data()); | ||||||
|  | 
 | ||||||
|  |         Ok(pending_frame) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can
 | ||||||
|  |     /// be preserved.
 | ||||||
|  |     //pub fn transmit_preserve<PTX, P>(
 | ||||||
|  |     pub fn write_fd(&self, frame: &FdFrame) -> nb::Result<Option<FdFrame>, Infallible> { | ||||||
|  |         let queue_is_full = self.tx_queue_is_full(); | ||||||
|  | 
 | ||||||
|  |         let id = frame.header().id(); | ||||||
|  | 
 | ||||||
|  |         // If the queue is full,
 | ||||||
|  |         // Discard the first slot with a lower priority message
 | ||||||
|  |         let (idx, pending_frame) = if queue_is_full { | ||||||
|  |             if self.is_available(0, id) { | ||||||
|  |                 (0, self.abort_pending_fd_mailbox(0)) | ||||||
|  |             } else if self.is_available(1, id) { | ||||||
|  |                 (1, self.abort_pending_fd_mailbox(1)) | ||||||
|  |             } else if self.is_available(2, id) { | ||||||
|  |                 (2, self.abort_pending_fd_mailbox(2)) | ||||||
|  |             } else { | ||||||
|  |                 // For now we bail when there is no lower priority slot available
 | ||||||
|  |                 // Can this lead to priority inversion?
 | ||||||
|  |                 return Err(nb::Error::WouldBlock); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             // Read the Write Pointer
 | ||||||
|  |             let idx = self.regs.txfqs().read().tfqpi(); | ||||||
|  | 
 | ||||||
|  |             (idx, None) | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         self.put_tx_frame(idx as usize, frame.header(), frame.data()); | ||||||
|  | 
 | ||||||
|  |         Ok(pending_frame) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     fn reset_msg_ram(&mut self) { | ||||||
|  |         self.msg_ram_mut().reset(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     fn enter_init_mode(&mut self) { | ||||||
|  |         self.regs.cccr().modify(|w| w.set_init(true)); | ||||||
|  |         while false == self.regs.cccr().read().init() {} | ||||||
|  |         self.regs.cccr().modify(|w| w.set_cce(true)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Enables or disables loopback mode: Internally connects the TX and RX
 | ||||||
|  |     /// signals together.
 | ||||||
|  |     #[inline] | ||||||
|  |     fn set_loopback_mode(&mut self, mode: LoopbackMode) { | ||||||
|  |         let (test, mon, lbck) = match mode { | ||||||
|  |             LoopbackMode::None => (false, false, false), | ||||||
|  |             LoopbackMode::Internal => (true, true, true), | ||||||
|  |             LoopbackMode::External => (true, false, true), | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         self.set_test_mode(test); | ||||||
|  |         self.set_bus_monitoring_mode(mon); | ||||||
|  | 
 | ||||||
|  |         self.regs.test().modify(|w| w.set_lbck(lbck)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Enables or disables silent mode: Disconnects the TX signal from the pin.
 | ||||||
|  |     #[inline] | ||||||
|  |     fn set_bus_monitoring_mode(&mut self, enabled: bool) { | ||||||
|  |         self.regs.cccr().modify(|w| w.set_mon(enabled)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     fn set_restricted_operations(&mut self, enabled: bool) { | ||||||
|  |         self.regs.cccr().modify(|w| w.set_asm(enabled)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     fn set_normal_operations(&mut self, _enabled: bool) { | ||||||
|  |         self.set_loopback_mode(LoopbackMode::None); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     fn set_test_mode(&mut self, enabled: bool) { | ||||||
|  |         self.regs.cccr().modify(|w| w.set_test(enabled)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     fn set_power_down_mode(&mut self, enabled: bool) { | ||||||
|  |         self.regs.cccr().modify(|w| w.set_csr(enabled)); | ||||||
|  |         while self.regs.cccr().read().csa() != enabled {} | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Moves out of PoweredDownMode and into ConfigMode
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn into_config_mode(mut self, _config: FdCanConfig) { | ||||||
|  |         self.set_power_down_mode(false); | ||||||
|  |         self.enter_init_mode(); | ||||||
|  | 
 | ||||||
|  |         self.reset_msg_ram(); | ||||||
|  | 
 | ||||||
|  |         // check the FDCAN core matches our expections
 | ||||||
|  |         assert!( | ||||||
|  |             self.regs.crel().read().rel() == 3, | ||||||
|  |             "Expected FDCAN core major release 3" | ||||||
|  |         ); | ||||||
|  |         assert!( | ||||||
|  |             self.regs.endn().read().etv() == 0x87654321_u32, | ||||||
|  |             "Error reading endianness test value from FDCAN core" | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |         // Framework specific settings are set here
 | ||||||
|  | 
 | ||||||
|  |         // set TxBuffer to Queue Mode
 | ||||||
|  |         self.regs.txbc().write(|w| w.set_tfqm(true)); | ||||||
|  | 
 | ||||||
|  |         // set standard filters list size to 28
 | ||||||
|  |         // set extended filters list size to 8
 | ||||||
|  |         // REQUIRED: we use the memory map as if these settings are set
 | ||||||
|  |         // instead of re-calculating them.
 | ||||||
|  |         #[cfg(not(stm32h7))] | ||||||
|  |         { | ||||||
|  |             self.regs.rxgfc().modify(|w| { | ||||||
|  |                 w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX); | ||||||
|  |                 w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |         #[cfg(stm32h7)] | ||||||
|  |         { | ||||||
|  |             self.regs | ||||||
|  |                 .sidfc() | ||||||
|  |                 .modify(|w| w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX)); | ||||||
|  |             self.regs | ||||||
|  |                 .xidfc() | ||||||
|  |                 .modify(|w| w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /* | ||||||
|  |         for fid in 0..crate::can::message_ram::STANDARD_FILTER_MAX { | ||||||
|  |             self.set_standard_filter((fid as u8).into(), StandardFilter::disable()); | ||||||
|  |         } | ||||||
|  |         for fid in 0..Ecrate::can::message_ram::XTENDED_FILTER_MAX { | ||||||
|  |             self.set_extended_filter(fid.into(), ExtendedFilter::disable()); | ||||||
|  |         } | ||||||
|  |         */ | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Disables the CAN interface and returns back the raw peripheral it was created from.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn free(mut self) { | ||||||
|  |         //self.disable_interrupts(Interrupts::all());
 | ||||||
|  | 
 | ||||||
|  |         //TODO check this!
 | ||||||
|  |         self.enter_init_mode(); | ||||||
|  |         self.set_power_down_mode(true); | ||||||
|  |         //self.control.instance
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Applies the settings of a new FdCanConfig See [`FdCanConfig`]
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn apply_config(&mut self, config: FdCanConfig) { | ||||||
|  |         self.set_data_bit_timing(config.dbtr); | ||||||
|  |         self.set_nominal_bit_timing(config.nbtr); | ||||||
|  |         self.set_automatic_retransmit(config.automatic_retransmit); | ||||||
|  |         self.set_transmit_pause(config.transmit_pause); | ||||||
|  |         self.set_frame_transmit(config.frame_transmit); | ||||||
|  |         //self.set_interrupt_line_config(config.interrupt_line_config);
 | ||||||
|  |         self.set_non_iso_mode(config.non_iso_mode); | ||||||
|  |         self.set_edge_filtering(config.edge_filtering); | ||||||
|  |         self.set_protocol_exception_handling(config.protocol_exception_handling); | ||||||
|  |         self.set_global_filter(config.global_filter); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     fn leave_init_mode(&mut self, config: FdCanConfig) { | ||||||
|  |         self.apply_config(config); | ||||||
|  | 
 | ||||||
|  |         self.regs.cccr().modify(|w| w.set_cce(false)); | ||||||
|  |         self.regs.cccr().modify(|w| w.set_init(false)); | ||||||
|  |         while self.regs.cccr().read().init() == true {} | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Moves out of ConfigMode and into InternalLoopbackMode
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn into_internal_loopback(mut self, config: FdCanConfig) { | ||||||
|  |         self.set_loopback_mode(LoopbackMode::Internal); | ||||||
|  |         self.leave_init_mode(config); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Moves out of ConfigMode and into ExternalLoopbackMode
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn into_external_loopback(mut self, config: FdCanConfig) { | ||||||
|  |         self.set_loopback_mode(LoopbackMode::External); | ||||||
|  |         self.leave_init_mode(config); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Moves out of ConfigMode and into RestrictedOperationMode
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn into_restricted(mut self, config: FdCanConfig) { | ||||||
|  |         self.set_restricted_operations(true); | ||||||
|  |         self.leave_init_mode(config); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Moves out of ConfigMode and into NormalOperationMode
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn into_normal(mut self, config: FdCanConfig) { | ||||||
|  |         self.set_normal_operations(true); | ||||||
|  |         self.leave_init_mode(config); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Moves out of ConfigMode and into BusMonitoringMode
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn into_bus_monitoring(mut self, config: FdCanConfig) { | ||||||
|  |         self.set_bus_monitoring_mode(true); | ||||||
|  |         self.leave_init_mode(config); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Moves out of ConfigMode and into Testmode
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn into_test_mode(mut self, config: FdCanConfig) { | ||||||
|  |         self.set_test_mode(true); | ||||||
|  |         self.leave_init_mode(config); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Moves out of ConfigMode and into PoweredDownmode
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn into_powered_down(mut self, config: FdCanConfig) { | ||||||
|  |         self.set_power_down_mode(true); | ||||||
|  |         self.leave_init_mode(config); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Configures the bit timings.
 | ||||||
|  |     ///
 | ||||||
|  |     /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
 | ||||||
|  |     /// parameters as follows:
 | ||||||
|  |     ///
 | ||||||
|  |     /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
 | ||||||
|  |     ///   This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
 | ||||||
|  |     /// - *Sample Point*: Should normally be left at the default value of 87.5%.
 | ||||||
|  |     /// - *SJW*: Should normally be left at the default value of 1.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
 | ||||||
|  |     /// parameter to this method.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn set_nominal_bit_timing(&mut self, btr: NominalBitTiming) { | ||||||
|  |         //self.control.config.nbtr = btr;
 | ||||||
|  | 
 | ||||||
|  |         self.regs.nbtp().write(|w| { | ||||||
|  |             w.set_nbrp(btr.nbrp() - 1); | ||||||
|  |             w.set_ntseg1(btr.ntseg1() - 1); | ||||||
|  |             w.set_ntseg2(btr.ntseg2() - 1); | ||||||
|  |             w.set_nsjw(btr.nsjw() - 1); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Configures the data bit timings for the FdCan Variable Bitrates.
 | ||||||
|  |     /// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn set_data_bit_timing(&mut self, btr: DataBitTiming) { | ||||||
|  |         //self.control.config.dbtr = btr;
 | ||||||
|  | 
 | ||||||
|  |         self.regs.dbtp().write(|w| { | ||||||
|  |             w.set_dbrp(btr.dbrp() - 1); | ||||||
|  |             w.set_dtseg1(btr.dtseg1() - 1); | ||||||
|  |             w.set_dtseg2(btr.dtseg2() - 1); | ||||||
|  |             w.set_dsjw(btr.dsjw() - 1); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Enables or disables automatic retransmission of messages
 | ||||||
|  |     ///
 | ||||||
|  |     /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
 | ||||||
|  |     /// util it can be sent. Otherwise, it will try only once to send each frame.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Automatic retransmission is enabled by default.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn set_automatic_retransmit(&mut self, enabled: bool) { | ||||||
|  |         self.regs.cccr().modify(|w| w.set_dar(!enabled)); | ||||||
|  |         //self.control.config.automatic_retransmit = enabled;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Configures the transmit pause feature. See
 | ||||||
|  |     /// [`FdCanConfig::set_transmit_pause`]
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn set_transmit_pause(&mut self, enabled: bool) { | ||||||
|  |         self.regs.cccr().modify(|w| w.set_txp(!enabled)); | ||||||
|  |         //self.control.config.transmit_pause = enabled;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Configures non-iso mode. See [`FdCanConfig::set_non_iso_mode`]
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn set_non_iso_mode(&mut self, enabled: bool) { | ||||||
|  |         self.regs.cccr().modify(|w| w.set_niso(enabled)); | ||||||
|  |         //self.control.config.non_iso_mode = enabled;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Configures edge filtering. See [`FdCanConfig::set_edge_filtering`]
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn set_edge_filtering(&mut self, enabled: bool) { | ||||||
|  |         self.regs.cccr().modify(|w| w.set_efbi(enabled)); | ||||||
|  |         //self.control.config.edge_filtering = enabled;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Configures frame transmission mode. See
 | ||||||
|  |     /// [`FdCanConfig::set_frame_transmit`]
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn set_frame_transmit(&mut self, fts: FrameTransmissionConfig) { | ||||||
|  |         let (fdoe, brse) = match fts { | ||||||
|  |             FrameTransmissionConfig::ClassicCanOnly => (false, false), | ||||||
|  |             FrameTransmissionConfig::AllowFdCan => (true, false), | ||||||
|  |             FrameTransmissionConfig::AllowFdCanAndBRS => (true, true), | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         self.regs.cccr().modify(|w| { | ||||||
|  |             w.set_fdoe(fdoe); | ||||||
|  |             #[cfg(stm32h7)] | ||||||
|  |             w.set_bse(brse); | ||||||
|  |             #[cfg(not(stm32h7))] | ||||||
|  |             w.set_brse(brse); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         //self.control.config.frame_transmit = fts;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Sets the protocol exception handling on/off
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn set_protocol_exception_handling(&mut self, enabled: bool) { | ||||||
|  |         self.regs.cccr().modify(|w| w.set_pxhd(!enabled)); | ||||||
|  | 
 | ||||||
|  |         //self.control.config.protocol_exception_handling = enabled;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Configures and resets the timestamp counter
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) { | ||||||
|  |         #[cfg(stm32h7)] | ||||||
|  |         let (tcp, tss) = match select { | ||||||
|  |             TimestampSource::None => (0, 0), | ||||||
|  |             TimestampSource::Prescaler(p) => (p as u8, 1), | ||||||
|  |             TimestampSource::FromTIM3 => (0, 2), | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         #[cfg(not(stm32h7))] | ||||||
|  |         let (tcp, tss) = match select { | ||||||
|  |             TimestampSource::None => (0, stm32_metapac::can::vals::Tss::ZERO), | ||||||
|  |             TimestampSource::Prescaler(p) => (p as u8, stm32_metapac::can::vals::Tss::INCREMENT), | ||||||
|  |             TimestampSource::FromTIM3 => (0, stm32_metapac::can::vals::Tss::EXTERNAL), | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         self.regs.tscc().write(|w| { | ||||||
|  |             w.set_tcp(tcp); | ||||||
|  |             w.set_tss(tss); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         //self.control.config.timestamp_source = select;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[cfg(not(stm32h7))] | ||||||
|  |     /// Configures the global filter settings
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn set_global_filter(&mut self, filter: GlobalFilter) { | ||||||
|  |         let anfs = match filter.handle_standard_frames { | ||||||
|  |             crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_0, | ||||||
|  |             crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_1, | ||||||
|  |             crate::can::fd::config::NonMatchingFilter::Reject => stm32_metapac::can::vals::Anfs::REJECT, | ||||||
|  |         }; | ||||||
|  |         let anfe = match filter.handle_extended_frames { | ||||||
|  |             crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => stm32_metapac::can::vals::Anfe::ACCEPT_FIFO_0, | ||||||
|  |             crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => stm32_metapac::can::vals::Anfe::ACCEPT_FIFO_1, | ||||||
|  |             crate::can::fd::config::NonMatchingFilter::Reject => stm32_metapac::can::vals::Anfe::REJECT, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         self.regs.rxgfc().modify(|w| { | ||||||
|  |             w.set_anfs(anfs); | ||||||
|  |             w.set_anfe(anfe); | ||||||
|  |             w.set_rrfs(filter.reject_remote_standard_frames); | ||||||
|  |             w.set_rrfe(filter.reject_remote_extended_frames); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[cfg(stm32h7)] | ||||||
|  |     /// Configures the global filter settings
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn set_global_filter(&mut self, filter: GlobalFilter) { | ||||||
|  |         let anfs = match filter.handle_standard_frames { | ||||||
|  |             crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => 0, | ||||||
|  |             crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => 1, | ||||||
|  |             crate::can::fd::config::NonMatchingFilter::Reject => 2, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         let anfe = match filter.handle_extended_frames { | ||||||
|  |             crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => 0, | ||||||
|  |             crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => 1, | ||||||
|  |             crate::can::fd::config::NonMatchingFilter::Reject => 2, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         self.regs.gfc().modify(|w| { | ||||||
|  |             w.set_anfs(anfs); | ||||||
|  |             w.set_anfe(anfe); | ||||||
|  |             w.set_rrfs(filter.reject_remote_standard_frames); | ||||||
|  |             w.set_rrfe(filter.reject_remote_extended_frames); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn make_id(id: u32, extended: bool) -> embedded_can::Id { | ||||||
|  |     if extended { | ||||||
|  |         embedded_can::Id::from(unsafe { embedded_can::ExtendedId::new_unchecked(id & 0x1FFFFFFF) }) | ||||||
|  |     } else { | ||||||
|  |         embedded_can::Id::from(unsafe { embedded_can::StandardId::new_unchecked((id & 0x000007FF) as u16) }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn put_tx_header(mailbox: &mut TxBufferElement, header: &Header) { | ||||||
|  |     let (id, id_type) = match header.id() { | ||||||
|  |         embedded_can::Id::Standard(id) => (id.as_raw() as u32, IdType::StandardId), | ||||||
|  |         embedded_can::Id::Extended(id) => (id.as_raw() as u32, IdType::ExtendedId), | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     // Use FDCAN only for DLC > 8. FDCAN users can revise this if required.
 | ||||||
|  |     let frame_format = if header.len() > 8 || header.fdcan() { | ||||||
|  |         FrameFormat::Fdcan | ||||||
|  |     } else { | ||||||
|  |         FrameFormat::Standard | ||||||
|  |     }; | ||||||
|  |     let brs = header.len() > 8 || header.bit_rate_switching(); | ||||||
|  | 
 | ||||||
|  |     mailbox.header.write(|w| { | ||||||
|  |         unsafe { w.id().bits(id) } | ||||||
|  |             .rtr() | ||||||
|  |             .bit(header.len() == 0 && header.rtr()) | ||||||
|  |             .xtd() | ||||||
|  |             .set_id_type(id_type) | ||||||
|  |             .set_len(DataLength::new(header.len(), frame_format)) | ||||||
|  |             .set_event(Event::NoEvent) | ||||||
|  |             .fdf() | ||||||
|  |             .set_format(frame_format) | ||||||
|  |             .brs() | ||||||
|  |             .bit(brs) | ||||||
|  |         //esi.set_error_indicator(//TODO//)
 | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn put_tx_data(mailbox: &mut TxBufferElement, buffer: &[u8]) { | ||||||
|  |     let mut lbuffer = [0_u32; 16]; | ||||||
|  |     let len = buffer.len(); | ||||||
|  |     let data = unsafe { slice::from_raw_parts_mut(lbuffer.as_mut_ptr() as *mut u8, len) }; | ||||||
|  |     data[..len].copy_from_slice(&buffer[..len]); | ||||||
|  |     let data_len = ((len) + 3) / 4; | ||||||
|  |     for (register, byte) in mailbox.data.iter_mut().zip(lbuffer[..data_len].iter()) { | ||||||
|  |         unsafe { register.write(*byte) }; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn data_from_fifo(buffer: &mut [u8], mailbox: &RxFifoElement, len: usize) { | ||||||
|  |     for (i, register) in mailbox.data.iter().enumerate() { | ||||||
|  |         let register_value = register.read(); | ||||||
|  |         let register_bytes = unsafe { slice::from_raw_parts(®ister_value as *const u32 as *const u8, 4) }; | ||||||
|  |         let num_bytes = (len) - i * 4; | ||||||
|  |         if num_bytes <= 4 { | ||||||
|  |             buffer[i * 4..i * 4 + num_bytes].copy_from_slice(®ister_bytes[..num_bytes]); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         buffer[i * 4..(i + 1) * 4].copy_from_slice(register_bytes); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn data_from_tx_buffer(buffer: &mut [u8], mailbox: &TxBufferElement, len: usize) { | ||||||
|  |     for (i, register) in mailbox.data.iter().enumerate() { | ||||||
|  |         let register_value = register.read(); | ||||||
|  |         let register_bytes = unsafe { slice::from_raw_parts(®ister_value as *const u32 as *const u8, 4) }; | ||||||
|  |         let num_bytes = (len) - i * 4; | ||||||
|  |         if num_bytes <= 4 { | ||||||
|  |             buffer[i * 4..i * 4 + num_bytes].copy_from_slice(®ister_bytes[..num_bytes]); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         buffer[i * 4..(i + 1) * 4].copy_from_slice(register_bytes); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<&RxFifoElement> for ClassicFrame { | ||||||
|  |     fn from(mailbox: &RxFifoElement) -> Self { | ||||||
|  |         let header_reg = mailbox.header.read(); | ||||||
|  | 
 | ||||||
|  |         let id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); | ||||||
|  |         let dlc = header_reg.to_data_length().len(); | ||||||
|  |         let len = dlc as usize; | ||||||
|  | 
 | ||||||
|  |         let mut buffer: [u8; 64] = [0; 64]; | ||||||
|  |         data_from_fifo(&mut buffer, mailbox, len); | ||||||
|  |         let data = ClassicData::new(&buffer[0..len]); | ||||||
|  |         let header = Header::new(id, dlc, header_reg.rtr().bits()); | ||||||
|  |         ClassicFrame::new(header, data.unwrap()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn extract_frame(mailbox: &RxFifoElement, buffer: &mut [u8]) -> Option<(Header, u16)> { | ||||||
|  |     let header_reg = mailbox.header.read(); | ||||||
|  | 
 | ||||||
|  |     let id = make_id(header_reg.id().bits(), header_reg.xtd().bits()); | ||||||
|  |     let dlc = header_reg.to_data_length().len(); | ||||||
|  |     let len = dlc as usize; | ||||||
|  |     let timestamp = header_reg.txts().bits; | ||||||
|  |     if len > buffer.len() { | ||||||
|  |         return None; | ||||||
|  |     } | ||||||
|  |     data_from_fifo(buffer, mailbox, len); | ||||||
|  |     let header = if header_reg.fdf().bits { | ||||||
|  |         Header::new_fd(id, dlc, header_reg.rtr().bits(), header_reg.brs().bits()) | ||||||
|  |     } else { | ||||||
|  |         Header::new(id, dlc, header_reg.rtr().bits()) | ||||||
|  |     }; | ||||||
|  |     Some((header, timestamp)) | ||||||
|  | } | ||||||
| @ -1,16 +1,15 @@ | |||||||
|  | #[allow(unused_variables)] | ||||||
| use core::future::poll_fn; | use core::future::poll_fn; | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
| use core::ops::{Deref, DerefMut}; |  | ||||||
| use core::task::Poll; | use core::task::Poll; | ||||||
| 
 | 
 | ||||||
|  | pub mod fd; | ||||||
| use cfg_if::cfg_if; | use cfg_if::cfg_if; | ||||||
| use embassy_hal_internal::{into_ref, PeripheralRef}; | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||||
| pub use fdcan::frame::{FrameFormat, RxFrameInfo, TxFrameHeader}; | use fd::config::*; | ||||||
| pub use fdcan::id::{ExtendedId, Id, StandardId}; | use fd::filter::*; | ||||||
| use fdcan::message_ram::RegisterBlock; |  | ||||||
| use fdcan::{self, LastErrorCode}; |  | ||||||
| pub use fdcan::{config, filter}; |  | ||||||
| 
 | 
 | ||||||
|  | use crate::can::fd::peripheral::Registers; | ||||||
| use crate::gpio::sealed::AFType; | use crate::gpio::sealed::AFType; | ||||||
| use crate::interrupt::typelevel::Interrupt; | use crate::interrupt::typelevel::Interrupt; | ||||||
| use crate::rcc::RccPeripheral; | use crate::rcc::RccPeripheral; | ||||||
| @ -20,127 +19,14 @@ pub mod enums; | |||||||
| use enums::*; | use enums::*; | ||||||
| pub mod util; | pub mod util; | ||||||
| 
 | 
 | ||||||
| /// CAN Frame returned by read
 | pub mod frame; | ||||||
| pub struct RxFrame { | use frame::*; | ||||||
|     /// CAN Header info: frame ID, data length and other meta
 |  | ||||||
|     pub header: RxFrameInfo, |  | ||||||
|     /// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data
 |  | ||||||
|     pub data: Data, |  | ||||||
|     /// Reception time.
 |  | ||||||
|     #[cfg(feature = "time")] |  | ||||||
|     pub timestamp: embassy_time::Instant, |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| /// CAN frame used for write
 | #[cfg(feature = "time")] | ||||||
| pub struct TxFrame { | type Timestamp = embassy_time::Instant; | ||||||
|     /// CAN Header info: frame ID, data length and other meta
 |  | ||||||
|     pub header: TxFrameHeader, |  | ||||||
|     /// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data
 |  | ||||||
|     pub data: Data, |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| impl TxFrame { | #[cfg(not(feature = "time"))] | ||||||
|     /// Create new TX frame from header and data
 | type Timestamp = u16; | ||||||
|     pub fn new(header: TxFrameHeader, data: &[u8]) -> Option<Self> { |  | ||||||
|         if data.len() < header.len as usize { |  | ||||||
|             return None; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         let Some(data) = Data::new(data) else { return None }; |  | ||||||
| 
 |  | ||||||
|         Some(TxFrame { header, data }) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn from_preserved(header: TxFrameHeader, data32: &[u32]) -> Option<Self> { |  | ||||||
|         let mut data = [0u8; 64]; |  | ||||||
| 
 |  | ||||||
|         for i in 0..data32.len() { |  | ||||||
|             data[4 * i..][..4].copy_from_slice(&data32[i].to_le_bytes()); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         let Some(data) = Data::new(&data) else { return None }; |  | ||||||
| 
 |  | ||||||
|         Some(TxFrame { header, data }) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Access frame data. Slice length will match header.
 |  | ||||||
|     pub fn data(&self) -> &[u8] { |  | ||||||
|         &self.data.bytes[..(self.header.len as usize)] |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl RxFrame { |  | ||||||
|     pub(crate) fn new( |  | ||||||
|         header: RxFrameInfo, |  | ||||||
|         data: &[u8], |  | ||||||
|         #[cfg(feature = "time")] timestamp: embassy_time::Instant, |  | ||||||
|     ) -> Self { |  | ||||||
|         let data = Data::new(&data).unwrap_or_else(|| Data::empty()); |  | ||||||
| 
 |  | ||||||
|         RxFrame { |  | ||||||
|             header, |  | ||||||
|             data, |  | ||||||
|             #[cfg(feature = "time")] |  | ||||||
|             timestamp, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Access frame data. Slice length will match header.
 |  | ||||||
|     pub fn data(&self) -> &[u8] { |  | ||||||
|         &self.data.bytes[..(self.header.len as usize)] |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Payload of a (FD)CAN data frame.
 |  | ||||||
| ///
 |  | ||||||
| /// Contains 0 to 64 Bytes of data.
 |  | ||||||
| #[derive(Debug, Copy, Clone)] |  | ||||||
| pub struct Data { |  | ||||||
|     pub(crate) bytes: [u8; 64], |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Data { |  | ||||||
|     /// Creates a data payload from a raw byte slice.
 |  | ||||||
|     ///
 |  | ||||||
|     /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
 |  | ||||||
|     /// cannot be represented with an FDCAN DLC.
 |  | ||||||
|     pub fn new(data: &[u8]) -> Option<Self> { |  | ||||||
|         if !Data::is_valid_len(data.len()) { |  | ||||||
|             return None; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         let mut bytes = [0; 64]; |  | ||||||
|         bytes[..data.len()].copy_from_slice(data); |  | ||||||
| 
 |  | ||||||
|         Some(Self { bytes }) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Raw read access to data.
 |  | ||||||
|     pub fn raw(&self) -> &[u8] { |  | ||||||
|         &self.bytes |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Checks if the length can be encoded in FDCAN DLC field.
 |  | ||||||
|     pub const fn is_valid_len(len: usize) -> bool { |  | ||||||
|         match len { |  | ||||||
|             0..=8 => true, |  | ||||||
|             12 => true, |  | ||||||
|             16 => true, |  | ||||||
|             20 => true, |  | ||||||
|             24 => true, |  | ||||||
|             32 => true, |  | ||||||
|             48 => true, |  | ||||||
|             64 => true, |  | ||||||
|             _ => false, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Creates an empty data payload containing 0 bytes.
 |  | ||||||
|     #[inline] |  | ||||||
|     pub const fn empty() -> Self { |  | ||||||
|         Self { bytes: [0; 64] } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| /// Interrupt handler channel 0.
 | /// Interrupt handler channel 0.
 | ||||||
| pub struct IT0InterruptHandler<T: Instance> { | pub struct IT0InterruptHandler<T: Instance> { | ||||||
| @ -172,7 +58,9 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if ir.rfn(0) { |         if ir.rfn(0) { | ||||||
|             regs.ir().write(|w| w.set_rfn(0, true)); |             let fifonr = 0 as usize; | ||||||
|  |             regs.ir().write(|w| w.set_rfn(fifonr, true)); | ||||||
|  | 
 | ||||||
|             T::state().rx_waker.wake(); |             T::state().rx_waker.wake(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -192,44 +80,82 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT1Interrupt> for IT1Interrup | |||||||
|     unsafe fn on_interrupt() {} |     unsafe fn on_interrupt() {} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl BusError { | /// Allows for Transmit Operations
 | ||||||
|     fn try_from(lec: LastErrorCode) -> Option<BusError> { | pub trait Transmit {} | ||||||
|         match lec { | /// Allows for Receive Operations
 | ||||||
|             LastErrorCode::AckError => Some(BusError::Acknowledge), | pub trait Receive {} | ||||||
|             // `0` data bit encodes a dominant state. `1` data bit is recessive.
 | 
 | ||||||
|             // Bit0Error: During transmit, the node wanted to send a 0 but monitored a 1
 | /// Allows for the FdCan Instance to be released or to enter ConfigMode
 | ||||||
|             LastErrorCode::Bit0Error => Some(BusError::BitRecessive), | pub struct PoweredDownMode; | ||||||
|             LastErrorCode::Bit1Error => Some(BusError::BitDominant), | /// Allows for the configuration for the Instance
 | ||||||
|             LastErrorCode::CRCError => Some(BusError::Crc), | pub struct ConfigMode; | ||||||
|             LastErrorCode::FormError => Some(BusError::Form), | /// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without
 | ||||||
|             LastErrorCode::StuffError => Some(BusError::Stuff), | /// affecting a running CAN system connected to the FDCAN_TX and FDCAN_RX pins. In this
 | ||||||
|             _ => None, | /// mode, FDCAN_RX pin is disconnected from the FDCAN and FDCAN_TX pin is held
 | ||||||
|         } | /// recessive.
 | ||||||
|     } | pub struct InternalLoopbackMode; | ||||||
| } | impl Transmit for InternalLoopbackMode {} | ||||||
|  | impl Receive for InternalLoopbackMode {} | ||||||
|  | /// This mode is provided for hardware self-test. To be independent from external stimulation,
 | ||||||
|  | /// the FDCAN ignores acknowledge errors (recessive bit sampled in the acknowledge slot of a
 | ||||||
|  | /// data / remote frame) in Loop Back mode. In this mode the FDCAN performs an internal
 | ||||||
|  | /// feedback from its transmit output to its receive input. The actual value of the FDCAN_RX
 | ||||||
|  | /// input pin is disregarded by the FDCAN. The transmitted messages can be monitored at the
 | ||||||
|  | /// FDCAN_TX transmit pin.
 | ||||||
|  | pub struct ExternalLoopbackMode; | ||||||
|  | impl Transmit for ExternalLoopbackMode {} | ||||||
|  | impl Receive for ExternalLoopbackMode {} | ||||||
|  | /// The normal use of the FdCan instance after configurations
 | ||||||
|  | pub struct NormalOperationMode; | ||||||
|  | impl Transmit for NormalOperationMode {} | ||||||
|  | impl Receive for NormalOperationMode {} | ||||||
|  | /// In Restricted operation mode the node is able to receive data and remote frames and to give
 | ||||||
|  | /// acknowledge to valid frames, but it does not send data frames, remote frames, active error
 | ||||||
|  | /// frames, or overload frames. In case of an error condition or overload condition, it does not
 | ||||||
|  | /// send dominant bits, instead it waits for the occurrence of bus idle condition to resynchronize
 | ||||||
|  | /// itself to the CAN communication. The error counters for transmit and receive are frozen while
 | ||||||
|  | /// error logging (can_errors) is active. TODO: automatically enter in this mode?
 | ||||||
|  | pub struct RestrictedOperationMode; | ||||||
|  | impl Receive for RestrictedOperationMode {} | ||||||
|  | ///  In Bus monitoring mode (for more details refer to ISO11898-1, 10.12 Bus monitoring),
 | ||||||
|  | /// the FDCAN is able to receive valid data frames and valid remote frames, but cannot start a
 | ||||||
|  | /// transmission. In this mode, it sends only recessive bits on the CAN bus. If the FDCAN is
 | ||||||
|  | /// required to send a dominant bit (ACK bit, overload flag, active error flag), the bit is
 | ||||||
|  | /// rerouted internally so that the FDCAN can monitor it, even if the CAN bus remains in recessive
 | ||||||
|  | /// state. In Bus monitoring mode the TXBRP register is held in reset state. The Bus monitoring
 | ||||||
|  | /// mode can be used to analyze the traffic on a CAN bus without affecting it by the transmission
 | ||||||
|  | /// of dominant bits.
 | ||||||
|  | pub struct BusMonitoringMode; | ||||||
|  | impl Receive for BusMonitoringMode {} | ||||||
|  | /// Test mode must be used for production tests or self test only. The software control for
 | ||||||
|  | /// FDCAN_TX pin interferes with all CAN protocol functions. It is not recommended to use test
 | ||||||
|  | /// modes for application.
 | ||||||
|  | pub struct TestMode; | ||||||
| 
 | 
 | ||||||
| /// Operating modes trait
 | /// Operating modes trait
 | ||||||
| pub trait FdcanOperatingMode {} | pub trait FdcanOperatingMode {} | ||||||
| impl FdcanOperatingMode for fdcan::PoweredDownMode {} | impl FdcanOperatingMode for PoweredDownMode {} | ||||||
| impl FdcanOperatingMode for fdcan::ConfigMode {} | impl FdcanOperatingMode for ConfigMode {} | ||||||
| impl FdcanOperatingMode for fdcan::InternalLoopbackMode {} | impl FdcanOperatingMode for InternalLoopbackMode {} | ||||||
| impl FdcanOperatingMode for fdcan::ExternalLoopbackMode {} | impl FdcanOperatingMode for ExternalLoopbackMode {} | ||||||
| impl FdcanOperatingMode for fdcan::NormalOperationMode {} | impl FdcanOperatingMode for NormalOperationMode {} | ||||||
| impl FdcanOperatingMode for fdcan::RestrictedOperationMode {} | impl FdcanOperatingMode for RestrictedOperationMode {} | ||||||
| impl FdcanOperatingMode for fdcan::BusMonitoringMode {} | impl FdcanOperatingMode for BusMonitoringMode {} | ||||||
| impl FdcanOperatingMode for fdcan::TestMode {} | impl FdcanOperatingMode for TestMode {} | ||||||
| 
 | 
 | ||||||
| /// FDCAN Instance
 | /// FDCAN Instance
 | ||||||
| pub struct Fdcan<'d, T: Instance, M: FdcanOperatingMode> { | pub struct Fdcan<'d, T: Instance, M: FdcanOperatingMode> { | ||||||
|  |     config: crate::can::fd::config::FdCanConfig, | ||||||
|     /// Reference to internals.
 |     /// Reference to internals.
 | ||||||
|     pub can: fdcan::FdCan<FdcanInstance<'d, T>, M>, |     instance: FdcanInstance<'d, T>, | ||||||
|  |     _mode: PhantomData<M>, | ||||||
|     ns_per_timer_tick: u64, // For FDCAN internal timer
 |     ns_per_timer_tick: u64, // For FDCAN internal timer
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn calc_ns_per_timer_tick<T: Instance>(mode: config::FrameTransmissionConfig) -> u64 { | fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 { | ||||||
|     match mode { |     match mode { | ||||||
|         // Use timestamp from Rx FIFO to adjust timestamp reported to user
 |         // Use timestamp from Rx FIFO to adjust timestamp reported to user
 | ||||||
|         config::FrameTransmissionConfig::ClassicCanOnly => { |         crate::can::fd::config::FrameTransmissionConfig::ClassicCanOnly => { | ||||||
|             let freq = T::frequency(); |             let freq = T::frequency(); | ||||||
|             let prescale: u64 = |             let prescale: u64 = | ||||||
|                 ({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64; |                 ({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64; | ||||||
| @ -242,17 +168,22 @@ fn calc_ns_per_timer_tick<T: Instance>(mode: config::FrameTransmissionConfig) -> | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[cfg(feature = "time")] | #[cfg(feature = "time")] | ||||||
| fn calc_timestamp<T: Instance>(ns_per_timer_tick: u64, ts_val: u16) -> embassy_time::Instant { | fn calc_timestamp<T: Instance>(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { | ||||||
|     let now_embassy = embassy_time::Instant::now(); |     let now_embassy = embassy_time::Instant::now(); | ||||||
|     if ns_per_timer_tick == 0 { |     if ns_per_timer_tick == 0 { | ||||||
|         return now_embassy; |         return now_embassy; | ||||||
|     } |     } | ||||||
|     let now_can = { T::regs().tscv().read().tsc() }; |     let cantime = { T::regs().tscv().read().tsc() }; | ||||||
|     let delta = now_can.overflowing_sub(ts_val).0 as u64; |     let delta = cantime.overflowing_sub(ts_val).0 as u64; | ||||||
|     let ns = ns_per_timer_tick * delta as u64; |     let ns = ns_per_timer_tick * delta as u64; | ||||||
|     now_embassy - embassy_time::Duration::from_nanos(ns) |     now_embassy - embassy_time::Duration::from_nanos(ns) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[cfg(not(feature = "time"))] | ||||||
|  | fn calc_timestamp<T: Instance>(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { | ||||||
|  |     ts_val | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fn curr_error<T: Instance>() -> Option<BusError> { | fn curr_error<T: Instance>() -> Option<BusError> { | ||||||
|     let err = { T::regs().psr().read() }; |     let err = { T::regs().psr().read() }; | ||||||
|     if err.bo() { |     if err.bo() { | ||||||
| @ -269,14 +200,14 @@ fn curr_error<T: Instance>() -> Option<BusError> { | |||||||
|                 let lec = err.lec().to_bits(); |                 let lec = err.lec().to_bits(); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if let Ok(err) = LastErrorCode::try_from(lec) { |         if let Ok(err) = BusError::try_from(lec) { | ||||||
|             return BusError::try_from(err); |             return Some(err); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     None |     None | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { | impl<'d, T: Instance> Fdcan<'d, T, ConfigMode> { | ||||||
|     /// Creates a new Fdcan instance, keeping the peripheral in sleep mode.
 |     /// Creates a new Fdcan instance, keeping the peripheral in sleep mode.
 | ||||||
|     /// You must call [Fdcan::enable_non_blocking] to use the peripheral.
 |     /// You must call [Fdcan::enable_non_blocking] to use the peripheral.
 | ||||||
|     pub fn new( |     pub fn new( | ||||||
| @ -286,7 +217,7 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { | |||||||
|         _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>> |         _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>> | ||||||
|             + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> |             + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> | ||||||
|             + 'd, |             + 'd, | ||||||
|     ) -> Fdcan<'d, T, fdcan::ConfigMode> { |     ) -> Fdcan<'d, T, ConfigMode> { | ||||||
|         into_ref!(peri, rx, tx); |         into_ref!(peri, rx, tx); | ||||||
| 
 | 
 | ||||||
|         rx.set_as_af(rx.af_num(), AFType::Input); |         rx.set_as_af(rx.af_num(), AFType::Input); | ||||||
| @ -294,11 +225,12 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { | |||||||
| 
 | 
 | ||||||
|         T::enable_and_reset(); |         T::enable_and_reset(); | ||||||
| 
 | 
 | ||||||
|  |         let mut config = crate::can::fd::config::FdCanConfig::default(); | ||||||
|  |         T::registers().into_config_mode(config); | ||||||
|  | 
 | ||||||
|         rx.set_as_af(rx.af_num(), AFType::Input); |         rx.set_as_af(rx.af_num(), AFType::Input); | ||||||
|         tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |         tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||||||
| 
 | 
 | ||||||
|         let mut can = fdcan::FdCan::new(FdcanInstance(peri)).into_config_mode(); |  | ||||||
| 
 |  | ||||||
|         T::configure_msg_ram(); |         T::configure_msg_ram(); | ||||||
|         unsafe { |         unsafe { | ||||||
|             // Enable timestamping
 |             // Enable timestamping
 | ||||||
| @ -308,6 +240,7 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { | |||||||
|                 .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT)); |                 .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT)); | ||||||
|             #[cfg(stm32h7)] |             #[cfg(stm32h7)] | ||||||
|             T::regs().tscc().write(|w| w.set_tss(0x01)); |             T::regs().tscc().write(|w| w.set_tss(0x01)); | ||||||
|  |             config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1); | ||||||
| 
 | 
 | ||||||
|             T::IT0Interrupt::unpend(); // Not unsafe
 |             T::IT0Interrupt::unpend(); // Not unsafe
 | ||||||
|             T::IT0Interrupt::enable(); |             T::IT0Interrupt::enable(); | ||||||
| @ -320,38 +253,104 @@ impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> { | |||||||
|             T::regs().txbtie().write(|w| w.0 = 0xffff_ffff); |             T::regs().txbtie().write(|w| w.0 = 0xffff_ffff); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo0NewMsg); |         T::regs().ie().modify(|w| { | ||||||
|         can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo1NewMsg); |             w.set_rfne(0, true); // Rx Fifo 0 New Msg
 | ||||||
|         can.enable_interrupt(fdcan::interrupt::Interrupt::TxComplete); |             w.set_rfne(1, true); // Rx Fifo 1 New Msg
 | ||||||
|         can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_0, true); |             w.set_tce(true); //  Tx Complete
 | ||||||
|         can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_1, true); |         }); | ||||||
|  |         T::regs().ile().modify(|w| { | ||||||
|  |             w.set_eint0(true); // Interrupt Line 0
 | ||||||
|  |             w.set_eint1(true); // Interrupt Line 1
 | ||||||
|  |         }); | ||||||
| 
 | 
 | ||||||
|         let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(can.get_config().frame_transmit); |         let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(config.frame_transmit); | ||||||
|         Self { can, ns_per_timer_tick } |         Self { | ||||||
|  |             config, | ||||||
|  |             instance: FdcanInstance(peri), | ||||||
|  |             _mode: PhantomData::<ConfigMode>, | ||||||
|  |             ns_per_timer_tick, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Get configuration
 | ||||||
|  |     pub fn config(&self) -> crate::can::fd::config::FdCanConfig { | ||||||
|  |         return self.config; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Set configuration
 | ||||||
|  |     pub fn set_config(&mut self, config: crate::can::fd::config::FdCanConfig) { | ||||||
|  |         self.config = config; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Configures the bit timings calculated from supplied bitrate.
 |     /// Configures the bit timings calculated from supplied bitrate.
 | ||||||
|     pub fn set_bitrate(&mut self, bitrate: u32) { |     pub fn set_bitrate(&mut self, bitrate: u32) { | ||||||
|         let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); |         let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); | ||||||
|         self.can.set_nominal_bit_timing(config::NominalBitTiming { | 
 | ||||||
|  |         let nbtr = crate::can::fd::config::NominalBitTiming { | ||||||
|             sync_jump_width: bit_timing.sync_jump_width, |             sync_jump_width: bit_timing.sync_jump_width, | ||||||
|             prescaler: bit_timing.prescaler, |             prescaler: bit_timing.prescaler, | ||||||
|             seg1: bit_timing.seg1, |             seg1: bit_timing.seg1, | ||||||
|             seg2: bit_timing.seg2, |             seg2: bit_timing.seg2, | ||||||
|         }); |         }; | ||||||
|  |         self.config = self.config.set_nominal_bit_timing(nbtr); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Configures the bit timings for VBR data calculated from supplied bitrate.
 | ||||||
|  |     pub fn set_fd_data_bitrate(&mut self, bitrate: u32, transceiver_delay_compensation: bool) { | ||||||
|  |         let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); | ||||||
|  |         // Note, used existing calcluation for normal(non-VBR) bitrate, appears to work for 250k/1M
 | ||||||
|  |         let nbtr = crate::can::fd::config::DataBitTiming { | ||||||
|  |             transceiver_delay_compensation, | ||||||
|  |             sync_jump_width: bit_timing.sync_jump_width, | ||||||
|  |             prescaler: bit_timing.prescaler, | ||||||
|  |             seg1: bit_timing.seg1, | ||||||
|  |             seg2: bit_timing.seg2, | ||||||
|  |         }; | ||||||
|  |         self.config.frame_transmit = FrameTransmissionConfig::AllowFdCanAndBRS; | ||||||
|  |         self.config = self.config.set_data_bit_timing(nbtr); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Set an Standard Address CAN filter into slot 'id'
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn set_standard_filter(&mut self, slot: StandardFilterSlot, filter: StandardFilter) { | ||||||
|  |         T::registers().msg_ram_mut().filters.flssa[slot as usize].activate(filter); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Set an array of Standard Address CAN filters and overwrite the current set
 | ||||||
|  |     pub fn set_standard_filters(&mut self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) { | ||||||
|  |         for (i, f) in filters.iter().enumerate() { | ||||||
|  |             T::registers().msg_ram_mut().filters.flssa[i].activate(*f); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Set an Extended Address CAN filter into slot 'id'
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn set_extended_filter(&mut self, slot: ExtendedFilterSlot, filter: ExtendedFilter) { | ||||||
|  |         T::registers().msg_ram_mut().filters.flesa[slot as usize].activate(filter); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Set an array of Extended Address CAN filters and overwrite the current set
 | ||||||
|  |     pub fn set_extended_filters(&mut self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) { | ||||||
|  |         for (i, f) in filters.iter().enumerate() { | ||||||
|  |             T::registers().msg_ram_mut().filters.flesa[i].activate(*f); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| macro_rules! impl_transition { | macro_rules! impl_transition { | ||||||
|     ($from_mode:ident, $to_mode:ident, $name:ident, $func: ident) => { |     ($from_mode:ident, $to_mode:ident, $name:ident, $func: ident) => { | ||||||
|         impl<'d, T: Instance> Fdcan<'d, T, fdcan::$from_mode> { |         impl<'d, T: Instance> Fdcan<'d, T, $from_mode> { | ||||||
|             /// Transition from $from_mode:ident mode to $to_mode:ident mode
 |             /// Transition from $from_mode:ident mode to $to_mode:ident mode
 | ||||||
|             pub fn $name(self) -> Fdcan<'d, T, fdcan::$to_mode> { |             pub fn $name(self) -> Fdcan<'d, T, $to_mode> { | ||||||
|                 let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.can.get_config().frame_transmit); |                 let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit); | ||||||
|                 Fdcan { |                 T::registers().$func(self.config); | ||||||
|                     can: self.can.$func(), |                 let ret = Fdcan { | ||||||
|  |                     config: self.config, | ||||||
|  |                     instance: self.instance, | ||||||
|  |                     _mode: PhantomData::<$to_mode>, | ||||||
|                     ns_per_timer_tick, |                     ns_per_timer_tick, | ||||||
|                 } |                 }; | ||||||
|  |                 ret | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| @ -376,38 +375,16 @@ impl_transition!( | |||||||
| 
 | 
 | ||||||
| impl<'d, T: Instance, M: FdcanOperatingMode> Fdcan<'d, T, M> | impl<'d, T: Instance, M: FdcanOperatingMode> Fdcan<'d, T, M> | ||||||
| where | where | ||||||
|     M: fdcan::Transmit, |     M: Transmit, | ||||||
|     M: fdcan::Receive, |     M: Receive, | ||||||
| { | { | ||||||
|     /// Queues the message to be sent but exerts backpressure.  If a lower-priority
 |  | ||||||
|     /// frame is dropped from the mailbox, it is returned.  If no lower-priority frames
 |  | ||||||
|     /// can be replaced, this call asynchronously waits for a frame to be successfully
 |  | ||||||
|     /// transmitted, then tries again.
 |  | ||||||
|     pub async fn write(&mut self, frame: &TxFrame) -> Option<TxFrame> { |  | ||||||
|         poll_fn(|cx| { |  | ||||||
|             T::state().tx_waker.register(cx.waker()); |  | ||||||
|             if let Ok(dropped) = self |  | ||||||
|                 .can |  | ||||||
|                 .transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| { |  | ||||||
|                     TxFrame::from_preserved(hdr, data32) |  | ||||||
|                 }) |  | ||||||
|             { |  | ||||||
|                 return Poll::Ready(dropped.flatten()); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // Couldn't replace any lower priority frames.  Need to wait for some mailboxes
 |  | ||||||
|             // to clear.
 |  | ||||||
|             Poll::Pending |  | ||||||
|         }) |  | ||||||
|         .await |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Flush one of the TX mailboxes.
 |     /// Flush one of the TX mailboxes.
 | ||||||
|     pub async fn flush(&self, mb: fdcan::Mailbox) { |     pub async fn flush(&self, idx: usize) { | ||||||
|         poll_fn(|cx| { |         poll_fn(|cx| { | ||||||
|             T::state().tx_waker.register(cx.waker()); |             T::state().tx_waker.register(cx.waker()); | ||||||
| 
 |             if idx > 3 { | ||||||
|             let idx: u8 = mb.into(); |                 panic!("Bad mailbox"); | ||||||
|  |             } | ||||||
|             let idx = 1 << idx; |             let idx = 1 << idx; | ||||||
|             if !T::regs().txbrp().read().trp(idx) { |             if !T::regs().txbrp().read().trp(idx) { | ||||||
|                 return Poll::Ready(()); |                 return Poll::Ready(()); | ||||||
| @ -418,37 +395,77 @@ where | |||||||
|         .await; |         .await; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Queues the message to be sent but exerts backpressure.  If a lower-priority
 | ||||||
|  |     /// frame is dropped from the mailbox, it is returned.  If no lower-priority frames
 | ||||||
|  |     /// can be replaced, this call asynchronously waits for a frame to be successfully
 | ||||||
|  |     /// transmitted, then tries again.
 | ||||||
|  |     pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> { | ||||||
|  |         poll_fn(|cx| { | ||||||
|  |             T::state().tx_waker.register(cx.waker()); | ||||||
|  | 
 | ||||||
|  |             if let Ok(dropped) = T::registers().write_classic(frame) { | ||||||
|  |                 return Poll::Ready(dropped); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Couldn't replace any lower priority frames.  Need to wait for some mailboxes
 | ||||||
|  |             // to clear.
 | ||||||
|  |             Poll::Pending | ||||||
|  |         }) | ||||||
|  |         .await | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /// Returns the next received message frame
 |     /// Returns the next received message frame
 | ||||||
|     pub async fn read(&mut self) -> Result<RxFrame, BusError> { |     pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { | ||||||
|         poll_fn(|cx| { |         poll_fn(|cx| { | ||||||
|             T::state().err_waker.register(cx.waker()); |             T::state().err_waker.register(cx.waker()); | ||||||
|             T::state().rx_waker.register(cx.waker()); |             T::state().rx_waker.register(cx.waker()); | ||||||
| 
 | 
 | ||||||
|             let mut buffer: [u8; 64] = [0; 64]; |             if let Some((msg, ts)) = T::registers().read_classic(0) { | ||||||
|             if let Ok(rx) = self.can.receive0(&mut buffer) { |                 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | ||||||
|                 // rx: fdcan::ReceiveOverrun<RxFrameInfo>
 |                 return Poll::Ready(Ok((msg, ts))); | ||||||
|                 // TODO: report overrun?
 |             } else if let Some((msg, ts)) = T::registers().read_classic(1) { | ||||||
|                 //  for now we just drop it
 |                 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | ||||||
|  |                 return Poll::Ready(Ok((msg, ts))); | ||||||
|  |             } else if let Some(err) = curr_error::<T>() { | ||||||
|  |                 // TODO: this is probably wrong
 | ||||||
|  |                 return Poll::Ready(Err(err)); | ||||||
|  |             } | ||||||
|  |             Poll::Pending | ||||||
|  |         }) | ||||||
|  |         .await | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|                 let frame: RxFrame = RxFrame::new( |     /// Queues the message to be sent but exerts backpressure.  If a lower-priority
 | ||||||
|                     rx.unwrap(), |     /// frame is dropped from the mailbox, it is returned.  If no lower-priority frames
 | ||||||
|                     &buffer, |     /// can be replaced, this call asynchronously waits for a frame to be successfully
 | ||||||
|                     #[cfg(feature = "time")] |     /// transmitted, then tries again.
 | ||||||
|                     calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp), |     pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { | ||||||
|                 ); |         poll_fn(|cx| { | ||||||
|                 return Poll::Ready(Ok(frame)); |             T::state().tx_waker.register(cx.waker()); | ||||||
|             } else if let Ok(rx) = self.can.receive1(&mut buffer) { |  | ||||||
|                 // rx: fdcan::ReceiveOverrun<RxFrameInfo>
 |  | ||||||
|                 // TODO: report overrun?
 |  | ||||||
|                 //  for now we just drop it
 |  | ||||||
| 
 | 
 | ||||||
|                 let frame: RxFrame = RxFrame::new( |             if let Ok(dropped) = T::registers().write_fd(frame) { | ||||||
|                     rx.unwrap(), |                 return Poll::Ready(dropped); | ||||||
|                     &buffer, |             } | ||||||
|                     #[cfg(feature = "time")] | 
 | ||||||
|                     calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp), |             // Couldn't replace any lower priority frames.  Need to wait for some mailboxes
 | ||||||
|                 ); |             // to clear.
 | ||||||
|                 return Poll::Ready(Ok(frame)); |             Poll::Pending | ||||||
|  |         }) | ||||||
|  |         .await | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns the next received message frame
 | ||||||
|  |     pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { | ||||||
|  |         poll_fn(|cx| { | ||||||
|  |             T::state().err_waker.register(cx.waker()); | ||||||
|  |             T::state().rx_waker.register(cx.waker()); | ||||||
|  | 
 | ||||||
|  |             if let Some((msg, ts)) = T::registers().read_fd(0) { | ||||||
|  |                 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | ||||||
|  |                 return Poll::Ready(Ok((msg, ts))); | ||||||
|  |             } else if let Some((msg, ts)) = T::registers().read_fd(1) { | ||||||
|  |                 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | ||||||
|  |                 return Poll::Ready(Ok((msg, ts))); | ||||||
|             } else if let Some(err) = curr_error::<T>() { |             } else if let Some(err) = curr_error::<T>() { | ||||||
|                 // TODO: this is probably wrong
 |                 // TODO: this is probably wrong
 | ||||||
|                 return Poll::Ready(Err(err)); |                 return Poll::Ready(Err(err)); | ||||||
| @ -459,40 +476,67 @@ where | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Split instance into separate Tx(write) and Rx(read) portions
 |     /// Split instance into separate Tx(write) and Rx(read) portions
 | ||||||
|     pub fn split<'c>(&'c mut self) -> (FdcanTx<'c, 'd, T, M>, FdcanRx<'c, 'd, T, M>) { |     pub fn split(self) -> (FdcanTx<'d, T, M>, FdcanRx<'d, T, M>) { | ||||||
|         let (mut _control, tx, rx0, rx1) = self.can.split_by_ref(); |  | ||||||
|         ( |         ( | ||||||
|             FdcanTx { _control, tx }, |             FdcanTx { | ||||||
|  |                 _instance: self.instance, | ||||||
|  |                 _mode: self._mode, | ||||||
|  |             }, | ||||||
|             FdcanRx { |             FdcanRx { | ||||||
|                 rx0, |                 _instance1: PhantomData::<T>, | ||||||
|                 rx1, |                 _instance2: T::regs(), | ||||||
|  |                 _mode: self._mode, | ||||||
|                 ns_per_timer_tick: self.ns_per_timer_tick, |                 ns_per_timer_tick: self.ns_per_timer_tick, | ||||||
|             }, |             }, | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// FDCAN Tx only Instance
 | /// FDCAN Rx only Instance
 | ||||||
| pub struct FdcanTx<'c, 'd, T: Instance, M: fdcan::Transmit> { | #[allow(dead_code)] | ||||||
|     _control: &'c mut fdcan::FdCanControl<FdcanInstance<'d, T>, M>, | pub struct FdcanRx<'d, T: Instance, M: Receive> { | ||||||
|     tx: &'c mut fdcan::Tx<FdcanInstance<'d, T>, M>, |     _instance1: PhantomData<T>, | ||||||
|  |     _instance2: &'d crate::pac::can::Fdcan, | ||||||
|  |     _mode: PhantomData<M>, | ||||||
|  |     ns_per_timer_tick: u64, // For FDCAN internal timer
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'c, 'd, T: Instance, M: fdcan::Transmit> FdcanTx<'c, 'd, T, M> { | /// FDCAN Tx only Instance
 | ||||||
|  | pub struct FdcanTx<'d, T: Instance, M: Transmit> { | ||||||
|  |     _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>);
 | ||||||
|  |     _mode: PhantomData<M>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'c, 'd, T: Instance, M: Transmit> FdcanTx<'d, T, M> { | ||||||
|     /// Queues the message to be sent but exerts backpressure.  If a lower-priority
 |     /// Queues the message to be sent but exerts backpressure.  If a lower-priority
 | ||||||
|     /// frame is dropped from the mailbox, it is returned.  If no lower-priority frames
 |     /// frame is dropped from the mailbox, it is returned.  If no lower-priority frames
 | ||||||
|     /// can be replaced, this call asynchronously waits for a frame to be successfully
 |     /// can be replaced, this call asynchronously waits for a frame to be successfully
 | ||||||
|     /// transmitted, then tries again.
 |     /// transmitted, then tries again.
 | ||||||
|     pub async fn write(&mut self, frame: &TxFrame) -> Option<TxFrame> { |     pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> { | ||||||
|         poll_fn(|cx| { |         poll_fn(|cx| { | ||||||
|             T::state().tx_waker.register(cx.waker()); |             T::state().tx_waker.register(cx.waker()); | ||||||
|             if let Ok(dropped) = self | 
 | ||||||
|                 .tx |             if let Ok(dropped) = T::registers().write_classic(frame) { | ||||||
|                 .transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| { |                 return Poll::Ready(dropped); | ||||||
|                     TxFrame::from_preserved(hdr, data32) |             } | ||||||
|                 }) | 
 | ||||||
|             { |             // Couldn't replace any lower priority frames.  Need to wait for some mailboxes
 | ||||||
|                 return Poll::Ready(dropped.flatten()); |             // to clear.
 | ||||||
|  |             Poll::Pending | ||||||
|  |         }) | ||||||
|  |         .await | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Queues the message to be sent but exerts backpressure.  If a lower-priority
 | ||||||
|  |     /// frame is dropped from the mailbox, it is returned.  If no lower-priority frames
 | ||||||
|  |     /// can be replaced, this call asynchronously waits for a frame to be successfully
 | ||||||
|  |     /// transmitted, then tries again.
 | ||||||
|  |     pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { | ||||||
|  |         poll_fn(|cx| { | ||||||
|  |             T::state().tx_waker.register(cx.waker()); | ||||||
|  | 
 | ||||||
|  |             if let Ok(dropped) = T::registers().write_fd(frame) { | ||||||
|  |                 return Poll::Ready(dropped); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // Couldn't replace any lower priority frames.  Need to wait for some mailboxes
 |             // Couldn't replace any lower priority frames.  Need to wait for some mailboxes
 | ||||||
| @ -503,65 +547,47 @@ impl<'c, 'd, T: Instance, M: fdcan::Transmit> FdcanTx<'c, 'd, T, M> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// FDCAN Rx only Instance
 | impl<'c, 'd, T: Instance, M: Receive> FdcanRx<'d, T, M> { | ||||||
| #[allow(dead_code)] |  | ||||||
| pub struct FdcanRx<'c, 'd, T: Instance, M: fdcan::Receive> { |  | ||||||
|     rx0: &'c mut fdcan::Rx<FdcanInstance<'d, T>, M, fdcan::Fifo0>, |  | ||||||
|     rx1: &'c mut fdcan::Rx<FdcanInstance<'d, T>, M, fdcan::Fifo1>, |  | ||||||
|     ns_per_timer_tick: u64, // For FDCAN internal timer
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<'c, 'd, T: Instance, M: fdcan::Receive> FdcanRx<'c, 'd, T, M> { |  | ||||||
|     /// Returns the next received message frame
 |     /// Returns the next received message frame
 | ||||||
|     pub async fn read(&mut self) -> Result<RxFrame, BusError> { |     pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { | ||||||
|         poll_fn(|cx| { |         poll_fn(|cx| { | ||||||
|             T::state().err_waker.register(cx.waker()); |             T::state().err_waker.register(cx.waker()); | ||||||
|             T::state().rx_waker.register(cx.waker()); |             T::state().rx_waker.register(cx.waker()); | ||||||
| 
 | 
 | ||||||
|             let mut buffer: [u8; 64] = [0; 64]; |             if let Some((msg, ts)) = T::registers().read_classic(0) { | ||||||
|             if let Ok(rx) = self.rx0.receive(&mut buffer) { |                 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | ||||||
|                 // rx: fdcan::ReceiveOverrun<RxFrameInfo>
 |                 return Poll::Ready(Ok((msg, ts))); | ||||||
|                 // TODO: report overrun?
 |             } else if let Some((msg, ts)) = T::registers().read_classic(1) { | ||||||
|                 //  for now we just drop it
 |                 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | ||||||
|                 let frame: RxFrame = RxFrame::new( |                 return Poll::Ready(Ok((msg, ts))); | ||||||
|                     rx.unwrap(), |  | ||||||
|                     &buffer, |  | ||||||
|                     #[cfg(feature = "time")] |  | ||||||
|                     calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp), |  | ||||||
|                 ); |  | ||||||
|                 return Poll::Ready(Ok(frame)); |  | ||||||
|             } else if let Ok(rx) = self.rx1.receive(&mut buffer) { |  | ||||||
|                 // rx: fdcan::ReceiveOverrun<RxFrameInfo>
 |  | ||||||
|                 // TODO: report overrun?
 |  | ||||||
|                 //  for now we just drop it
 |  | ||||||
|                 let frame: RxFrame = RxFrame::new( |  | ||||||
|                     rx.unwrap(), |  | ||||||
|                     &buffer, |  | ||||||
|                     #[cfg(feature = "time")] |  | ||||||
|                     calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp), |  | ||||||
|                 ); |  | ||||||
|                 return Poll::Ready(Ok(frame)); |  | ||||||
|             } else if let Some(err) = curr_error::<T>() { |             } else if let Some(err) = curr_error::<T>() { | ||||||
|                 // TODO: this is probably wrong
 |                 // TODO: this is probably wrong
 | ||||||
|                 return Poll::Ready(Err(err)); |                 return Poll::Ready(Err(err)); | ||||||
|             } |             } | ||||||
| 
 |  | ||||||
|             Poll::Pending |             Poll::Pending | ||||||
|         }) |         }) | ||||||
|         .await |         .await | ||||||
|     } |     } | ||||||
| } |  | ||||||
| impl<'d, T: Instance, M: FdcanOperatingMode> Deref for Fdcan<'d, T, M> { |  | ||||||
|     type Target = fdcan::FdCan<FdcanInstance<'d, T>, M>; |  | ||||||
| 
 | 
 | ||||||
|     fn deref(&self) -> &Self::Target { |     /// Returns the next received message frame
 | ||||||
|         &self.can |     pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { | ||||||
|     } |         poll_fn(|cx| { | ||||||
| } |             T::state().err_waker.register(cx.waker()); | ||||||
|  |             T::state().rx_waker.register(cx.waker()); | ||||||
| 
 | 
 | ||||||
| impl<'d, T: Instance, M: FdcanOperatingMode> DerefMut for Fdcan<'d, T, M> { |             if let Some((msg, ts)) = T::registers().read_fd(0) { | ||||||
|     fn deref_mut(&mut self) -> &mut Self::Target { |                 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | ||||||
|         &mut self.can |                 return Poll::Ready(Ok((msg, ts))); | ||||||
|  |             } else if let Some((msg, ts)) = T::registers().read_fd(1) { | ||||||
|  |                 let ts = calc_timestamp::<T>(self.ns_per_timer_tick, ts); | ||||||
|  |                 return Poll::Ready(Ok((msg, ts))); | ||||||
|  |             } else if let Some(err) = curr_error::<T>() { | ||||||
|  |                 // TODO: this is probably wrong
 | ||||||
|  |                 return Poll::Ready(Err(err)); | ||||||
|  |             } | ||||||
|  |             Poll::Pending | ||||||
|  |         }) | ||||||
|  |         .await | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -585,11 +611,11 @@ pub(crate) mod sealed { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub trait Instance { |     pub trait Instance { | ||||||
|         const REGISTERS: *mut fdcan::RegisterBlock; |  | ||||||
|         const MSG_RAM: *mut fdcan::message_ram::RegisterBlock; |  | ||||||
|         const MSG_RAM_OFFSET: usize; |         const MSG_RAM_OFFSET: usize; | ||||||
| 
 | 
 | ||||||
|         fn regs() -> &'static crate::pac::can::Fdcan; |         fn regs() -> &'static crate::pac::can::Fdcan; | ||||||
|  |         fn registers() -> crate::can::fd::peripheral::Registers; | ||||||
|  |         fn ram() -> &'static crate::pac::fdcanram::Fdcanram; | ||||||
|         fn state() -> &'static State; |         fn state() -> &'static State; | ||||||
| 
 | 
 | ||||||
|         #[cfg(not(stm32h7))] |         #[cfg(not(stm32h7))] | ||||||
| @ -599,7 +625,8 @@ pub(crate) mod sealed { | |||||||
|         fn configure_msg_ram() { |         fn configure_msg_ram() { | ||||||
|             let r = Self::regs(); |             let r = Self::regs(); | ||||||
| 
 | 
 | ||||||
|             use fdcan::message_ram::*; |             use crate::can::fd::message_ram::*; | ||||||
|  |             //use fdcan::message_ram::*;
 | ||||||
|             let mut offset_words = Self::MSG_RAM_OFFSET as u16; |             let mut offset_words = Self::MSG_RAM_OFFSET as u16; | ||||||
| 
 | 
 | ||||||
|             // 11-bit filter
 |             // 11-bit filter
 | ||||||
| @ -677,28 +704,20 @@ pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + ' | |||||||
| /// Fdcan Instance struct
 | /// Fdcan Instance struct
 | ||||||
| pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); | pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); | ||||||
| 
 | 
 | ||||||
| unsafe impl<'d, T: Instance> fdcan::message_ram::Instance for FdcanInstance<'d, T> { |  | ||||||
|     const MSG_RAM: *mut RegisterBlock = T::MSG_RAM; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| unsafe impl<'d, T: Instance> fdcan::Instance for FdcanInstance<'d, T> |  | ||||||
| where |  | ||||||
|     FdcanInstance<'d, T>: fdcan::message_ram::Instance, |  | ||||||
| { |  | ||||||
|     const REGISTERS: *mut fdcan::RegisterBlock = T::REGISTERS; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| macro_rules! impl_fdcan { | macro_rules! impl_fdcan { | ||||||
|     ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => { |     ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => { | ||||||
|         impl sealed::Instance for peripherals::$inst { |         impl sealed::Instance for peripherals::$inst { | ||||||
|             const REGISTERS: *mut fdcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; |  | ||||||
|             const MSG_RAM: *mut fdcan::message_ram::RegisterBlock = crate::pac::$msg_ram_inst.as_ptr() as *mut _; |  | ||||||
|             const MSG_RAM_OFFSET: usize = $msg_ram_offset; |             const MSG_RAM_OFFSET: usize = $msg_ram_offset; | ||||||
| 
 | 
 | ||||||
|             fn regs() -> &'static crate::pac::can::Fdcan { |             fn regs() -> &'static crate::pac::can::Fdcan { | ||||||
|                 &crate::pac::$inst |                 &crate::pac::$inst | ||||||
|             } |             } | ||||||
| 
 |             fn registers() -> Registers { | ||||||
|  |                 Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst} | ||||||
|  |             } | ||||||
|  |             fn ram() -> &'static crate::pac::fdcanram::Fdcanram { | ||||||
|  |                 &crate::pac::$msg_ram_inst | ||||||
|  |             } | ||||||
|             fn state() -> &'static sealed::State { |             fn state() -> &'static sealed::State { | ||||||
|                 static STATE: sealed::State = sealed::State::new(); |                 static STATE: sealed::State = sealed::State::new(); | ||||||
|                 &STATE |                 &STATE | ||||||
|  | |||||||
							
								
								
									
										370
									
								
								embassy-stm32/src/can/frame.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										370
									
								
								embassy-stm32/src/can/frame.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,370 @@ | |||||||
|  | //! Definition for CAN Frames
 | ||||||
|  | use bit_field::BitField; | ||||||
|  | 
 | ||||||
|  | /// CAN Header, without meta data
 | ||||||
|  | #[derive(Debug, Copy, Clone)] | ||||||
|  | pub struct Header { | ||||||
|  |     id: embedded_can::Id, | ||||||
|  |     len: u8, | ||||||
|  |     flags: u8, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Header { | ||||||
|  |     const FLAG_RTR: usize = 0; // Remote
 | ||||||
|  |     const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN
 | ||||||
|  |     const FLAG_BRS: usize = 2; // Bit-rate switching, ignored for Classic CAN
 | ||||||
|  | 
 | ||||||
|  |     /// Create new CAN Header
 | ||||||
|  |     pub fn new(id: embedded_can::Id, len: u8, rtr: bool) -> Header { | ||||||
|  |         let mut flags = 0u8; | ||||||
|  |         flags.set_bit(Self::FLAG_RTR, rtr); | ||||||
|  |         Header { id, len, flags } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Create new CAN FD Header
 | ||||||
|  |     pub fn new_fd(id: embedded_can::Id, len: u8, rtr: bool, brs: bool) -> Header { | ||||||
|  |         let mut flags = 0u8; | ||||||
|  |         flags.set_bit(Self::FLAG_RTR, rtr); | ||||||
|  |         flags.set_bit(Self::FLAG_FDCAN, true); | ||||||
|  |         flags.set_bit(Self::FLAG_BRS, brs); | ||||||
|  |         Header { id, len, flags } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Return ID
 | ||||||
|  |     pub fn id(&self) -> &embedded_can::Id { | ||||||
|  |         &self.id | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Return length as u8
 | ||||||
|  |     pub fn len(&self) -> u8 { | ||||||
|  |         self.len | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Is remote frame
 | ||||||
|  |     pub fn rtr(&self) -> bool { | ||||||
|  |         self.flags.get_bit(Self::FLAG_RTR) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Request/is FDCAN frame
 | ||||||
|  |     pub fn fdcan(&self) -> bool { | ||||||
|  |         self.flags.get_bit(Self::FLAG_FDCAN) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Request/is Flexible Data Rate
 | ||||||
|  |     pub fn bit_rate_switching(&self) -> bool { | ||||||
|  |         self.flags.get_bit(Self::FLAG_BRS) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Payload of a classic CAN data frame.
 | ||||||
|  | ///
 | ||||||
|  | /// Contains 0 to 8 Bytes of data.
 | ||||||
|  | #[derive(Debug, Copy, Clone)] | ||||||
|  | pub struct ClassicData { | ||||||
|  |     pub(crate) bytes: [u8; 8], | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ClassicData { | ||||||
|  |     /// Creates a data payload from a raw byte slice.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
 | ||||||
|  |     /// cannot be represented with an FDCAN DLC.
 | ||||||
|  |     pub fn new(data: &[u8]) -> Option<Self> { | ||||||
|  |         if !FdData::is_valid_len(data.len()) { | ||||||
|  |             return None; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let mut bytes = [0; 8]; | ||||||
|  |         bytes[..data.len()].copy_from_slice(data); | ||||||
|  | 
 | ||||||
|  |         Some(Self { bytes }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Raw read access to data.
 | ||||||
|  |     pub fn raw(&self) -> &[u8] { | ||||||
|  |         &self.bytes | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Checks if the length can be encoded in FDCAN DLC field.
 | ||||||
|  |     pub const fn is_valid_len(len: usize) -> bool { | ||||||
|  |         match len { | ||||||
|  |             0..=8 => true, | ||||||
|  |             _ => false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Creates an empty data payload containing 0 bytes.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub const fn empty() -> Self { | ||||||
|  |         Self { bytes: [0; 8] } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Frame with up to 8 bytes of data payload as per Classic CAN
 | ||||||
|  | #[derive(Debug, Copy, Clone)] | ||||||
|  | pub struct ClassicFrame { | ||||||
|  |     can_header: Header, | ||||||
|  |     data: ClassicData, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ClassicFrame { | ||||||
|  |     pub(crate) const MAX_DATA_LEN: usize = 8; | ||||||
|  | 
 | ||||||
|  |     /// Create a new CAN classic Frame
 | ||||||
|  |     pub fn new(can_header: Header, data: ClassicData) -> ClassicFrame { | ||||||
|  |         ClassicFrame { can_header, data } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Create new extended frame
 | ||||||
|  |     pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> { | ||||||
|  |         if let Some(id) = embedded_can::ExtendedId::new(raw_id) { | ||||||
|  |             match ClassicData::new(raw_data) { | ||||||
|  |                 Some(data) => Some(ClassicFrame::new( | ||||||
|  |                     Header::new(id.into(), raw_data.len() as u8, false), | ||||||
|  |                     data, | ||||||
|  |                 )), | ||||||
|  |                 None => None, | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Create new standard frame
 | ||||||
|  |     pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> { | ||||||
|  |         if let Some(id) = embedded_can::StandardId::new(raw_id) { | ||||||
|  |             match ClassicData::new(raw_data) { | ||||||
|  |                 Some(data) => Some(ClassicFrame::new( | ||||||
|  |                     Header::new(id.into(), raw_data.len() as u8, false), | ||||||
|  |                     data, | ||||||
|  |                 )), | ||||||
|  |                 None => None, | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Create new remote frame
 | ||||||
|  |     pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { | ||||||
|  |         if len <= 8usize { | ||||||
|  |             Some(ClassicFrame::new( | ||||||
|  |                 Header::new(id.into(), len as u8, true), | ||||||
|  |                 ClassicData::empty(), | ||||||
|  |             )) | ||||||
|  |         } else { | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Get reference to data
 | ||||||
|  |     pub fn header(&self) -> &Header { | ||||||
|  |         &self.can_header | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Return ID
 | ||||||
|  |     pub fn id(&self) -> &embedded_can::Id { | ||||||
|  |         &self.can_header.id | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Get reference to data
 | ||||||
|  |     pub fn data(&self) -> &[u8] { | ||||||
|  |         &self.data.raw() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl embedded_can::Frame for ClassicFrame { | ||||||
|  |     fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { | ||||||
|  |         match ClassicData::new(raw_data) { | ||||||
|  |             Some(data) => Some(ClassicFrame::new( | ||||||
|  |                 Header::new(id.into(), raw_data.len() as u8, false), | ||||||
|  |                 data, | ||||||
|  |             )), | ||||||
|  |             None => None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { | ||||||
|  |         if len <= 8 { | ||||||
|  |             Some(ClassicFrame::new( | ||||||
|  |                 Header::new(id.into(), len as u8, true), | ||||||
|  |                 ClassicData::empty(), | ||||||
|  |             )) | ||||||
|  |         } else { | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     fn is_extended(&self) -> bool { | ||||||
|  |         match self.can_header.id { | ||||||
|  |             embedded_can::Id::Extended(_) => true, | ||||||
|  |             embedded_can::Id::Standard(_) => true, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     fn is_remote_frame(&self) -> bool { | ||||||
|  |         self.can_header.rtr() | ||||||
|  |     } | ||||||
|  |     fn id(&self) -> embedded_can::Id { | ||||||
|  |         self.can_header.id | ||||||
|  |     } | ||||||
|  |     fn dlc(&self) -> usize { | ||||||
|  |         self.can_header.len as usize | ||||||
|  |     } | ||||||
|  |     fn data(&self) -> &[u8] { | ||||||
|  |         &self.data.raw() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Payload of a (FD)CAN data frame.
 | ||||||
|  | ///
 | ||||||
|  | /// Contains 0 to 64 Bytes of data.
 | ||||||
|  | #[derive(Debug, Copy, Clone)] | ||||||
|  | pub struct FdData { | ||||||
|  |     pub(crate) bytes: [u8; 64], | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl FdData { | ||||||
|  |     /// Creates a data payload from a raw byte slice.
 | ||||||
|  |     ///
 | ||||||
|  |     /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
 | ||||||
|  |     /// cannot be represented with an FDCAN DLC.
 | ||||||
|  |     pub fn new(data: &[u8]) -> Option<Self> { | ||||||
|  |         if !FdData::is_valid_len(data.len()) { | ||||||
|  |             return None; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let mut bytes = [0; 64]; | ||||||
|  |         bytes[..data.len()].copy_from_slice(data); | ||||||
|  | 
 | ||||||
|  |         Some(Self { bytes }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Raw read access to data.
 | ||||||
|  |     pub fn raw(&self) -> &[u8] { | ||||||
|  |         &self.bytes | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Checks if the length can be encoded in FDCAN DLC field.
 | ||||||
|  |     pub const fn is_valid_len(len: usize) -> bool { | ||||||
|  |         match len { | ||||||
|  |             0..=8 => true, | ||||||
|  |             12 => true, | ||||||
|  |             16 => true, | ||||||
|  |             20 => true, | ||||||
|  |             24 => true, | ||||||
|  |             32 => true, | ||||||
|  |             48 => true, | ||||||
|  |             64 => true, | ||||||
|  |             _ => false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Creates an empty data payload containing 0 bytes.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub const fn empty() -> Self { | ||||||
|  |         Self { bytes: [0; 64] } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Frame with up to 8 bytes of data payload as per Fd CAN
 | ||||||
|  | #[derive(Debug, Copy, Clone)] | ||||||
|  | pub struct FdFrame { | ||||||
|  |     can_header: Header, | ||||||
|  |     data: FdData, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl FdFrame { | ||||||
|  |     pub(crate) const MAX_DATA_LEN: usize = 64; | ||||||
|  | 
 | ||||||
|  |     /// Create a new CAN classic Frame
 | ||||||
|  |     pub fn new(can_header: Header, data: FdData) -> FdFrame { | ||||||
|  |         FdFrame { can_header, data } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Create new extended frame
 | ||||||
|  |     pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> { | ||||||
|  |         if let Some(id) = embedded_can::ExtendedId::new(raw_id) { | ||||||
|  |             match FdData::new(raw_data) { | ||||||
|  |                 Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)), | ||||||
|  |                 None => None, | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Create new standard frame
 | ||||||
|  |     pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> { | ||||||
|  |         if let Some(id) = embedded_can::StandardId::new(raw_id) { | ||||||
|  |             match FdData::new(raw_data) { | ||||||
|  |                 Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)), | ||||||
|  |                 None => None, | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Create new remote frame
 | ||||||
|  |     pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { | ||||||
|  |         if len <= 8 { | ||||||
|  |             Some(FdFrame::new(Header::new(id.into(), len as u8, true), FdData::empty())) | ||||||
|  |         } else { | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Get reference to data
 | ||||||
|  |     pub fn header(&self) -> &Header { | ||||||
|  |         &self.can_header | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Return ID
 | ||||||
|  |     pub fn id(&self) -> &embedded_can::Id { | ||||||
|  |         &self.can_header.id | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Get reference to data
 | ||||||
|  |     pub fn data(&self) -> &[u8] { | ||||||
|  |         &self.data.raw() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl embedded_can::Frame for FdFrame { | ||||||
|  |     fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { | ||||||
|  |         match FdData::new(raw_data) { | ||||||
|  |             Some(data) => Some(FdFrame::new( | ||||||
|  |                 Header::new_fd(id.into(), raw_data.len() as u8, false, true), | ||||||
|  |                 data, | ||||||
|  |             )), | ||||||
|  |             None => None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { | ||||||
|  |         if len <= 8 { | ||||||
|  |             Some(FdFrame::new( | ||||||
|  |                 Header::new_fd(id.into(), len as u8, true, true), | ||||||
|  |                 FdData::empty(), | ||||||
|  |             )) | ||||||
|  |         } else { | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     fn is_extended(&self) -> bool { | ||||||
|  |         match self.can_header.id { | ||||||
|  |             embedded_can::Id::Extended(_) => true, | ||||||
|  |             embedded_can::Id::Standard(_) => true, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     fn is_remote_frame(&self) -> bool { | ||||||
|  |         self.can_header.rtr() | ||||||
|  |     } | ||||||
|  |     fn id(&self) -> embedded_can::Id { | ||||||
|  |         self.can_header.id | ||||||
|  |     } | ||||||
|  |     // Returns length in bytes even for CANFD packets which embedded-can does not really mention.
 | ||||||
|  |     fn dlc(&self) -> usize { | ||||||
|  |         self.can_header.len as usize | ||||||
|  |     } | ||||||
|  |     fn data(&self) -> &[u8] { | ||||||
|  |         &self.data.raw() | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -20,6 +20,7 @@ defmt-rtt = "0.4" | |||||||
| cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | ||||||
| cortex-m-rt = "0.7.0" | cortex-m-rt = "0.7.0" | ||||||
| embedded-hal = "0.2.6" | embedded-hal = "0.2.6" | ||||||
|  | embedded-can = { version = "0.4" } | ||||||
| panic-probe = { version = "0.3", features = ["print-defmt"] } | panic-probe = { version = "0.3", features = ["print-defmt"] } | ||||||
| futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||||||
| heapless = { version = "0.8", default-features = false } | heapless = { version = "0.8", default-features = false } | ||||||
|  | |||||||
| @ -20,32 +20,100 @@ async fn main(_spawner: Spawner) { | |||||||
| 
 | 
 | ||||||
|     let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); |     let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | ||||||
| 
 | 
 | ||||||
|  |     can.set_extended_filter( | ||||||
|  |         can::fd::filter::ExtendedFilterSlot::_0, | ||||||
|  |         can::fd::filter::ExtendedFilter::accept_all_into_fifo1(), | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|     // 250k bps
 |     // 250k bps
 | ||||||
|     can.set_bitrate(250_000); |     can.set_bitrate(250_000); | ||||||
| 
 | 
 | ||||||
|  |     // 1M bps
 | ||||||
|  |     can.set_fd_data_bitrate(1_000_000, false); | ||||||
|  | 
 | ||||||
|     info!("Configured"); |     info!("Configured"); | ||||||
| 
 | 
 | ||||||
|     //let mut can = can.into_external_loopback_mode();
 |     //let mut can = can.into_normal_mode();
 | ||||||
|     let mut can = can.into_normal_mode(); |     let mut can = can.into_internal_loopback_mode(); | ||||||
| 
 | 
 | ||||||
|     let mut i = 0; |     let mut i = 0; | ||||||
|  |     let mut last_read_ts = embassy_time::Instant::now(); | ||||||
|  | 
 | ||||||
|     loop { |     loop { | ||||||
|         let frame = can::TxFrame::new( |         let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||||||
|             can::TxFrameHeader { |  | ||||||
|                 len: 1, |  | ||||||
|                 frame_format: can::FrameFormat::Standard, |  | ||||||
|                 id: can::StandardId::new(0x123).unwrap().into(), |  | ||||||
|                 bit_rate_switching: false, |  | ||||||
|                 marker: None, |  | ||||||
|             }, |  | ||||||
|             &[i], |  | ||||||
|         ) |  | ||||||
|         .unwrap(); |  | ||||||
|         info!("Writing frame"); |         info!("Writing frame"); | ||||||
|  | 
 | ||||||
|         _ = can.write(&frame).await; |         _ = can.write(&frame).await; | ||||||
| 
 | 
 | ||||||
|         match can.read().await { |         match can.read().await { | ||||||
|             Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), |             Ok((rx_frame, ts)) => { | ||||||
|  |                 let delta = (ts - last_read_ts).as_millis(); | ||||||
|  |                 last_read_ts = ts; | ||||||
|  |                 info!( | ||||||
|  |                     "Rx: {} {:02x} --- {}ms", | ||||||
|  |                     rx_frame.header().len(), | ||||||
|  |                     rx_frame.data()[0..rx_frame.header().len() as usize], | ||||||
|  |                     delta, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             Err(_err) => error!("Error in frame"), | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Timer::after_millis(250).await; | ||||||
|  | 
 | ||||||
|  |         i += 1; | ||||||
|  |         if i > 2 { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Use the FD API's even if we don't get FD packets.
 | ||||||
|  |     loop { | ||||||
|  |         let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap(); | ||||||
|  |         info!("Writing frame using FD API"); | ||||||
|  | 
 | ||||||
|  |         _ = can.write_fd(&frame).await; | ||||||
|  | 
 | ||||||
|  |         match can.read_fd().await { | ||||||
|  |             Ok((rx_frame, ts)) => { | ||||||
|  |                 let delta = (ts - last_read_ts).as_millis(); | ||||||
|  |                 last_read_ts = ts; | ||||||
|  |                 info!( | ||||||
|  |                     "Rx: {} {:02x} --- using FD API {}ms", | ||||||
|  |                     rx_frame.header().len(), | ||||||
|  |                     rx_frame.data()[0..rx_frame.header().len() as usize], | ||||||
|  |                     delta, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             Err(_err) => error!("Error in frame"), | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Timer::after_millis(250).await; | ||||||
|  | 
 | ||||||
|  |         i += 1; | ||||||
|  |         if i > 4 { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let (mut tx, mut rx) = can.split(); | ||||||
|  |     // With split
 | ||||||
|  |     loop { | ||||||
|  |         let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||||||
|  |         info!("Writing frame"); | ||||||
|  |         _ = tx.write(&frame).await; | ||||||
|  | 
 | ||||||
|  |         match rx.read().await { | ||||||
|  |             Ok((rx_frame, ts)) => { | ||||||
|  |                 let delta = (ts - last_read_ts).as_millis(); | ||||||
|  |                 last_read_ts = ts; | ||||||
|  |                 info!( | ||||||
|  |                     "Rx: {} {:02x} --- {}ms", | ||||||
|  |                     rx_frame.header().len(), | ||||||
|  |                     rx_frame.data()[0..rx_frame.header().len() as usize], | ||||||
|  |                     delta, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|             Err(_err) => error!("Error in frame"), |             Err(_err) => error!("Error in frame"), | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -16,54 +16,77 @@ bind_interrupts!(struct Irqs { | |||||||
| #[embassy_executor::main] | #[embassy_executor::main] | ||||||
| async fn main(_spawner: Spawner) { | async fn main(_spawner: Spawner) { | ||||||
|     let mut config = Config::default(); |     let mut config = Config::default(); | ||||||
| 
 |     config.rcc.hse = Some(rcc::Hse { | ||||||
|     // configure FDCAN to use PLL1_Q at 64 MHz
 |         freq: embassy_stm32::time::Hertz(25_000_000), | ||||||
|     config.rcc.pll1 = Some(rcc::Pll { |         mode: rcc::HseMode::Oscillator, | ||||||
|         source: rcc::PllSource::HSI, |  | ||||||
|         prediv: rcc::PllPreDiv::DIV4, |  | ||||||
|         mul: rcc::PllMul::MUL8, |  | ||||||
|         divp: None, |  | ||||||
|         divq: Some(rcc::PllDiv::DIV2), |  | ||||||
|         divr: None, |  | ||||||
|     }); |     }); | ||||||
|     config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q; |     config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; | ||||||
| 
 | 
 | ||||||
|     let peripherals = embassy_stm32::init(config); |     let peripherals = embassy_stm32::init(config); | ||||||
| 
 | 
 | ||||||
|  |     //let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs);
 | ||||||
|     let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); |     let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | ||||||
| 
 | 
 | ||||||
|     can.can.apply_config( |     // 250k bps
 | ||||||
|         can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming { |     can.set_bitrate(250_000); | ||||||
|             sync_jump_width: 1.try_into().unwrap(), |  | ||||||
|             prescaler: 8.try_into().unwrap(), |  | ||||||
|             seg1: 13.try_into().unwrap(), |  | ||||||
|             seg2: 2.try_into().unwrap(), |  | ||||||
|         }), |  | ||||||
|     ); |  | ||||||
| 
 | 
 | ||||||
|     info!("Configured"); |     //let mut can = can.into_internal_loopback_mode();
 | ||||||
|  |     let mut can = can.into_normal_mode(); | ||||||
| 
 | 
 | ||||||
|     let mut can = can.into_external_loopback_mode(); |     info!("CAN Configured"); | ||||||
|     //let mut can = can.into_normal_mode();
 |  | ||||||
| 
 | 
 | ||||||
|     let mut i = 0; |     let mut i = 0; | ||||||
|  |     let mut last_read_ts = embassy_time::Instant::now(); | ||||||
|  | 
 | ||||||
|     loop { |     loop { | ||||||
|         let frame = can::TxFrame::new( |         let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||||||
|             can::TxFrameHeader { |  | ||||||
|                 len: 1, |  | ||||||
|                 frame_format: can::FrameFormat::Standard, |  | ||||||
|                 id: can::StandardId::new(0x123).unwrap().into(), |  | ||||||
|                 bit_rate_switching: false, |  | ||||||
|                 marker: None, |  | ||||||
|             }, |  | ||||||
|             &[i], |  | ||||||
|         ) |  | ||||||
|         .unwrap(); |  | ||||||
|         info!("Writing frame"); |         info!("Writing frame"); | ||||||
|         _ = can.write(&frame).await; |         _ = can.write(&frame).await; | ||||||
| 
 | 
 | ||||||
|         match can.read().await { |         match can.read().await { | ||||||
|             Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), |             Ok((rx_frame, ts)) => { | ||||||
|  |                 let delta = (ts - last_read_ts).as_millis(); | ||||||
|  |                 last_read_ts = ts; | ||||||
|  |                 info!( | ||||||
|  |                     "Rx: {:x} {:x} {:x} {:x} --- NEW {}", | ||||||
|  |                     rx_frame.data()[0], | ||||||
|  |                     rx_frame.data()[1], | ||||||
|  |                     rx_frame.data()[2], | ||||||
|  |                     rx_frame.data()[3], | ||||||
|  |                     delta, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             Err(_err) => error!("Error in frame"), | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Timer::after_millis(250).await; | ||||||
|  | 
 | ||||||
|  |         i += 1; | ||||||
|  |         if i > 3 { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let (mut tx, mut rx) = can.split(); | ||||||
|  |     // With split
 | ||||||
|  |     loop { | ||||||
|  |         let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||||||
|  |         info!("Writing frame"); | ||||||
|  |         _ = tx.write(&frame).await; | ||||||
|  | 
 | ||||||
|  |         match rx.read().await { | ||||||
|  |             Ok((rx_frame, ts)) => { | ||||||
|  |                 let delta = (ts - last_read_ts).as_millis(); | ||||||
|  |                 last_read_ts = ts; | ||||||
|  |                 info!( | ||||||
|  |                     "Rx: {:x} {:x} {:x} {:x} --- NEW {}", | ||||||
|  |                     rx_frame.data()[0], | ||||||
|  |                     rx_frame.data()[1], | ||||||
|  |                     rx_frame.data()[2], | ||||||
|  |                     rx_frame.data()[3], | ||||||
|  |                     delta, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|             Err(_err) => error!("Error in frame"), |             Err(_err) => error!("Error in frame"), | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -16,54 +16,77 @@ bind_interrupts!(struct Irqs { | |||||||
| #[embassy_executor::main] | #[embassy_executor::main] | ||||||
| async fn main(_spawner: Spawner) { | async fn main(_spawner: Spawner) { | ||||||
|     let mut config = Config::default(); |     let mut config = Config::default(); | ||||||
| 
 |     config.rcc.hse = Some(rcc::Hse { | ||||||
|     // configure FDCAN to use PLL1_Q at 64 MHz
 |         freq: embassy_stm32::time::Hertz(25_000_000), | ||||||
|     config.rcc.pll1 = Some(rcc::Pll { |         mode: rcc::HseMode::Oscillator, | ||||||
|         source: rcc::PllSource::HSI, |  | ||||||
|         prediv: rcc::PllPreDiv::DIV4, |  | ||||||
|         mul: rcc::PllMul::MUL8, |  | ||||||
|         divp: None, |  | ||||||
|         divq: Some(rcc::PllDiv::DIV2), |  | ||||||
|         divr: None, |  | ||||||
|     }); |     }); | ||||||
|     config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q; |     config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; | ||||||
| 
 | 
 | ||||||
|     let peripherals = embassy_stm32::init(config); |     let peripherals = embassy_stm32::init(config); | ||||||
| 
 | 
 | ||||||
|  |     //let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs);
 | ||||||
|     let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); |     let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | ||||||
| 
 | 
 | ||||||
|     can.can.apply_config( |     // 250k bps
 | ||||||
|         can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming { |     can.set_bitrate(250_000); | ||||||
|             sync_jump_width: 1.try_into().unwrap(), |  | ||||||
|             prescaler: 8.try_into().unwrap(), |  | ||||||
|             seg1: 13.try_into().unwrap(), |  | ||||||
|             seg2: 2.try_into().unwrap(), |  | ||||||
|         }), |  | ||||||
|     ); |  | ||||||
| 
 | 
 | ||||||
|     info!("Configured"); |     //let mut can = can.into_internal_loopback_mode();
 | ||||||
|  |     let mut can = can.into_normal_mode(); | ||||||
| 
 | 
 | ||||||
|     let mut can = can.into_external_loopback_mode(); |     info!("CAN Configured"); | ||||||
|     //let mut can = can.into_normal_mode();
 |  | ||||||
| 
 | 
 | ||||||
|     let mut i = 0; |     let mut i = 0; | ||||||
|  |     let mut last_read_ts = embassy_time::Instant::now(); | ||||||
|  | 
 | ||||||
|     loop { |     loop { | ||||||
|         let frame = can::TxFrame::new( |         let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||||||
|             can::TxFrameHeader { |  | ||||||
|                 len: 1, |  | ||||||
|                 frame_format: can::FrameFormat::Standard, |  | ||||||
|                 id: can::StandardId::new(0x123).unwrap().into(), |  | ||||||
|                 bit_rate_switching: false, |  | ||||||
|                 marker: None, |  | ||||||
|             }, |  | ||||||
|             &[i], |  | ||||||
|         ) |  | ||||||
|         .unwrap(); |  | ||||||
|         info!("Writing frame"); |         info!("Writing frame"); | ||||||
|         _ = can.write(&frame).await; |         _ = can.write(&frame).await; | ||||||
| 
 | 
 | ||||||
|         match can.read().await { |         match can.read().await { | ||||||
|             Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]), |             Ok((rx_frame, ts)) => { | ||||||
|  |                 let delta = (ts - last_read_ts).as_millis(); | ||||||
|  |                 last_read_ts = ts; | ||||||
|  |                 info!( | ||||||
|  |                     "Rx: {:x} {:x} {:x} {:x} --- NEW {}", | ||||||
|  |                     rx_frame.data()[0], | ||||||
|  |                     rx_frame.data()[1], | ||||||
|  |                     rx_frame.data()[2], | ||||||
|  |                     rx_frame.data()[3], | ||||||
|  |                     delta, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             Err(_err) => error!("Error in frame"), | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Timer::after_millis(250).await; | ||||||
|  | 
 | ||||||
|  |         i += 1; | ||||||
|  |         if i > 3 { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let (mut tx, mut rx) = can.split(); | ||||||
|  |     // With split
 | ||||||
|  |     loop { | ||||||
|  |         let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||||||
|  |         info!("Writing frame"); | ||||||
|  |         _ = tx.write(&frame).await; | ||||||
|  | 
 | ||||||
|  |         match rx.read().await { | ||||||
|  |             Ok((rx_frame, ts)) => { | ||||||
|  |                 let delta = (ts - last_read_ts).as_millis(); | ||||||
|  |                 last_read_ts = ts; | ||||||
|  |                 info!( | ||||||
|  |                     "Rx: {:x} {:x} {:x} {:x} --- NEW {}", | ||||||
|  |                     rx_frame.data()[0], | ||||||
|  |                     rx_frame.data()[1], | ||||||
|  |                     rx_frame.data()[2], | ||||||
|  |                     rx_frame.data()[3], | ||||||
|  |                     delta, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|             Err(_err) => error!("Error in frame"), |             Err(_err) => error!("Error in frame"), | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -69,6 +69,7 @@ cortex-m-rt = "0.7.0" | |||||||
| embedded-hal = "0.2.6" | embedded-hal = "0.2.6" | ||||||
| embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | ||||||
| embedded-hal-async = { version = "1.0" } | embedded-hal-async = { version = "1.0" } | ||||||
|  | embedded-can = { version = "0.4" } | ||||||
| micromath = "2.0.0" | micromath = "2.0.0" | ||||||
| panic-probe = { version = "0.3.0", features = ["print-defmt"] } | panic-probe = { version = "0.3.0", features = ["print-defmt"] } | ||||||
| rand_core = { version = "0.6", default-features = false } | rand_core = { version = "0.6", default-features = false } | ||||||
|  | |||||||
| @ -36,7 +36,7 @@ fn options() -> TestOptions { | |||||||
|     c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; |     c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; | ||||||
|     TestOptions { |     TestOptions { | ||||||
|         config: c, |         config: c, | ||||||
|         max_latency: Duration::from_micros(3800), |         max_latency: Duration::from_micros(1200), | ||||||
|         second_fifo_working: false, |         second_fifo_working: false, | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -53,12 +53,12 @@ fn options() -> TestOptions { | |||||||
|     c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; |     c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; | ||||||
|     TestOptions { |     TestOptions { | ||||||
|         config: c, |         config: c, | ||||||
|         max_latency: Duration::from_micros(5500), |         max_latency: Duration::from_micros(1200), | ||||||
|         second_fifo_working: false, |         second_fifo_working: false, | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[cfg(any(feature = "stm32g491re"))] | #[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))] | ||||||
| fn options() -> TestOptions { | fn options() -> TestOptions { | ||||||
|     info!("G4 config"); |     info!("G4 config"); | ||||||
|     TestOptions { |     TestOptions { | ||||||
| @ -80,9 +80,9 @@ async fn main(_spawner: Spawner) { | |||||||
|     // 250k bps
 |     // 250k bps
 | ||||||
|     can.set_bitrate(250_000); |     can.set_bitrate(250_000); | ||||||
| 
 | 
 | ||||||
|     can.can.set_extended_filter( |     can.set_extended_filter( | ||||||
|         can::filter::ExtendedFilterSlot::_0, |         can::fd::filter::ExtendedFilterSlot::_0, | ||||||
|         can::filter::ExtendedFilter::accept_all_into_fifo1(), |         can::fd::filter::ExtendedFilter::accept_all_into_fifo1(), | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     let mut can = can.into_internal_loopback_mode(); |     let mut can = can.into_internal_loopback_mode(); | ||||||
| @ -91,31 +91,21 @@ async fn main(_spawner: Spawner) { | |||||||
| 
 | 
 | ||||||
|     let mut i: u8 = 0; |     let mut i: u8 = 0; | ||||||
|     loop { |     loop { | ||||||
|         let tx_frame = can::TxFrame::new( |         let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); | ||||||
|             can::TxFrameHeader { |  | ||||||
|                 len: 1, |  | ||||||
|                 frame_format: can::FrameFormat::Standard, |  | ||||||
|                 id: can::StandardId::new(0x123).unwrap().into(), |  | ||||||
|                 bit_rate_switching: false, |  | ||||||
|                 marker: None, |  | ||||||
|             }, |  | ||||||
|             &[i], |  | ||||||
|         ) |  | ||||||
|         .unwrap(); |  | ||||||
| 
 | 
 | ||||||
|         info!("Transmitting frame..."); |         info!("Transmitting frame..."); | ||||||
|         let tx_ts = Instant::now(); |         let tx_ts = Instant::now(); | ||||||
|         can.write(&tx_frame).await; |         can.write(&tx_frame).await; | ||||||
| 
 | 
 | ||||||
|         let envelope = can.read().await.unwrap(); |         let (frame, timestamp) = can.read().await.unwrap(); | ||||||
|         info!("Frame received!"); |         info!("Frame received!"); | ||||||
| 
 | 
 | ||||||
|         // Check data.
 |         // Check data.
 | ||||||
|         assert!(i == envelope.data()[0], "{} == {}", i, envelope.data()[0]); |         assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]); | ||||||
| 
 | 
 | ||||||
|         info!("loopback time {}", envelope.header.time_stamp); |         info!("loopback time {}", timestamp); | ||||||
|         info!("loopback frame {=u8}", envelope.data()[0]); |         info!("loopback frame {=u8}", frame.data()[0]); | ||||||
|         let latency = envelope.timestamp.saturating_duration_since(tx_ts); |         let latency = timestamp.saturating_duration_since(tx_ts); | ||||||
|         info!("loopback latency {} us", latency.as_micros()); |         info!("loopback latency {} us", latency.as_micros()); | ||||||
| 
 | 
 | ||||||
|         // Theoretical minimum latency is 55us, actual is usually ~80us
 |         // Theoretical minimum latency is 55us, actual is usually ~80us
 | ||||||
| @ -143,47 +133,26 @@ async fn main(_spawner: Spawner) { | |||||||
|     // in each FIFO so make sure we write enough to fill them both up before reading.
 |     // in each FIFO so make sure we write enough to fill them both up before reading.
 | ||||||
|     for i in 0..3 { |     for i in 0..3 { | ||||||
|         // Try filling up the RX FIFO0 buffers with standard packets
 |         // Try filling up the RX FIFO0 buffers with standard packets
 | ||||||
|         let tx_frame = can::TxFrame::new( |         let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); | ||||||
|             can::TxFrameHeader { |  | ||||||
|                 len: 1, |  | ||||||
|                 frame_format: can::FrameFormat::Standard, |  | ||||||
|                 id: can::StandardId::new(0x123).unwrap().into(), |  | ||||||
|                 bit_rate_switching: false, |  | ||||||
|                 marker: None, |  | ||||||
|             }, |  | ||||||
|             &[i], |  | ||||||
|         ) |  | ||||||
|         .unwrap(); |  | ||||||
|         info!("Transmitting frame {}", i); |         info!("Transmitting frame {}", i); | ||||||
|         can.write(&tx_frame).await; |         can.write(&tx_frame).await; | ||||||
|     } |     } | ||||||
|     for i in 3..max_buffered { |     for i in 3..max_buffered { | ||||||
|         // Try filling up the RX FIFO0 buffers with extended packets
 |         // Try filling up the RX FIFO0 buffers with extended packets
 | ||||||
|         let tx_frame = can::TxFrame::new( |         let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap(); | ||||||
|             can::TxFrameHeader { |  | ||||||
|                 len: 1, |  | ||||||
|                 frame_format: can::FrameFormat::Standard, |  | ||||||
|                 id: can::ExtendedId::new(0x1232344).unwrap().into(), |  | ||||||
|                 bit_rate_switching: false, |  | ||||||
|                 marker: None, |  | ||||||
|             }, |  | ||||||
|             &[i], |  | ||||||
|         ) |  | ||||||
|         .unwrap(); |  | ||||||
| 
 |  | ||||||
|         info!("Transmitting frame {}", i); |         info!("Transmitting frame {}", i); | ||||||
|         can.write(&tx_frame).await; |         can.write(&tx_frame).await; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Try and receive all 6 packets
 |     // Try and receive all 6 packets
 | ||||||
|     for i in 0..max_buffered { |     for i in 0..max_buffered { | ||||||
|         let envelope = can.read().await.unwrap(); |         let (frame, _ts) = can.read().await.unwrap(); | ||||||
|         match envelope.header.id { |         match frame.id() { | ||||||
|             can::Id::Extended(id) => { |             embedded_can::Id::Extended(id) => { | ||||||
|                 info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); |                 info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||||||
|             } |             } | ||||||
|             can::Id::Standard(id) => { |             embedded_can::Id::Standard(id) => { | ||||||
|                 info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); |                 info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -192,48 +161,26 @@ async fn main(_spawner: Spawner) { | |||||||
|     let (mut tx, mut rx) = can.split(); |     let (mut tx, mut rx) = can.split(); | ||||||
|     for i in 0..3 { |     for i in 0..3 { | ||||||
|         // Try filling up the RX FIFO0 buffers with standard packets
 |         // Try filling up the RX FIFO0 buffers with standard packets
 | ||||||
|         let tx_frame = can::TxFrame::new( |         let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); | ||||||
|             can::TxFrameHeader { |  | ||||||
|                 len: 1, |  | ||||||
|                 frame_format: can::FrameFormat::Standard, |  | ||||||
|                 id: can::StandardId::new(0x123).unwrap().into(), |  | ||||||
|                 bit_rate_switching: false, |  | ||||||
|                 marker: None, |  | ||||||
|             }, |  | ||||||
|             &[i], |  | ||||||
|         ) |  | ||||||
|         .unwrap(); |  | ||||||
| 
 |  | ||||||
|         info!("Transmitting frame {}", i); |         info!("Transmitting frame {}", i); | ||||||
|         tx.write(&tx_frame).await; |         tx.write(&tx_frame).await; | ||||||
|     } |     } | ||||||
|     for i in 3..max_buffered { |     for i in 3..max_buffered { | ||||||
|         // Try filling up the RX FIFO0 buffers with extended packets
 |         // Try filling up the RX FIFO0 buffers with extended packets
 | ||||||
|         let tx_frame = can::TxFrame::new( |         let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap(); | ||||||
|             can::TxFrameHeader { |  | ||||||
|                 len: 1, |  | ||||||
|                 frame_format: can::FrameFormat::Standard, |  | ||||||
|                 id: can::ExtendedId::new(0x1232344).unwrap().into(), |  | ||||||
|                 bit_rate_switching: false, |  | ||||||
|                 marker: None, |  | ||||||
|             }, |  | ||||||
|             &[i], |  | ||||||
|         ) |  | ||||||
|         .unwrap(); |  | ||||||
| 
 |  | ||||||
|         info!("Transmitting frame {}", i); |         info!("Transmitting frame {}", i); | ||||||
|         tx.write(&tx_frame).await; |         tx.write(&tx_frame).await; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Try and receive all 6 packets
 |     // Try and receive all 6 packets
 | ||||||
|     for i in 0..max_buffered { |     for i in 0..max_buffered { | ||||||
|         let envelope = rx.read().await.unwrap(); |         let (frame, _ts) = rx.read().await.unwrap(); | ||||||
|         match envelope.header.id { |         match frame.id() { | ||||||
|             can::Id::Extended(id) => { |             embedded_can::Id::Extended(id) => { | ||||||
|                 info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); |                 info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||||||
|             } |             } | ||||||
|             can::Id::Standard(id) => { |             embedded_can::Id::Standard(id) => { | ||||||
|                 info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); |                 info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user