Serge Bazanski | 8198136 | 2021-03-06 13:08:00 +0100 | [diff] [blame] | 1 | #![no_main] |
| 2 | #![no_std] |
| 3 | |
| 4 | extern crate panic_semihosting; |
| 5 | |
| 6 | use rtic::app; |
| 7 | |
| 8 | use cortex_m::asm::delay; |
| 9 | use stm32f1xx_hal::{ |
| 10 | gpio::{gpioc::*, Output, PushPull}, |
| 11 | i2c::{BlockingI2c, Mode}, |
| 12 | pac::{Peripherals}, |
| 13 | prelude::*, |
| 14 | usb::{Peripheral, UsbBus, UsbBusType}, |
| 15 | }; |
| 16 | use embedded_hal::digital::v2::OutputPin; |
| 17 | |
| 18 | use usb_device::bus; |
| 19 | use usb_device::prelude::*; |
| 20 | |
| 21 | use usbd_webusb::WebUsb; |
| 22 | |
| 23 | mod i2c; |
| 24 | mod 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)] |
| 29 | const 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 | |