1use bit_field::BitField;
5use core::cell::RefCell;
6use core::mem::MaybeUninit;
7use core::sync::atomic::{self, AtomicBool, Ordering};
8use core::{fmt::Write, ptr, slice};
9use embedded_hal_compat::{markers::ForwardOutputPin, Forward, ForwardCompat};
10use heapless::String;
11use stm32h7xx_hal::{
12 self as hal,
13 ethernet::{self, PHY},
14 gpio::Speed,
15 prelude::*,
16};
17
18use smoltcp_nal::smoltcp;
19
20use crate::hardware::delay::AsmDelay;
21use crate::settings::{AppSettings, NetSettings};
22
23use super::{
24 adc, afe, cpu_temp_sensor::CpuTempSensor, dac, delay, design_parameters,
25 eeprom, input_stamper::InputStamper, metadata::ApplicationMetadata,
26 platform, pounder, pounder::dds_output::DdsOutput, shared_adc::SharedAdc,
27 timers, DigitalInput0, DigitalInput1, Eem, EthernetPhy, Gpio,
28 HardwareVersion, NetworkStack, SerialTerminal, SystemTimer, Systick,
29 UsbDevice, AFE0, AFE1,
30};
31
32const NUM_TCP_SOCKETS: usize = 4;
33const NUM_UDP_SOCKETS: usize = 1;
34const NUM_SOCKETS: usize = NUM_UDP_SOCKETS + NUM_TCP_SOCKETS;
35
36pub struct NetStorage {
37 pub ip_addrs: [smoltcp::wire::IpCidr; 1],
38
39 pub sockets: [smoltcp::iface::SocketStorage<'static>; NUM_SOCKETS + 2],
42 pub tcp_socket_storage: [TcpSocketStorage; NUM_TCP_SOCKETS],
43 pub udp_socket_storage: [UdpSocketStorage; NUM_UDP_SOCKETS],
44 pub dns_storage: [Option<smoltcp::socket::dns::DnsQuery>; 1],
45}
46
47#[derive(Copy, Clone)]
48pub struct UdpSocketStorage {
49 rx_storage: [u8; 1024],
50 tx_storage: [u8; 2048],
51 tx_metadata: [smoltcp::storage::PacketMetadata<
52 smoltcp::socket::udp::UdpMetadata,
53 >; 10],
54 rx_metadata: [smoltcp::storage::PacketMetadata<
55 smoltcp::socket::udp::UdpMetadata,
56 >; 10],
57}
58
59impl UdpSocketStorage {
60 const fn new() -> Self {
61 Self {
62 rx_storage: [0; 1024],
63 tx_storage: [0; 2048],
64 tx_metadata: [smoltcp::storage::PacketMetadata::EMPTY; 10],
65 rx_metadata: [smoltcp::storage::PacketMetadata::EMPTY; 10],
66 }
67 }
68}
69
70#[derive(Copy, Clone)]
71pub struct TcpSocketStorage {
72 rx_storage: [u8; 1024],
73 tx_storage: [u8; 1024],
74}
75
76impl TcpSocketStorage {
77 const fn new() -> Self {
78 Self {
79 rx_storage: [0; 1024],
80 tx_storage: [0; 1024],
81 }
82 }
83}
84
85impl Default for NetStorage {
86 fn default() -> Self {
87 NetStorage {
88 ip_addrs: [smoltcp::wire::IpCidr::Ipv6(
90 smoltcp::wire::Ipv6Cidr::SOLICITED_NODE_PREFIX,
91 )],
92 sockets: [smoltcp::iface::SocketStorage::EMPTY; NUM_SOCKETS + 2],
93 tcp_socket_storage: [TcpSocketStorage::new(); NUM_TCP_SOCKETS],
94 udp_socket_storage: [UdpSocketStorage::new(); NUM_UDP_SOCKETS],
95 dns_storage: [None; 1],
96 }
97 }
98}
99
100pub struct NetworkDevices {
102 pub stack: NetworkStack,
103 pub phy: EthernetPhy,
104 pub mac_address: smoltcp::wire::EthernetAddress,
105}
106
107pub struct StabilizerDevices<
109 C: serial_settings::Settings + 'static,
110 const Y: usize,
111> {
112 pub temperature_sensor: CpuTempSensor,
113 pub afes: (AFE0, AFE1),
114 pub adcs: (adc::Adc0Input, adc::Adc1Input),
115 pub dacs: (dac::Dac0Output, dac::Dac1Output),
116 pub timestamper: InputStamper,
117 pub adc_dac_timer: timers::SamplingTimer,
118 pub timestamp_timer: timers::TimestampTimer,
119 pub net: NetworkDevices,
120 pub digital_inputs: (DigitalInput0, DigitalInput1),
121 pub eem: Eem,
122 pub usb_serial: SerialTerminal<C, Y>,
123 pub usb: UsbDevice,
124 pub metadata: &'static ApplicationMetadata,
125 pub settings: C,
126}
127
128pub struct PounderDevices {
130 pub pounder: pounder::PounderDevices,
131 pub dds_output: DdsOutput,
132
133 #[cfg(not(feature = "pounder_v1_0"))]
134 pub timestamper: pounder::timestamp::Timestamper,
135}
136
137#[link_section = ".sram3.eth"]
138static mut DES_RING: MaybeUninit<
140 ethernet::DesRing<{ super::TX_DESRING_CNT }, { super::RX_DESRING_CNT }>,
141> = MaybeUninit::uninit();
142
143fn load_itcm() {
154 extern "C" {
155 static mut __sitcm: u32;
156 static mut __eitcm: u32;
157 static mut __siitcm: u32;
158 }
159 unsafe {
165 const ITCMCR: *mut u32 = 0xE000_EF90usize as _;
168 ptr::write_volatile(ITCMCR, ptr::read_volatile(ITCMCR) | 1);
169
170 atomic::fence(Ordering::SeqCst);
172
173 let sitcm = core::ptr::addr_of_mut!(__sitcm);
174 let eitcm = core::ptr::addr_of_mut!(__eitcm);
175 let siitcm = core::ptr::addr_of_mut!(__siitcm);
176
177 let len = eitcm.offset_from(sitcm) as usize;
178 let dst = slice::from_raw_parts_mut(sitcm, len);
179 let src = slice::from_raw_parts(siitcm, len);
180 dst.copy_from_slice(src);
182 }
183
184 atomic::fence(Ordering::SeqCst);
186 cortex_m::asm::dsb();
187 cortex_m::asm::isb();
188}
189
190pub fn setup<C, const Y: usize>(
208 mut core: stm32h7xx_hal::stm32::CorePeripherals,
209 device: stm32h7xx_hal::stm32::Peripherals,
210 clock: SystemTimer,
211 batch_size: usize,
212 sample_ticks: u32,
213) -> (StabilizerDevices<C, Y>, Option<PounderDevices>)
214where
215 C: serial_settings::Settings + AppSettings,
216{
217 {
219 device.DBGMCU.cr.modify(|_, w| w.dbgsleep_d1().set_bit());
221
222 let channels = rtt_target::rtt_init_default!();
231 unsafe {
234 rtt_target::set_print_channel_cs(
235 channels.up.0,
236 &((|arg, f| {
237 static LOCKED: AtomicBool = AtomicBool::new(false);
238 if LOCKED.compare_exchange_weak(
239 false,
240 true,
241 Ordering::Acquire,
242 Ordering::Relaxed,
243 ) == Ok(false)
244 {
245 f(arg);
246 LOCKED.store(false, Ordering::Release);
247 }
248 }) as rtt_target::CriticalSectionFunc),
249 );
250 }
251
252 static LOGGER: rtt_logger::RTTLogger =
253 rtt_logger::RTTLogger::new(log::LevelFilter::Info);
254 log::set_logger(&LOGGER)
255 .map(|()| log::set_max_level(log::LevelFilter::Trace))
256 .unwrap();
257 log::info!("Starting");
258 }
259
260 if platform::dfu_bootflag() {
262 platform::execute_system_bootloader();
263 }
264
265 let pwr = device.PWR.constrain();
266 let vos = pwr.freeze();
267
268 device.RCC.ahb2enr.modify(|_, w| w.sram3en().set_bit());
270
271 device.RCC.rsr.write(|w| w.rmvf().set_bit());
273
274 device
276 .RCC
277 .d2ccip1r
278 .modify(|_, w| w.spi123sel().pll2_p().spi45sel().pll2_q());
279
280 device.RCC.d1ccipr.modify(|_, w| w.qspisel().rcc_hclk3());
281
282 device
283 .RCC
284 .d3ccipr
285 .modify(|_, w| w.adcsel().per().spi6sel().pll2_q());
286
287 let rcc = device.RCC.constrain();
288 let mut ccdr = rcc
289 .use_hse(8.MHz())
290 .sysclk(design_parameters::SYSCLK.convert())
291 .hclk(200.MHz())
292 .per_ck(64.MHz()) .pll2_p_ck(100.MHz())
294 .pll2_q_ck(100.MHz())
295 .freeze(vos, &device.SYSCFG);
296
297 ccdr.clocks.hsi48_ck().unwrap();
299 ccdr.peripheral
300 .kernel_usb_clk_mux(stm32h7xx_hal::rcc::rec::UsbClkSel::Hsi48);
301
302 load_itcm();
304
305 Systick::start(core.SYST, ccdr.clocks.sysclk().to_Hz());
306
307 core.SCB.enable_icache();
309
310 let mut delay = delay::AsmDelay::new(ccdr.clocks.c_ck().to_Hz());
311
312 let gpioa = device.GPIOA.split(ccdr.peripheral.GPIOA);
313 let gpiob = device.GPIOB.split(ccdr.peripheral.GPIOB);
314 let gpioc = device.GPIOC.split(ccdr.peripheral.GPIOC);
315 let gpiod = device.GPIOD.split(ccdr.peripheral.GPIOD);
316 let gpioe = device.GPIOE.split(ccdr.peripheral.GPIOE);
317 let gpiof = device.GPIOF.split(ccdr.peripheral.GPIOF);
318 let mut gpiog = device.GPIOG.split(ccdr.peripheral.GPIOG);
319
320 let dma_streams =
321 hal::dma::dma::StreamsTuple::new(device.DMA1, ccdr.peripheral.DMA1);
322
323 assert!(
325 (batch_size as u32 * sample_ticks) as f32
326 * design_parameters::TIMER_PERIOD
327 * (super::MONOTONIC_FREQUENCY as f32)
328 < 1.
329 );
330
331 let mut sampling_timer = {
333 let mut timer2 =
336 device
337 .TIM2
338 .timer(1.kHz(), ccdr.peripheral.TIM2, &ccdr.clocks);
339
340 timer2.pause();
343 timer2.set_tick_freq(design_parameters::TIMER_FREQUENCY.convert());
344
345 let mut sampling_timer = timers::SamplingTimer::new(timer2);
346 sampling_timer.set_period_ticks(sample_ticks - 1);
347
348 sampling_timer
352 };
353
354 let mut shadow_sampling_timer = {
355 let mut timer3 =
358 device
359 .TIM3
360 .timer(1.kHz(), ccdr.peripheral.TIM3, &ccdr.clocks);
361
362 timer3.pause();
365 timer3.reset_counter();
366 timer3.set_tick_freq(design_parameters::TIMER_FREQUENCY.convert());
367
368 let mut shadow_sampling_timer =
369 timers::ShadowSamplingTimer::new(timer3);
370 shadow_sampling_timer.set_period_ticks(sample_ticks as u16 - 1);
371
372 shadow_sampling_timer.set_slave_mode(
378 timers::TriggerSource::Trigger1,
379 timers::SlaveMode::Trigger,
380 );
381
382 shadow_sampling_timer
383 };
384
385 let sampling_timer_channels = sampling_timer.channels();
386 let shadow_sampling_timer_channels = shadow_sampling_timer.channels();
387
388 let mut timestamp_timer = {
389 let mut timer5 =
392 device
393 .TIM5
394 .timer(1.kHz(), ccdr.peripheral.TIM5, &ccdr.clocks);
395
396 timer5.pause();
399 timer5.set_tick_freq(design_parameters::TIMER_FREQUENCY.convert());
400
401 let mut timer = timers::TimestampTimer::new(timer5);
405
406 timer.set_period_ticks(u32::MAX);
410
411 timer
412 };
413
414 let timestamp_timer_channels = timestamp_timer.channels();
415
416 let adcs = {
418 let adc0 = {
419 let miso = gpiob.pb14.into_alternate().speed(Speed::VeryHigh);
420 let sck = gpiob.pb10.into_alternate().speed(Speed::VeryHigh);
421 let nss = gpiob.pb9.into_alternate().speed(Speed::VeryHigh);
422
423 let config = hal::spi::Config::new(hal::spi::Mode {
424 polarity: hal::spi::Polarity::IdleHigh,
425 phase: hal::spi::Phase::CaptureOnSecondTransition,
426 })
427 .hardware_cs(hal::spi::HardwareCS {
428 mode: hal::spi::HardwareCSMode::WordTransaction,
429 assertion_delay: design_parameters::ADC_SETUP_TIME,
430 polarity: hal::spi::Polarity::IdleHigh,
431 })
432 .communication_mode(hal::spi::CommunicationMode::Receiver);
433
434 let spi: hal::spi::Spi<_, _, u16> = device.SPI2.spi(
435 (sck, miso, hal::spi::NoMosi, nss),
436 config,
437 design_parameters::ADC_DAC_SCK_MAX.convert(),
438 ccdr.peripheral.SPI2,
439 &ccdr.clocks,
440 );
441
442 adc::Adc0Input::new(
443 spi,
444 dma_streams.0,
445 dma_streams.1,
446 dma_streams.2,
447 sampling_timer_channels.ch1,
448 shadow_sampling_timer_channels.ch1,
449 batch_size,
450 )
451 };
452
453 let adc1 = {
454 let miso = gpiob.pb4.into_alternate().speed(Speed::VeryHigh);
455 let sck = gpioc.pc10.into_alternate().speed(Speed::VeryHigh);
456 let nss = gpioa.pa15.into_alternate().speed(Speed::VeryHigh);
457
458 let config = hal::spi::Config::new(hal::spi::Mode {
459 polarity: hal::spi::Polarity::IdleHigh,
460 phase: hal::spi::Phase::CaptureOnSecondTransition,
461 })
462 .hardware_cs(hal::spi::HardwareCS {
463 mode: hal::spi::HardwareCSMode::WordTransaction,
464 assertion_delay: design_parameters::ADC_SETUP_TIME,
465 polarity: hal::spi::Polarity::IdleHigh,
466 })
467 .communication_mode(hal::spi::CommunicationMode::Receiver);
468
469 let spi: hal::spi::Spi<_, _, u16> = device.SPI3.spi(
470 (sck, miso, hal::spi::NoMosi, nss),
471 config,
472 design_parameters::ADC_DAC_SCK_MAX.convert(),
473 ccdr.peripheral.SPI3,
474 &ccdr.clocks,
475 );
476
477 adc::Adc1Input::new(
478 spi,
479 dma_streams.3,
480 dma_streams.4,
481 dma_streams.5,
482 sampling_timer_channels.ch2,
483 shadow_sampling_timer_channels.ch2,
484 batch_size,
485 )
486 };
487
488 (adc0, adc1)
489 };
490
491 let dacs = {
492 let mut dac_clr_n = gpioe.pe12.into_push_pull_output();
493 dac_clr_n.set_high();
494
495 let dac0_spi = {
496 let miso = gpioe.pe5.into_alternate().speed(Speed::VeryHigh);
497 let sck = gpioe.pe2.into_alternate().speed(Speed::VeryHigh);
498 let nss = gpioe.pe4.into_alternate().speed(Speed::VeryHigh);
499
500 let config = hal::spi::Config::new(hal::spi::Mode {
501 polarity: hal::spi::Polarity::IdleHigh,
502 phase: hal::spi::Phase::CaptureOnSecondTransition,
503 })
504 .hardware_cs(hal::spi::HardwareCS {
505 mode: hal::spi::HardwareCSMode::WordTransaction,
506 assertion_delay: 0.0,
507 polarity: hal::spi::Polarity::IdleHigh,
508 })
509 .communication_mode(hal::spi::CommunicationMode::Transmitter)
510 .swap_mosi_miso();
511
512 device.SPI4.spi(
513 (sck, miso, hal::spi::NoMosi, nss),
514 config,
515 design_parameters::ADC_DAC_SCK_MAX.convert(),
516 ccdr.peripheral.SPI4,
517 &ccdr.clocks,
518 )
519 };
520
521 let dac1_spi = {
522 let miso = gpiof.pf8.into_alternate().speed(Speed::VeryHigh);
523 let sck = gpiof.pf7.into_alternate().speed(Speed::VeryHigh);
524 let nss = gpiof.pf6.into_alternate().speed(Speed::VeryHigh);
525
526 let config = hal::spi::Config::new(hal::spi::Mode {
527 polarity: hal::spi::Polarity::IdleHigh,
528 phase: hal::spi::Phase::CaptureOnSecondTransition,
529 })
530 .hardware_cs(hal::spi::HardwareCS {
531 mode: hal::spi::HardwareCSMode::WordTransaction,
532 assertion_delay: 0.0,
533 polarity: hal::spi::Polarity::IdleHigh,
534 })
535 .communication_mode(hal::spi::CommunicationMode::Transmitter)
536 .swap_mosi_miso();
537
538 device.SPI5.spi(
539 (sck, miso, hal::spi::NoMosi, nss),
540 config,
541 design_parameters::ADC_DAC_SCK_MAX.convert(),
542 ccdr.peripheral.SPI5,
543 &ccdr.clocks,
544 )
545 };
546
547 let dac0 = dac::Dac0Output::new(
548 dac0_spi,
549 dma_streams.6,
550 sampling_timer_channels.ch3,
551 batch_size,
552 );
553 let dac1 = dac::Dac1Output::new(
554 dac1_spi,
555 dma_streams.7,
556 sampling_timer_channels.ch4,
557 batch_size,
558 );
559
560 dac_clr_n.set_low();
561 gpioe.pe11.into_push_pull_output().set_low();
563 gpioe.pe15.into_push_pull_output().set_low();
565 dac_clr_n.set_high();
566
567 (dac0, dac1)
568 };
569
570 let afes = {
571 gpioe.pe1.into_push_pull_output().set_high();
573
574 let afe0 = {
575 let a0_pin = gpiof.pf2.into_push_pull_output();
576 let a1_pin = gpiof.pf5.into_push_pull_output();
577 afe::ProgrammableGainAmplifier::new(a0_pin, a1_pin)
578 };
579
580 let afe1 = {
581 let a0_pin = gpiod.pd14.into_push_pull_output();
582 let a1_pin = gpiod.pd15.into_push_pull_output();
583 afe::ProgrammableGainAmplifier::new(a0_pin, a1_pin)
584 };
585
586 (afe0, afe1)
587 };
588
589 let input_stamper = {
590 let trigger = gpioa.pa3.into_alternate();
591 InputStamper::new(trigger, timestamp_timer_channels.ch4)
592 };
593
594 let digital_inputs = {
595 let di0 = gpiog.pg9.into_floating_input();
596 let di1 = gpioc.pc15.into_floating_input();
597 (di0, di1)
598 };
599
600 let mut eeprom_i2c = {
601 let sda = gpiof.pf0.into_alternate().set_open_drain();
602 let scl = gpiof.pf1.into_alternate().set_open_drain();
603 device.I2C2.i2c(
604 (scl, sda),
605 100.kHz(),
606 ccdr.peripheral.I2C2,
607 &ccdr.clocks,
608 )
609 };
610
611 let metadata = {
612 let hardware_version = {
614 let hwrev0 = gpiog.pg0.into_pull_down_input();
615 let hwrev1 = gpiog.pg1.into_pull_down_input();
616 let hwrev2 = gpiog.pg2.into_pull_down_input();
617 let hwrev3 = gpiog.pg3.into_pull_down_input();
618
619 HardwareVersion::from(
620 *0u8.set_bit(0, hwrev0.is_high())
621 .set_bit(1, hwrev1.is_high())
622 .set_bit(2, hwrev2.is_high())
623 .set_bit(3, hwrev3.is_high()),
624 )
625 };
626
627 ApplicationMetadata::new(hardware_version)
628 };
629
630 let mac_addr = smoltcp::wire::EthernetAddress(eeprom::read_eui48(
631 &mut eeprom_i2c,
632 &mut delay,
633 ));
634 log::info!("EUI48: {}", mac_addr);
635
636 let (flash, mut settings) = {
637 let mut flash = {
638 let (_, flash_bank2) = device.FLASH.split();
639 super::flash::Flash(flash_bank2.unwrap())
640 };
641
642 let mut settings = C::new(NetSettings::new(mac_addr));
643 crate::settings::SerialSettingsPlatform::load(
644 &mut settings,
645 &mut flash,
646 );
647 (flash, settings)
648 };
649
650 let network_devices = {
651 let ethernet_pins = {
652 let mut eth_phy_nrst = gpioe.pe3.into_push_pull_output();
654 eth_phy_nrst.set_low();
655 delay.delay_us(200u8);
656 eth_phy_nrst.set_high();
657
658 let ref_clk = gpioa.pa1.into_alternate().speed(Speed::VeryHigh);
659 let mdio = gpioa.pa2.into_alternate().speed(Speed::VeryHigh);
660 let mdc = gpioc.pc1.into_alternate().speed(Speed::VeryHigh);
661 let crs_dv = gpioa.pa7.into_alternate().speed(Speed::VeryHigh);
662 let rxd0 = gpioc.pc4.into_alternate().speed(Speed::VeryHigh);
663 let rxd1 = gpioc.pc5.into_alternate().speed(Speed::VeryHigh);
664 let tx_en = gpiob.pb11.into_alternate().speed(Speed::VeryHigh);
665 let txd0 = gpiob.pb12.into_alternate().speed(Speed::VeryHigh);
666 let txd1 = gpiog.pg14.into_alternate().speed(Speed::VeryHigh);
667
668 (ref_clk, mdio, mdc, crs_dv, rxd0, rxd1, tx_en, txd0, txd1)
669 };
670
671 let ring = unsafe { DES_RING.write(ethernet::DesRing::new()) };
672
673 let (mut eth_dma, eth_mac) = ethernet::new(
675 device.ETHERNET_MAC,
676 device.ETHERNET_MTL,
677 device.ETHERNET_DMA,
678 ethernet_pins,
679 ring,
682 mac_addr,
683 ccdr.peripheral.ETH1MAC,
684 &ccdr.clocks,
685 );
686
687 let mut lan8742a =
689 ethernet::phy::LAN8742A::new(eth_mac.set_phy_addr(0));
690 lan8742a.phy_reset();
691 lan8742a.phy_init();
692
693 unsafe { ethernet::enable_interrupt() };
694
695 let ip_addrs: smoltcp::wire::IpAddress = match settings.net().ip.parse()
697 {
698 Ok(addr) => addr,
699 Err(e) => {
700 log::warn!("Invalid IP address in settings: {e:?}. Defaulting to 0.0.0.0 (DHCP)");
701 "0.0.0.0".parse().unwrap()
702 }
703 };
704
705 let random_seed = {
706 let mut rng =
707 device.RNG.constrain(ccdr.peripheral.RNG, &ccdr.clocks);
708 let mut data = [0u8; 8];
709 rng.fill(&mut data).unwrap();
710 data
711 };
712
713 let store =
716 cortex_m::singleton!(: NetStorage = NetStorage::default()).unwrap();
717
718 store.ip_addrs[0] = smoltcp::wire::IpCidr::new(ip_addrs, 24);
719
720 let mut ethernet_config = smoltcp::iface::Config::new(
721 smoltcp::wire::HardwareAddress::Ethernet(mac_addr),
722 );
723 ethernet_config.random_seed = u64::from_be_bytes(random_seed);
724
725 let mut interface = smoltcp::iface::Interface::new(
726 ethernet_config,
727 &mut eth_dma,
728 smoltcp::time::Instant::ZERO,
729 );
730
731 interface
732 .routes_mut()
733 .add_default_ipv4_route(smoltcp::wire::Ipv4Address::UNSPECIFIED)
734 .unwrap();
735
736 interface.update_ip_addrs(|ref mut addrs| {
737 if !ip_addrs.is_unspecified() {
738 addrs
739 .push(smoltcp::wire::IpCidr::new(ip_addrs, 24))
740 .unwrap();
741 }
742 });
743
744 let mut sockets =
745 smoltcp::iface::SocketSet::new(&mut store.sockets[..]);
746 for storage in store.tcp_socket_storage[..].iter_mut() {
747 let tcp_socket = {
748 let rx_buffer = smoltcp::socket::tcp::SocketBuffer::new(
749 &mut storage.rx_storage[..],
750 );
751 let tx_buffer = smoltcp::socket::tcp::SocketBuffer::new(
752 &mut storage.tx_storage[..],
753 );
754
755 smoltcp::socket::tcp::Socket::new(rx_buffer, tx_buffer)
756 };
757
758 sockets.add(tcp_socket);
759 }
760
761 if ip_addrs.is_unspecified() {
762 sockets.add(smoltcp::socket::dhcpv4::Socket::new());
763 }
764
765 sockets.add(smoltcp::socket::dns::Socket::new(
766 &[],
767 &mut store.dns_storage[..],
768 ));
769
770 for storage in store.udp_socket_storage[..].iter_mut() {
771 let udp_socket = {
772 let rx_buffer = smoltcp::socket::udp::PacketBuffer::new(
773 &mut storage.rx_metadata[..],
774 &mut storage.rx_storage[..],
775 );
776 let tx_buffer = smoltcp::socket::udp::PacketBuffer::new(
777 &mut storage.tx_metadata[..],
778 &mut storage.tx_storage[..],
779 );
780
781 smoltcp::socket::udp::Socket::new(rx_buffer, tx_buffer)
782 };
783
784 sockets.add(udp_socket);
785 }
786
787 let mut stack =
788 smoltcp_nal::NetworkStack::new(interface, eth_dma, sockets, clock);
789
790 stack.seed_random_port(&random_seed);
791
792 NetworkDevices {
793 stack,
794 phy: lan8742a,
795 mac_address: mac_addr,
796 }
797 };
798
799 let mut fp_led_0 = gpiod.pd5.into_push_pull_output();
800 let mut fp_led_1 = gpiod.pd6.into_push_pull_output();
801 let mut fp_led_2 = gpiog.pg4.into_push_pull_output();
802 let mut fp_led_3 = gpiod.pd12.into_push_pull_output();
803
804 fp_led_0.set_low();
805 fp_led_1.set_low();
806 fp_led_2.set_low();
807 fp_led_3.set_low();
808
809 let (adc1, adc2, adc3) = {
810 let (mut adc1, mut adc2) = hal::adc::adc12(
811 device.ADC1,
812 device.ADC2,
813 stm32h7xx_hal::time::Hertz::MHz(25),
814 &mut delay,
815 ccdr.peripheral.ADC12,
816 &ccdr.clocks,
817 );
818 let mut adc3 = hal::adc::Adc::adc3(
819 device.ADC3,
820 stm32h7xx_hal::time::Hertz::MHz(25),
821 &mut delay,
822 ccdr.peripheral.ADC3,
823 &ccdr.clocks,
824 );
825
826 adc1.set_sample_time(hal::adc::AdcSampleTime::T_810);
827 adc1.set_resolution(hal::adc::Resolution::SixteenBit);
828 adc1.calibrate();
829 adc2.set_sample_time(hal::adc::AdcSampleTime::T_810);
830 adc2.set_resolution(hal::adc::Resolution::SixteenBit);
831 adc2.calibrate();
832 adc3.set_sample_time(hal::adc::AdcSampleTime::T_810);
833 adc3.set_resolution(hal::adc::Resolution::SixteenBit);
834 adc3.calibrate();
835
836 hal::adc::Temperature::new().enable(&adc3);
837
838 let adc1 = adc1.enable();
839 let adc2 = adc2.enable();
840 let adc3 = adc3.enable();
841
842 (
843 cortex_m::singleton!(: SharedAdc<hal::stm32::ADC1> = SharedAdc::new(adc1.slope() as f32, adc1)).unwrap(),
849 cortex_m::singleton!(: SharedAdc<hal::stm32::ADC2> = SharedAdc::new(adc2.slope() as f32, adc2)).unwrap(),
850 cortex_m::singleton!(: SharedAdc<hal::stm32::ADC3> = SharedAdc::new(adc3.slope() as f32, adc3)).unwrap(),
851 )
852 };
853
854 let pounder_pgood = gpiob.pb13.into_pull_down_input();
856 delay.delay_ms(2u8);
857 let pounder = if pounder_pgood.is_high() {
858 log::info!("Found Pounder");
859
860 let i2c1 = {
861 let sda = gpiob.pb7.into_alternate().set_open_drain();
862 let scl = gpiob.pb8.into_alternate().set_open_drain();
863 let i2c1 = device.I2C1.i2c(
864 (scl, sda),
865 400.kHz(),
866 ccdr.peripheral.I2C1,
867 &ccdr.clocks,
868 );
869
870 shared_bus::new_atomic_check!(hal::i2c::I2c<hal::stm32::I2C1> = i2c1).unwrap()
871 };
872
873 let spi = {
874 let mosi = gpiod.pd7.into_alternate();
875 let miso = gpioa.pa6.into_alternate();
876 let sck = gpiog.pg11.into_alternate();
877
878 let config = hal::spi::Config::new(hal::spi::Mode {
879 polarity: hal::spi::Polarity::IdleHigh,
880 phase: hal::spi::Phase::CaptureOnSecondTransition,
881 });
882
883 device.SPI1.spi(
886 (sck, miso, mosi),
887 config,
888 5.MHz(),
889 ccdr.peripheral.SPI1,
890 &ccdr.clocks,
891 )
892 };
893
894 let pwr0 = adc1.create_channel(gpiof.pf11.into_analog());
895 let pwr1 = adc2.create_channel(gpiof.pf14.into_analog());
896 let aux_adc0 = adc3.create_channel(gpiof.pf3.into_analog());
897 let aux_adc1 = adc3.create_channel(gpiof.pf4.into_analog());
898
899 let pounder_devices = pounder::PounderDevices::new(
900 i2c1.acquire_i2c(),
901 spi,
902 (pwr0, pwr1),
903 (aux_adc0, aux_adc1),
904 )
905 .unwrap();
906
907 let ad9959 = {
908 let qspi_interface = {
909 let qspi_pins = {
911 let _ncs =
912 gpioc.pc11.into_alternate::<9>().speed(Speed::VeryHigh);
913
914 let clk = gpiob.pb2.into_alternate().speed(Speed::VeryHigh);
915 let io0 = gpioe.pe7.into_alternate().speed(Speed::VeryHigh);
916 let io1 = gpioe.pe8.into_alternate().speed(Speed::VeryHigh);
917 let io2 = gpioe.pe9.into_alternate().speed(Speed::VeryHigh);
918 let io3 =
919 gpioe.pe10.into_alternate().speed(Speed::VeryHigh);
920
921 (clk, io0, io1, io2, io3)
922 };
923
924 let qspi = device.QUADSPI.bank2(
925 qspi_pins,
926 design_parameters::POUNDER_QSPI_FREQUENCY.convert(),
927 &ccdr.clocks,
928 ccdr.peripheral.QSPI,
929 );
930
931 pounder::QspiInterface::new(qspi).unwrap()
932 };
933
934 #[cfg(not(feature = "pounder_v1_0"))]
935 let reset_pin = gpiog.pg6.into_push_pull_output();
936 #[cfg(feature = "pounder_v1_0")]
937 let reset_pin = gpioa.pa0.into_push_pull_output();
938
939 let mut io_update = gpiog.pg7.into_push_pull_output();
940
941 delay.delay_ms(10u32);
946
947 let mut ad9959 = ad9959::Ad9959::new(
948 qspi_interface,
949 reset_pin,
950 &mut io_update,
951 &mut delay,
952 ad9959::Mode::FourBitSerial,
953 design_parameters::DDS_REF_CLK.to_Hz() as f32,
954 design_parameters::DDS_MULTIPLIER,
955 )
956 .unwrap();
957
958 ad9959.self_test().unwrap();
959
960 gpiog.pg7 = io_update.into_analog();
962
963 ad9959
964 };
965
966 let dds_output = {
967 let io_update_trigger = {
968 let _io_update =
969 gpiog.pg7.into_alternate::<2>().speed(Speed::VeryHigh);
970
971 let mut hrtimer = pounder::hrtimer::HighResTimerE::new(
973 device.HRTIM_TIME,
974 device.HRTIM_MASTER,
975 device.HRTIM_COMMON,
976 ccdr.clocks,
977 ccdr.peripheral.HRTIM,
978 );
979
980 hrtimer.configure_single_shot(
984 pounder::hrtimer::Channel::Two,
985 design_parameters::POUNDER_IO_UPDATE_DELAY,
986 design_parameters::POUNDER_IO_UPDATE_DURATION,
987 );
988
989 let sample_frequency = {
991 design_parameters::TIMER_FREQUENCY.to_Hz() as f32
992 / sample_ticks as f32
993 };
994
995 let sample_period = 1.0 / sample_frequency;
996 assert!(
997 sample_period * batch_size as f32
998 > design_parameters::POUNDER_IO_UPDATE_DELAY
999 );
1000
1001 hrtimer
1002 };
1003
1004 let (qspi, config) = ad9959.freeze();
1005 DdsOutput::new(qspi, io_update_trigger, config)
1006 };
1007
1008 #[cfg(not(feature = "pounder_v1_0"))]
1009 let pounder_stamper = {
1010 log::info!("Assuming Pounder v1.1 or later");
1011 let etr_pin = gpioa.pa0.into_alternate();
1012
1013 let tim8 =
1016 device
1017 .TIM8
1018 .timer(1.kHz(), ccdr.peripheral.TIM8, &ccdr.clocks);
1019 let mut timestamp_timer = timers::PounderTimestampTimer::new(tim8);
1020
1021 timestamp_timer.set_external_clock(timers::Prescaler::Div4);
1026 timestamp_timer.start();
1027
1028 timestamp_timer.set_period_ticks(u16::MAX);
1031 let tim8_channels = timestamp_timer.channels();
1032
1033 pounder::timestamp::Timestamper::new(
1034 timestamp_timer,
1035 tim8_channels.ch1,
1036 &mut sampling_timer,
1037 etr_pin,
1038 batch_size,
1039 )
1040 };
1041
1042 Some(PounderDevices {
1043 pounder: pounder_devices,
1044 dds_output,
1045
1046 #[cfg(not(feature = "pounder_v1_0"))]
1047 timestamper: pounder_stamper,
1048 })
1049 } else {
1050 None
1051 };
1052
1053 #[derive(Copy, Clone, Debug, PartialEq)]
1054 pub enum PoePower {
1055 Absent,
1057 Low,
1059 High,
1061 }
1062
1063 let poe_src_status = gpiob.pb6.into_floating_input();
1064 let poe_at_event = gpioc.pc14.into_floating_input();
1065 let poe = match (poe_src_status.is_high(), poe_at_event.is_high()) {
1066 (false, _) => PoePower::Absent,
1067 (true, false) => PoePower::Low,
1068 (true, true) => PoePower::High,
1069 };
1070 log::info!("PoE: {poe:?}",);
1071
1072 let mut force_eem_source = gpioe.pe0.into_push_pull_output();
1073
1074 fn check_input<const P: char, const N: u8>(
1076 pin: hal::gpio::Pin<P, N, hal::gpio::Analog>,
1077 mut is_floating: bool,
1078 delay: &mut AsmDelay,
1079 ) -> (hal::gpio::Pin<P, N, hal::gpio::Analog>, bool) {
1080 let pin = pin.into_pull_up_input();
1081 delay.delay_ms(1u8);
1082 is_floating &= pin.is_high();
1083 let pin = pin.into_pull_down_input();
1084 delay.delay_ms(1u8);
1085 is_floating &= pin.is_low();
1086 (pin.into_analog(), is_floating)
1087 }
1088
1089 let mut lvds0 = gpiog.pg13;
1090 let mut lvds1 = gpiob.pb5;
1091 let mut lvds3 = gpiog.pg8;
1092 let mut is_floating = true;
1093 (lvds0, is_floating) = check_input(lvds0, is_floating, &mut delay);
1095 (lvds1, is_floating) = check_input(lvds1, is_floating, &mut delay);
1096 (lvds3, is_floating) = check_input(lvds3, is_floating, &mut delay);
1097 let eem = if !is_floating {
1098 log::info!("EEM population variant: Default detected");
1099 force_eem_source.set_low();
1100 Eem::Gpio(Gpio {
1101 lvds4: gpiod.pd1.into_floating_input(),
1102 lvds5: gpiod.pd2.into_floating_input(),
1103 lvds6: gpiod.pd3.into_push_pull_output(),
1104 lvds7: gpiod.pd4.into_push_pull_output(),
1105 })
1106 } else {
1107 log::info!("EEM population variant: Output detected");
1108 assert!(poe != PoePower::Low);
1109 force_eem_source.set_high();
1110 delay.delay_ms(200u8);
1111
1112 let spi = device
1113 .SPI6
1114 .spi(
1115 (
1116 lvds0.into_alternate(), gpiog.pg12.into_alternate(), lvds1.into_alternate(), ),
1120 hal::spi::MODE_0,
1121 20.MHz(),
1122 ccdr.peripheral.SPI6,
1123 &ccdr.clocks,
1124 )
1125 .forward();
1126 let spi = cortex_m::singleton!(:
1127 RefCell<Forward<hal::spi::Spi<hal::stm32::SPI6, hal::spi::Enabled>>> =
1128 RefCell::new(spi)).unwrap();
1129
1130 let cs = [
1131 lvds3.into_push_pull_output().erase().forward(),
1132 gpiod.pd1.into_push_pull_output().erase().forward(),
1133 gpiod.pd2.into_push_pull_output().erase().forward(),
1134 ];
1135 let cs = cortex_m::singleton!(:
1136 RefCell<[Forward<hal::gpio::ErasedPin<hal::gpio::Output>, ForwardOutputPin>; 3]> =
1137 RefCell::new(cs)
1138 )
1139 .unwrap();
1140
1141 match urukul::Urukul::new(
1142 spi,
1143 cs,
1144 gpiod.pd3.into_push_pull_output().erase().forward(),
1145 gpiod.pd4.into_push_pull_output().erase().forward(),
1146 ) {
1147 Ok(urukul) => Eem::Urukul(urukul),
1148 Err(err) => {
1149 log::warn!("Urukul initialization failed: {err:?}");
1150 Eem::None
1151 }
1152 }
1153 };
1154
1155 let (usb_device, usb_serial) = {
1156 let _usb_id = gpioa.pa10.into_alternate::<10>();
1157 let usb_n = gpioa.pa11.into_alternate();
1158 let usb_p = gpioa.pa12.into_alternate();
1159 let usb = stm32h7xx_hal::usb_hs::USB2::new(
1160 device.OTG2_HS_GLOBAL,
1161 device.OTG2_HS_DEVICE,
1162 device.OTG2_HS_PWRCLK,
1163 usb_n,
1164 usb_p,
1165 ccdr.peripheral.USB2OTG,
1166 &ccdr.clocks,
1167 );
1168
1169 let endpoint_memory =
1170 cortex_m::singleton!(: Option<&'static mut [u32]> = None).unwrap();
1171 endpoint_memory.replace(
1172 &mut cortex_m::singleton!(: [u32; 1024] = [0; 1024]).unwrap()[..],
1173 );
1174 let usb_bus = cortex_m::singleton!(: usb_device::bus::UsbBusAllocator<super::UsbBus> =
1175 stm32h7xx_hal::usb_hs::UsbBus::new(
1176 usb,
1177 endpoint_memory.take().unwrap(),
1178 ))
1179 .unwrap();
1180
1181 let read_store = cortex_m::singleton!(: [u8; 128] = [0; 128]).unwrap();
1182 let write_store =
1183 cortex_m::singleton!(: [u8; 1024] = [0; 1024]).unwrap();
1184 let serial = usbd_serial::SerialPort::new_with_store(
1185 usb_bus,
1186 &mut read_store[..],
1187 &mut write_store[..],
1188 );
1189
1190 let serial_number = cortex_m::singleton!(: String<17> = {
1192 let mut s = String::new();
1193 write!(s, "{mac_addr}").unwrap();
1194 s
1195 })
1196 .unwrap();
1197
1198 let usb_device = usb_device::device::UsbDeviceBuilder::new(
1199 usb_bus,
1200 usb_device::device::UsbVidPid(0x1209, 0x392F),
1201 )
1202 .strings(&[usb_device::device::StringDescriptors::default()
1203 .manufacturer("ARTIQ/Sinara")
1204 .product("Stabilizer")
1205 .serial_number(serial_number)])
1206 .unwrap()
1207 .device_class(usbd_serial::USB_CLASS_CDC)
1208 .build();
1209
1210 (usb_device, serial)
1211 };
1212
1213 let usb_terminal = {
1214 let input_buffer =
1215 cortex_m::singleton!(: [u8; 128] = [0u8; 128]).unwrap();
1216 let serialize_buffer =
1217 cortex_m::singleton!(: [u8; 512] = [0u8; 512]).unwrap();
1218
1219 serial_settings::Runner::new(
1220 crate::settings::SerialSettingsPlatform {
1221 interface: serial_settings::BestEffortInterface::new(
1222 usb_serial,
1223 ),
1224 storage: flash,
1225 metadata,
1226 _settings_marker: core::marker::PhantomData,
1227 },
1228 input_buffer,
1229 serialize_buffer,
1230 &mut settings,
1231 )
1232 .unwrap()
1233 };
1234
1235 let stabilizer = StabilizerDevices {
1236 afes,
1237 adcs,
1238 dacs,
1239 temperature_sensor: CpuTempSensor::new(
1240 adc3.create_channel(hal::adc::Temperature::new()),
1241 ),
1242 usb_serial: usb_terminal,
1243 timestamper: input_stamper,
1244 net: network_devices,
1245 adc_dac_timer: sampling_timer,
1246 timestamp_timer,
1247 digital_inputs,
1248 eem,
1249 usb: usb_device,
1250 metadata,
1251 settings,
1252 };
1253
1254 log::info!("setup() complete");
1258
1259 (stabilizer, pounder)
1260}