blob: 45279c2960fee54080c9985078f9baf2e8158aa2 [file] [log] [blame]
Serge Bazanski81981362021-03-06 13:08:00 +01001#![no_main]
2#![no_std]
3
4extern crate panic_semihosting;
5
6use rtic::app;
7
8use cortex_m::asm::delay;
9use stm32f1xx_hal::{
10 gpio::{gpioc::*, Output, PushPull},
11 i2c::{BlockingI2c, Mode},
12 pac::{Peripherals},
13 prelude::*,
14 usb::{Peripheral, UsbBus, UsbBusType},
15};
16use embedded_hal::digital::v2::OutputPin;
17
18use usb_device::bus;
19use usb_device::prelude::*;
20
21use usbd_webusb::WebUsb;
22
23mod i2c;
24mod print;
25
Serge Bazanskic8b14e72021-03-27 11:52:44 +000026// The main RTIC application object. See RTIC documentation for more information about how to read
27// this.
28
Serge Bazanski81981362021-03-06 13:08:00 +010029#[app(device = stm32f1xx_hal::stm32, peripherals = true)]
30const APP: () = {
31 struct Resources {
32 usb_dev: UsbDevice<'static, UsbBusType>,
33 webusb: WebUsb<UsbBusType>,
34 // The I2C USB device class that performs the main logic of accessing the I2C bus over USB
35 // for users of the device.
36 i2c: i2c::I2CClass<'static, UsbBusType, PC13<Output<PushPull>>>,
37 }
38
39 /// Idle loop to prevent WFI which in turn prevents debugging.
40 // TODO: make this only happen on debug builds?
41 #[idle]
42 fn idle(_: idle::Context) -> ! {
43 loop {}
44 }
45
46 #[init]
47 fn init(cx: init::Context) -> init::LateResources {
48 static mut USB_BUS: Option<bus::UsbBusAllocator<UsbBusType>> = None;
49
50 let mut flash = cx.device.FLASH.constrain();
51 let mut rcc = cx.device.RCC.constrain();
52
53 let clocks = rcc
54 .cfgr
55 .use_hse(8.mhz())
56 .sysclk(48.mhz())
57 .pclk1(24.mhz())
58 .freeze(&mut flash.acr);
59
60 assert!(clocks.usbclk_valid());
61
62 let mut gpioa = cx.device.GPIOA.split(&mut rcc.apb2);
63 let mut gpiob = cx.device.GPIOB.split(&mut rcc.apb2);
64 let mut gpioc = cx.device.GPIOC.split(&mut rcc.apb2);
65
66 // Active-low LED on bluepill board.
67 let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
68 led.set_high().ok();
69
70 let mut afio = cx.device.AFIO.constrain(&mut rcc.apb2);
71
72 // BluePill board has a pull-up resistor on the D+ line.
73 // Pull the D+ pin down to send a RESET condition to the USB bus.
74 // This forced reset is needed only for development, without it host
75 // will not reset your device when you upload new firmware.
76 let mut usb_dp = gpioa.pa12.into_push_pull_output(&mut gpioa.crh);
77 usb_dp.set_low().unwrap();
78 delay(clocks.sysclk().0 / 100);
79
80 let usb_dm = gpioa.pa11;
81 let usb_dp = usb_dp.into_floating_input(&mut gpioa.crh);
82
83 let usb = Peripheral {
84 usb: cx.device.USB,
85 pin_dm: usb_dm,
86 pin_dp: usb_dp,
87 };
88
89 *USB_BUS = Some(UsbBus::new(usb));
90
91 let i2c_pins = (
92 gpiob.pb6.into_alternate_open_drain(&mut gpiob.crl),
93 gpiob.pb7.into_alternate_open_drain(&mut gpiob.crl),
94 );
95
96 // Blocking I2C peripheral for use by the I2C app.
97 let i2c_dev = BlockingI2c::i2c1(
98 cx.device.I2C1,
99 i2c_pins,
100 &mut afio.mapr,
101 Mode::standard(100.khz()),
102 clocks,
103 &mut rcc.apb1,
104 1000, 10, 1000, 1000,
105 );
106
107 // I2C app.
108 let i2c = i2c::I2CClass::new(
109 USB_BUS.as_ref().unwrap(),
110 led, i2c_dev,
111 );
112
113 let usb_dev = UsbDeviceBuilder::new(USB_BUS.as_ref().unwrap(), UsbVidPid(0x16c0, 0x27d8))
114 .manufacturer("Warsaw Hackerspace")
115 .product("Web I2C Programmer")
116 // TODO(q3k): generate serial at build time?
117 .serial_number("2137")
118 .build();
119
120 init::LateResources {
121 usb_dev, i2c,
122 webusb: WebUsb::new(
123 USB_BUS.as_ref().unwrap(),
124 usbd_webusb::url_scheme::HTTPS,
125 "hackdoc.hackerspace.pl/dc/hbj11/flasher",
126 ),
127 }
128 }
129
130 #[task(binds = USB_LP_CAN_RX0, resources = [usb_dev, webusb, i2c])]
131 fn usb_lp(cx: usb_lp::Context) {
132 cx.resources
133 .usb_dev
134 .poll(&mut [cx.resources.webusb, cx.resources.i2c]);
135 }
136};
137