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