aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32-wpan/src/wb55/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32-wpan/src/wb55/mod.rs')
-rw-r--r--embassy-stm32-wpan/src/wb55/mod.rs198
1 files changed, 198 insertions, 0 deletions
diff --git a/embassy-stm32-wpan/src/wb55/mod.rs b/embassy-stm32-wpan/src/wb55/mod.rs
new file mode 100644
index 000000000..95cfe09f1
--- /dev/null
+++ b/embassy-stm32-wpan/src/wb55/mod.rs
@@ -0,0 +1,198 @@
1// This must go FIRST so that all the other modules see its macros.
2mod fmt;
3
4use core::mem::MaybeUninit;
5use core::sync::atomic::{Ordering, compiler_fence};
6
7use embassy_hal_internal::Peri;
8use embassy_stm32::interrupt;
9use embassy_stm32::ipcc::{Config, Ipcc, IpccRxChannel, ReceiveInterruptHandler, TransmitInterruptHandler};
10use embassy_stm32::peripherals::IPCC;
11use sub::mm::MemoryManager;
12use sub::sys::Sys;
13use tables::*;
14use unsafe_linked_list::LinkedListNode;
15
16pub mod channels;
17pub mod cmd;
18pub mod consts;
19pub mod evt;
20pub mod lhci;
21pub mod shci;
22pub mod sub;
23pub mod tables;
24pub mod unsafe_linked_list;
25
26#[cfg(feature = "wb55_mac")]
27pub mod mac;
28
29#[cfg(feature = "wb55_ble")]
30pub use crate::sub::ble::hci;
31
32type PacketHeader = LinkedListNode;
33
34/// Transport Layer for the Mailbox interface
35pub struct TlMbox<'d> {
36 pub sys_subsystem: Sys<'d>,
37 pub mm_subsystem: MemoryManager<'d>,
38 #[cfg(feature = "wb55_ble")]
39 pub ble_subsystem: sub::ble::Ble<'d>,
40 #[cfg(feature = "wb55_mac")]
41 pub mac_subsystem: sub::mac::Mac<'d>,
42 pub traces: IpccRxChannel<'d>,
43}
44
45impl<'d> TlMbox<'d> {
46 /// Initialise the Transport Layer, and creates and returns a wrapper around it.
47 ///
48 /// This method performs the initialisation laid out in AN5289 annex 14.1. However, it differs
49 /// from the implementation documented in Figure 64, to avoid needing to reference any C
50 /// function pointers.
51 ///
52 /// Annex 14.1 lays out the following methods that should be called:
53 /// 1. tl_mbox.c/TL_Init, which initialises the reference table that is shared between CPU1
54 /// and CPU2.
55 /// 2. shci_tl.c/shci_init(), which initialises the system transport layer, and in turn
56 /// calls tl_mbox.c/TL_SYS_Init, which initialises SYSTEM_EVT_QUEUE channel.
57 /// 3. tl_mbox.c/TL_MM_Init(), which initialises the channel used for sending memory
58 /// manager commands.
59 /// 4. tl_mbox.c/TL_Enable(), which enables the IPCC, and starts CPU2.
60 /// This implementation initialises all of the shared refernce tables and all IPCC channel that
61 /// would be initialised by this process. The developer should therefore treat this method as
62 /// completing all steps in Figure 64.
63 ///
64 /// Once this method has been called, no system commands may be sent until the CPU2 ready
65 /// signal is received, via [sys_subsystem.read]; this completes the procedure laid out in
66 /// Figure 65.
67 ///
68 /// If the `ble` feature is enabled, at this point, the user should call
69 /// [sys_subsystem.shci_c2_ble_init], before any commands are written to the
70 /// [TlMbox.ble_subsystem] ([sub::ble::Ble::new()] completes the process that would otherwise
71 /// be handled by `TL_BLE_Init`; see Figure 66). This completes the procedure laid out in
72 /// Figure 66.
73 // TODO: document what the user should do after calling init to use the mac_802_15_4 subsystem
74 pub async fn init(
75 ipcc: Peri<'d, IPCC>,
76 _irqs: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler>
77 + interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_TX, TransmitInterruptHandler>,
78 config: Config,
79 ) -> Self {
80 // this is an inlined version of TL_Init from the STM32WB firmware as requested by AN5289.
81 // HW_IPCC_Init is not called, and its purpose is (presumably?) covered by this
82 // implementation
83 unsafe {
84 TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable {
85 device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(),
86 ble_table: TL_BLE_TABLE.as_ptr(),
87 thread_table: TL_THREAD_TABLE.as_ptr(),
88 sys_table: TL_SYS_TABLE.as_ptr(),
89 mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(),
90 traces_table: TL_TRACES_TABLE.as_ptr(),
91 mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(),
92 zigbee_table: TL_ZIGBEE_TABLE.as_ptr(),
93 lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(),
94 ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(),
95 });
96
97 TL_SYS_TABLE
98 .as_mut_ptr()
99 .write_volatile(MaybeUninit::zeroed().assume_init());
100 TL_DEVICE_INFO_TABLE
101 .as_mut_ptr()
102 .write_volatile(MaybeUninit::zeroed().assume_init());
103 TL_BLE_TABLE
104 .as_mut_ptr()
105 .write_volatile(MaybeUninit::zeroed().assume_init());
106 TL_THREAD_TABLE
107 .as_mut_ptr()
108 .write_volatile(MaybeUninit::zeroed().assume_init());
109 TL_MEM_MANAGER_TABLE
110 .as_mut_ptr()
111 .write_volatile(MaybeUninit::zeroed().assume_init());
112
113 TL_TRACES_TABLE
114 .as_mut_ptr()
115 .write_volatile(MaybeUninit::zeroed().assume_init());
116 TL_MAC_802_15_4_TABLE
117 .as_mut_ptr()
118 .write_volatile(MaybeUninit::zeroed().assume_init());
119 TL_ZIGBEE_TABLE
120 .as_mut_ptr()
121 .write_volatile(MaybeUninit::zeroed().assume_init());
122 TL_LLD_TESTS_TABLE
123 .as_mut_ptr()
124 .write_volatile(MaybeUninit::zeroed().assume_init());
125 TL_BLE_LLD_TABLE
126 .as_mut_ptr()
127 .write_volatile(MaybeUninit::zeroed().assume_init());
128
129 EVT_POOL
130 .as_mut_ptr()
131 .write_volatile(MaybeUninit::zeroed().assume_init());
132 SYS_SPARE_EVT_BUF
133 .as_mut_ptr()
134 .write_volatile(MaybeUninit::zeroed().assume_init());
135 CS_BUFFER
136 .as_mut_ptr()
137 .write_volatile(MaybeUninit::zeroed().assume_init());
138
139 #[cfg(feature = "wb55_ble")]
140 {
141 BLE_SPARE_EVT_BUF
142 .as_mut_ptr()
143 .write_volatile(MaybeUninit::zeroed().assume_init());
144
145 BLE_CMD_BUFFER
146 .as_mut_ptr()
147 .write_volatile(MaybeUninit::zeroed().assume_init());
148 HCI_ACL_DATA_BUFFER
149 .as_mut_ptr()
150 .write_volatile(MaybeUninit::zeroed().assume_init());
151 }
152
153 #[cfg(feature = "wb55_mac")]
154 {
155 MAC_802_15_4_CMD_BUFFER
156 .as_mut_ptr()
157 .write_volatile(MaybeUninit::zeroed().assume_init());
158 MAC_802_15_4_NOTIF_RSP_EVT_BUFFER
159 .as_mut_ptr()
160 .write_volatile(MaybeUninit::zeroed().assume_init());
161 }
162 }
163
164 compiler_fence(Ordering::SeqCst);
165
166 // this is equivalent to `HW_IPCC_Enable`, which is called by `TL_Enable`
167 let [
168 (_hw_ipcc_ble_cmd_channel, _ipcc_ble_event_channel),
169 (ipcc_system_cmd_rsp_channel, ipcc_system_event_channel),
170 (_ipcc_mac_802_15_4_cmd_rsp_channel, _ipcc_mac_802_15_4_notification_ack_channel),
171 (ipcc_mm_release_buffer_channel, _ipcc_traces_channel),
172 (_ipcc_ble_lld_cmd_channel, _ipcc_ble_lld_rsp_channel),
173 (_ipcc_hci_acl_data_channel, _),
174 ] = Ipcc::new(ipcc, _irqs, config).split();
175
176 let mm = sub::mm::MemoryManager::new(ipcc_mm_release_buffer_channel);
177 let mut sys = sub::sys::Sys::new(ipcc_system_cmd_rsp_channel, ipcc_system_event_channel);
178
179 debug!("sys event: {}", sys.read().await.payload());
180
181 Self {
182 sys_subsystem: sys,
183 #[cfg(feature = "wb55_ble")]
184 ble_subsystem: sub::ble::Ble::new(
185 _hw_ipcc_ble_cmd_channel,
186 _ipcc_ble_event_channel,
187 _ipcc_hci_acl_data_channel,
188 ),
189 #[cfg(feature = "wb55_mac")]
190 mac_subsystem: sub::mac::Mac::new(
191 _ipcc_mac_802_15_4_cmd_rsp_channel,
192 _ipcc_mac_802_15_4_notification_ack_channel,
193 ),
194 mm_subsystem: mm,
195 traces: _ipcc_traces_channel,
196 }
197 }
198}