1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
|
#![no_std]
#![feature(rustc_private)]
extern crate fusible;
use core::net::Ipv4Addr;
use core::num::NonZeroU8;
use core::pin::Pin;
use imxrt_rt as _;
use imxrt1170evk_fcb as _;
use rust_threadx_cortex_m as _;
use rust_threadx_imxrt::*;
use rust_threadx_stdio_semihosting as _;
use drivers::{enet, gpio};
use imxrt1170::interrupt;
use fusible::netx_duo::{
ip::{Ip, IpContext},
packet::{PacketPool, PacketPoolContext, StaticPacketStorage, packet_storage_size},
};
#[doc(hidden)]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn _tx_initialize_low_level() {
use cortex_m::{
Peripherals,
peripheral::{scb::SystemHandler, syst::SystClkSource},
};
cortex_m::interrupt::disable();
unsafe {
let Peripherals {
mut SYST, mut SCB, ..
} = Peripherals::steal();
SCB.set_priority(SystemHandler::SysTick, 0x40);
SCB.set_priority(SystemHandler::PendSV, 0xff);
SCB.set_priority(SystemHandler::SVCall, 0xff);
SYST.set_clock_source(SystClkSource::External);
SYST.set_reload(100_000 / 100 - 1);
SYST.clear_current();
SYST.enable_interrupt();
SYST.enable_counter();
}
}
use fusible::thread::{StaticStack, Thread, ThreadContext};
static STACK: StaticStack<512> = StaticStack::new();
static THREAD: ThreadContext = Thread::context();
#[unsafe(no_mangle)]
#[doc(hidden)]
pub extern "C" fn __rust_threadx_app_define() {
configure_clocks();
configure_pins();
unsafe {
cortex_m::peripheral::NVIC::unmask(interrupt::ENET);
let gpio3 = GPIO3.create(const { imxrt1170::instances::gpio3() });
let gpio6 = GPIO6.create(const { imxrt1170::instances::gpio6() });
let led = gpio3.make_output(gpio::IO::IO03);
let phy_rst = gpio6.make_output(gpio::IO::IO12);
let enet = ENET.create(
imxrt1170::instances::enet(),
ENET_TX_RING.as_slice(),
ENET_RX_RING.as_slice(),
rust_threadx_net_phys::ksz8081::Ksz8081::new(),
phy_rst,
BUS_FREQUENCY_HZ,
);
let pool = PacketPool::create(
Pin::static_ref(&PACKET_POOL),
PACKET_STORAGE.0.take().unwrap(),
1536 / 12,
&Default::default(),
)
.unwrap();
let ip = Ip::create(
Pin::static_ref(&IP),
Ipv4Addr::new(192, 168, 5, 1),
0xffff_ff00,
pool,
enet,
IP_THREAD_STACK.take().unwrap(),
&Default::default(),
)
.unwrap();
ip.set_physical_address(0x0011, 0x22334456);
ip.enable_arp();
ip.enable_udp();
ip.enable_icmp();
Thread::create(
Pin::static_ref(&THREAD),
STACK.take().unwrap(),
&Default::default(),
move || loop {
fusible::thread::sleep(25);
led.toggle();
},
)
.unwrap();
}
}
#[unsafe(no_mangle)]
#[doc(hidden)]
pub extern "C" fn __rust_threadx_ip() -> Option<&'static Ip> {
Pin::static_ref(&IP).try_created()
}
fn configure_clocks() {
use imxrt1170::{ccm, gpc_cpu_mode_ctrl as gpc_cpu, pmu};
let ccm = unsafe { imxrt1170::instances::ccm() };
let pmu = unsafe { imxrt1170::instances::pmu() };
let gpc_cpu = unsafe { imxrt1170::instances::gpc_cpu_mode_ctrl0() };
let pll = unsafe { imxrt1170::instances::pll() };
// Switch the core to something stable before we
// start changing upstream sources.
ccm::set_clock_root(
ccm,
ccm::ClockRoot::M7,
const { ccm::mux(ccm::ClockRoot::M7, ccm::ClockSource::Xtal) },
NO_DIVIDER,
);
ccm::set_clock_root(
ccm,
ccm::ClockRoot::Bus,
const { ccm::mux(ccm::ClockRoot::Bus, ccm::ClockSource::Xtal) },
NO_DIVIDER,
);
ccm::set_clock_root(
ccm,
ccm::ClockRoot::BusLpsr,
const { ccm::mux(ccm::ClockRoot::BusLpsr, ccm::ClockSource::Xtal) },
NO_DIVIDER,
);
ccm::set_clock_root(
ccm,
ccm::ClockRoot::M7Systick,
const { ccm::mux(ccm::ClockRoot::M7Systick, ccm::ClockSource::Xtal) },
const { NonZeroU8::new(240).unwrap() },
);
pmu::enable_pll_reference_voltage(pmu, true);
pmu::set_phy_ldo_setpoints(pmu, u16::MAX);
pmu::enable_phy_ldo_setpoints(pmu);
pmu::enable_pll_reference_setpoints(pmu);
for clock_source in {
use ccm::ClockSource::*;
[
Pll1, Pll1Clk, Pll1Div2, Pll1Div5, ArmPll, ArmPllClk, //
Pll2, Pll2Clk, Pll2Pfd0, Pll2Pfd1, Pll2Pfd2, Pll2Pfd3, //
Pll3, Pll3Clk, Pll3Div2, Pll3Pfd0, Pll3Pfd1, Pll3Pfd2, Pll3Pfd3, //
]
} {
ccm::set_source_setpoints(ccm, clock_source, u16::MAX, 0);
ccm::enable_source_setpoints(ccm, clock_source).unwrap();
}
ccm::pll::enable_sys_pll1_setpoints(pll);
ccm::pll::enable_arm_pll_setpoints(pll, ARM_PLL_POST_DIV, ARM_PLL_DIV_SELECT);
ccm::pll::enable_sys_pll2_setpoints(pll);
ccm::pll::enable_sys_pll3_setpoints(pll);
gpc_cpu::request_setpoint_transition(gpc_cpu, 1).unwrap();
ccm::pll::set_pll3_pfd_fracs(
pll,
[
SYS_PLL3_PFD0_DIV,
SYS_PLL3_PFD1_DIV,
SYS_PLL3_PFD2_DIV,
SYS_PLL3_PFD3_DIV,
],
);
ccm::pll::update_pll3_pfd_fracs(pll, [true, true, true, true]);
ccm::set_clock_root(
ccm,
ccm::ClockRoot::M7,
const { ccm::mux(ccm::ClockRoot::M7, ccm::ClockSource::ArmPll) },
M7_DIVIDER,
);
ccm::set_clock_root(
ccm,
ccm::ClockRoot::Bus,
const { ccm::mux(ccm::ClockRoot::Bus, ccm::ClockSource::Pll1Div5) },
BUS_DIVIDER,
);
ccm::set_clock_root(
ccm,
ccm::ClockRoot::Enet,
const { ccm::mux(ccm::ClockRoot::Enet, ccm::ClockSource::Pll1Div2) },
const { NonZeroU8::new((SYS_PLL1_DIV2_FREQUENCY_HZ / ENET_FREQUENCY_HZ) as u8).unwrap() },
);
}
const NO_DIVIDER: NonZeroU8 = NonZeroU8::new(1).unwrap();
const M7_DIVIDER: NonZeroU8 = NonZeroU8::new(1).unwrap();
const BUS_DIVIDER: NonZeroU8 = NonZeroU8::new(1).unwrap();
const FLEXSPI1_DIVIDER: NonZeroU8 = NonZeroU8::new(2).unwrap();
pub const XTAL_FREQUENCY_HZ: u32 = 24_000_000;
pub const BUS_FREQUENCY_HZ: u32 = SYS_PLL1_DIV5_FREQUENCY_HZ / BUS_DIVIDER.get() as u32;
pub const ENET_FREQUENCY_HZ: u32 = 50_000_000;
pub const SYS_PLL1_FREQUENCY_HZ: u32 = 1_000_000_000;
pub const SYS_PLL1_DIV2_FREQUENCY_HZ: u32 = SYS_PLL1_FREQUENCY_HZ / 2;
pub const SYS_PLL1_DIV5_FREQUENCY_HZ: u32 = SYS_PLL1_FREQUENCY_HZ / 5;
pub const M7_FREQUENCY_HZ: u32 = ARM_PLL_FREQUENCY_HZ / M7_DIVIDER.get() as u32;
pub const SYS_PLL2_FREQUENCY_HZ: u32 = 528_000_000;
pub const SYS_PLL3_FREQUENCY_HZ: u32 = 480_000_000;
pub const FLEXSPI1_FREQUENCY_HZ: u32 =
SYS_PLL3_FREQUENCY_HZ / SYS_PLL3_PFD0_DIV.get() as u32 / FLEXSPI1_DIVIDER.get() as u32 * 18;
const ARM_PLL_DIV_SELECT: imxrt1170::ccm::pll::ArmPllDivSelect =
imxrt1170::ccm::pll::ArmPllDivSelect::new(200).unwrap();
const ARM_PLL_POST_DIV: imxrt1170::ccm::pll::ArmPllPostDiv =
imxrt1170::ccm::pll::ArmPllPostDiv::Div4;
const ARM_PLL_FREQUENCY_HZ: u32 =
imxrt1170::ccm::pll::arm_pll_frequency(ARM_PLL_POST_DIV, ARM_PLL_DIV_SELECT);
const SYS_PLL3_PFD0_DIV: imxrt1170::ccm::pll::PfdFrac =
imxrt1170::ccm::pll::PfdFrac::new(33).unwrap();
const SYS_PLL3_PFD1_DIV: imxrt1170::ccm::pll::PfdFrac =
imxrt1170::ccm::pll::PfdFrac::new(27).unwrap();
const SYS_PLL3_PFD2_DIV: imxrt1170::ccm::pll::PfdFrac =
imxrt1170::ccm::pll::PfdFrac::new(21).unwrap();
const SYS_PLL3_PFD3_DIV: imxrt1170::ccm::pll::PfdFrac =
imxrt1170::ccm::pll::PfdFrac::new(17).unwrap();
fn configure_pins() {
use imxrt1170::{
iomuxc::{self, select_input},
iomuxc_gpr, iomuxc_lpsr,
};
let iomuxc = unsafe { imxrt1170::instances::iomuxc() };
let iomuxc_gpr = unsafe { imxrt1170::instances::iomuxc_gpr() };
let iomuxc_lpsr = unsafe { imxrt1170::instances::iomuxc_lpsr() };
// ENET_REF_CLK driven as output.
modify_reg!(iomuxc_gpr, iomuxc_gpr, GPR[4], |gpr| gpr | (1 << 1));
// ERR050396 handling.
modify_reg!(iomuxc_gpr, iomuxc_gpr, GPR[28], |gpr| gpr
| (1 << 5)
| (1 << 7));
// LED.
write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_AD[4], MUX_MODE: 5);
write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_AD[4], PUE: 0);
// ENET PHY_RST.
write_reg!(iomuxc_lpsr, iomuxc_lpsr, SW_MUX_CTL_PAD[12], MUX_MODE: 5);
// ENET RMII.
write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_AD[32], MUX_MODE: 3, SION: 0); // MDC
write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_AD[33], MUX_MODE: 3, SION: 0); // MDIO
write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[2], MUX_MODE: 1, SION: 0); // TX_DATA0
write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[3], MUX_MODE: 1, SION: 0); // TX_DATA1
write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[4], MUX_MODE: 1, SION: 0); // TX_EN
write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[5], MUX_MODE: 2, SION: 1); // REF_CLK
write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[6], MUX_MODE: 1, SION: 1); // RX_DATA0
write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[7], MUX_MODE: 1, SION: 1); // RX_DATA1
write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[8], MUX_MODE: 1, SION: 0); // RX_EN
write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[9], MUX_MODE: 1, SION: 0); // RX_ER
write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_AD[32], PUE: 1, PUS: PULL_UP, ODE: 0); // MDC
write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_AD[33], PUE: 1, PUS: PULL_UP, ODE: 1); // MDIO
write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[2], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // TX_DATA0
write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[3], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // TX_DATA1
write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[4], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // TX_EN
write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[5], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // REF_CLK
write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[6], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // RX_DATA0
write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[7], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // RX_DATA1
write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[8], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // RX_EN
write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[9], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // RX_ER
for select_input in [
select_input::ENET_IPG_CLK_RMII,
select_input::ENET_MAC0_MDIO,
select_input::ENET_MAC0_RXDATA_0,
select_input::ENET_MAC0_RXDATA_1,
select_input::ENET_MAC0_RXEN,
select_input::ENET_MAC0_RXERR,
] {
write_reg!(iomuxc, iomuxc, SELECT_INPUT[select_input], 1);
}
}
type Enet = drivers::enet::Enet<rust_threadx_net_phys::ksz8081::Ksz8081>;
static ENET: enet::EnetContext = enet::EnetContext::new();
static ENET_TX_RING: enet::TxRing<16> = enet::TxRing::ZEROED;
static ENET_RX_RING: enet::RxRing<16> = enet::RxRing::ZEROED;
static IP: IpContext<Enet> = Ip::context();
#[repr(align(64))]
pub struct AlignedPacketStorage(StaticPacketStorage<{ packet_storage_size(8 * 12, 1536 / 12) }>);
static PACKET_POOL: PacketPoolContext = PacketPool::context();
static PACKET_STORAGE: AlignedPacketStorage = AlignedPacketStorage(StaticPacketStorage::new());
static IP_THREAD_STACK: StaticStack<4096> = StaticStack::new();
static GPIO3: gpio::GpioContext = gpio::GpioContext::new();
static GPIO6: gpio::GpioContext = gpio::GpioContext::new();
#[imxrt_rt::interrupt]
fn ENET() {
unsafe {
ENET.on_interrupt(
const { imxrt1170::instances::enet() },
Pin::static_ref(&IP).assume_created(),
)
}
}
|