Skip to content

Commit 0d93d88

Browse files
committed
feat: Adding back the usb light example
1 parent 5e61bbb commit 0d93d88

File tree

2 files changed

+169
-0
lines changed

2 files changed

+169
-0
lines changed

boards/grand_central_m4/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,7 @@ name = "neopixel_rainbow"
5959
[[example]]
6060
name = "usb_serial"
6161
required-features = ["usb"]
62+
63+
[[example]]
64+
name = "usb_light"
65+
required-features = ["usb"]
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
//! Makes the grand_central_m4 appear as a USB serial port. The color of the
5+
//! neopixel LED can be changed by sending bytes to the serial port.
6+
//!
7+
//! Sending the characters R, G, and O set the LED red, green, and off
8+
//! respectively. For example:
9+
//! $> sudo stty -F /dev/ttyACM0 115200 raw -echo
10+
//! $> sudo bash -c "echo 'R' > /dev/ttyACM0"
11+
//! $> sudo bash -c "echo 'G' > /dev/ttyACM0"
12+
//! $> sudo bash -c "echo 'O' > /dev/ttyACM0"
13+
//!
14+
//! Note leds may appear white during debug. Either build for release or add
15+
//! opt-level = 2 to profile.dev in Cargo.toml
16+
17+
use grand_central_m4 as bsp;
18+
19+
use bsp::hal;
20+
21+
#[cfg(not(feature = "use_semihosting"))]
22+
use panic_halt as _;
23+
#[cfg(feature = "use_semihosting")]
24+
use panic_semihosting as _;
25+
26+
use bsp::entry;
27+
use cortex_m::interrupt::free as disable_interrupts;
28+
use cortex_m::peripheral::NVIC;
29+
use hal::clock::v2::{
30+
clock_system_at_reset, dfll,
31+
gclk::{Gclk, Gclk1Id},
32+
pclk::Pclk,
33+
};
34+
use hal::pac::{interrupt, CorePeripherals, Peripherals};
35+
use hal::prelude::*;
36+
use hal::time::Hertz;
37+
use hal::timer::TimerCounter;
38+
use hal::usb::UsbBus;
39+
use smart_leds::{colors, hsv::RGB8, SmartLedsWrite};
40+
use usb_device::bus::UsbBusAllocator;
41+
use usb_device::prelude::*;
42+
use usbd_serial::{SerialPort, USB_CLASS_CDC};
43+
use ws2812_timer_delay as ws2812;
44+
45+
#[entry]
46+
fn main() -> ! {
47+
let mut peripherals = Peripherals::take().unwrap();
48+
let mut core = CorePeripherals::take().unwrap();
49+
let (mut buses, clocks, tokens) = clock_system_at_reset(
50+
peripherals.oscctrl,
51+
peripherals.osc32kctrl,
52+
peripherals.gclk,
53+
peripherals.mclk,
54+
&mut peripherals.nvmctrl,
55+
);
56+
let mut mclk = unsafe { clocks.pac.steal().3 }; // THIS IS ONLY TEMPORARY
57+
58+
let (tc2_3, _gclk0) = Pclk::enable(tokens.pclks.tc2_tc3, clocks.gclk0);
59+
let mut timer = TimerCounter::tc3_(&tc2_3.into(), peripherals.tc3, &mut mclk);
60+
InterruptDrivenTimer::start(&mut timer, Hertz::MHz(3).into_duration());
61+
62+
let pins = bsp::Pins::new(peripherals.port);
63+
let neopixel_pin = pins.neopixel.into_push_pull_output();
64+
let mut neopixel = ws2812::Ws2812::new(timer, neopixel_pin);
65+
let _ = neopixel.write((0..5).map(|_| RGB8::default()));
66+
67+
// Set up USB clocking
68+
let (dfll_usb, _) = clocks.dfll.into_mode(dfll::FromUsb, |_| {});
69+
// GCLK1 comes from DFLL, outputs to USB
70+
let (gclk_1, _) = Gclk::from_source(tokens.gclks.gclk1, dfll_usb);
71+
let gclk_1_48mhz = gclk_1.enable();
72+
let (pclk_usb, _) = Pclk::enable(tokens.pclks.usb, gclk_1_48mhz);
73+
74+
let usb_bus = UsbBus::new(
75+
pclk_usb,
76+
clocks.ahbs.usb,
77+
buses.apb.enable(tokens.apbs.usb),
78+
pins.usb_dm,
79+
pins.usb_dp,
80+
peripherals.usb,
81+
)
82+
.unwrap();
83+
let bus_allocator = unsafe {
84+
USB_ALLOCATOR = Some(UsbBusAllocator::new(usb_bus));
85+
USB_ALLOCATOR.as_ref().unwrap()
86+
};
87+
88+
unsafe {
89+
USB_SERIAL = Some(SerialPort::new(bus_allocator));
90+
USB_BUS = Some(
91+
UsbDeviceBuilder::new(bus_allocator, UsbVidPid(0x1209, 0x0001))
92+
.strings(&[StringDescriptors::new(LangID::EN_US)
93+
.manufacturer("Fake company")
94+
.product("Serial port")
95+
.serial_number("TEST")])
96+
.expect("Failed to set strings")
97+
.device_class(USB_CLASS_CDC)
98+
.build(),
99+
);
100+
}
101+
102+
unsafe {
103+
core.NVIC.set_priority(interrupt::USB_TRCPT0, 1);
104+
NVIC::unmask(interrupt::USB_TRCPT0);
105+
core.NVIC.set_priority(interrupt::USB_TRCPT1, 1);
106+
NVIC::unmask(interrupt::USB_TRCPT1);
107+
core.NVIC.set_priority(interrupt::USB_OTHER, 1);
108+
NVIC::unmask(interrupt::USB_OTHER);
109+
}
110+
111+
loop {
112+
let pending = disable_interrupts(|_| unsafe {
113+
let pending = PENDING_COLOR;
114+
PENDING_COLOR = None;
115+
pending
116+
});
117+
if let Some(color) = pending {
118+
let _ = neopixel.write((0..5).map(|_| color));
119+
}
120+
}
121+
}
122+
123+
static mut USB_ALLOCATOR: Option<UsbBusAllocator<UsbBus<Gclk1Id>>> = None;
124+
static mut USB_BUS: Option<UsbDevice<UsbBus<Gclk1Id>>> = None;
125+
static mut USB_SERIAL: Option<SerialPort<UsbBus<Gclk1Id>>> = None;
126+
static mut PENDING_COLOR: Option<RGB8> = None;
127+
128+
fn poll_usb() {
129+
unsafe {
130+
USB_BUS.as_mut().map(|usb_dev| {
131+
USB_SERIAL.as_mut().map(|serial| {
132+
usb_dev.poll(&mut [serial]);
133+
134+
let mut buf = [0u8; 64];
135+
136+
if let Ok(count) = serial.read(&mut buf) {
137+
let last = buf[count - 1] as char;
138+
let color = match last {
139+
'R' => colors::RED,
140+
'G' => colors::GREEN,
141+
'O' => colors::ORANGE,
142+
_ => RGB8::default(),
143+
};
144+
145+
PENDING_COLOR = Some(color);
146+
};
147+
});
148+
});
149+
};
150+
}
151+
152+
#[interrupt]
153+
fn USB_OTHER() {
154+
poll_usb();
155+
}
156+
157+
#[interrupt]
158+
fn USB_TRCPT0() {
159+
poll_usb();
160+
}
161+
162+
#[interrupt]
163+
fn USB_TRCPT1() {
164+
poll_usb();
165+
}

0 commit comments

Comments
 (0)