mirror of
https://github.com/ferrous-systems/embedded-trainings-2020.git
synced 2025-01-24 06:48:11 +00:00
- dk: API docs
- advanced: adapt to changes in usb2 dependency - dk: add reminder to connect the USB cable to port J3
This commit is contained in:
parent
e212e819b9
commit
31c331c1a3
8 changed files with 99 additions and 55 deletions
26
advanced/firmware/Cargo.lock
generated
26
advanced/firmware/Cargo.lock
generated
|
@ -60,7 +60,7 @@ version = "0.1.0"
|
|||
[[package]]
|
||||
name = "cortex-m"
|
||||
version = "0.6.2"
|
||||
source = "git+https://github.com/rust-embedded/cortex-m#3136e01e708413774d7be2868705e1782c910027"
|
||||
source = "git+https://github.com/rust-embedded/cortex-m#c9c7539233954822a6132f4bc13e5763371b5cb2"
|
||||
dependencies = [
|
||||
"bare-metal",
|
||||
"bitfield",
|
||||
|
@ -118,6 +118,7 @@ name = "dk"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"embedded-hal",
|
||||
"log",
|
||||
"nrf52840-hal",
|
||||
|
@ -143,6 +144,7 @@ dependencies = [
|
|||
"cortex-m-rt",
|
||||
"cortex-m-rtfm",
|
||||
"dk",
|
||||
"heapless",
|
||||
"log",
|
||||
"panic-log",
|
||||
"quote",
|
||||
|
@ -201,9 +203,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.3.2"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292"
|
||||
checksum = "c398b2b113b55809ceb9ee3e753fcbac793f1956663f3c36549c1346015c2afe"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
@ -226,7 +228,7 @@ checksum = "b1411551beb3c11dedfb0a90a0fa256b47d28b9ec2cdff34c25a2fa59e45dbdc"
|
|||
[[package]]
|
||||
name = "nrf-hal-common"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/japaric/nrf-hal?branch=radio#443662d20591c3bef26a4fff2de03de90fec51aa"
|
||||
source = "git+https://github.com/japaric/nrf-hal?branch=radio#d624e80e5724e4709081ed65abaf63271fe1eca7"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"cortex-m",
|
||||
|
@ -241,7 +243,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "nrf52840-hal"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/japaric/nrf-hal?branch=radio#443662d20591c3bef26a4fff2de03de90fec51aa"
|
||||
source = "git+https://github.com/japaric/nrf-hal?branch=radio#d624e80e5724e4709081ed65abaf63271fe1eca7"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"cortex-m",
|
||||
|
@ -274,18 +276,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.17"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1502d12e458c49a4c9cbff560d0fe0060c252bc29799ed94ca2ed4bb665a0101"
|
||||
checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.6"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea"
|
||||
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -362,9 +364,9 @@ checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.25"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f14a640819f79b72a710c0be059dce779f9339ae046c8bef12c361d56702146f"
|
||||
checksum = "93a56fabc59dce20fe48b6c832cc249c713e7ed88fa28b0ee0a3bfcaae5fe4e2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -396,7 +398,7 @@ version = "0.1.0"
|
|||
[[package]]
|
||||
name = "usb2"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/japaric/usb2#c2b8118e667026f690c847782ebc5809aba749fe"
|
||||
source = "git+https://github.com/japaric/usb2#6a8c4b1ed0db005dcf19694684524b33cc04abd2"
|
||||
|
||||
[[package]]
|
||||
name = "vcell"
|
||||
|
|
|
@ -16,6 +16,7 @@ cortex-m-rt = "0.6.12"
|
|||
# TODO switch to RTIC before public release
|
||||
cortex-m-rtfm = "0.5.1"
|
||||
dk = { path = "../../boards/dk" }
|
||||
heapless = "0.5.5"
|
||||
log = "0.4.8"
|
||||
panic-log = { path = "../../common/panic-log" }
|
||||
usb = { path = "../common/usb" }
|
||||
|
|
|
@ -16,15 +16,10 @@ const APP: () = {
|
|||
struct Resources {
|
||||
usbd: USBD,
|
||||
ep0in: Ep0In,
|
||||
#[init([0; 64])]
|
||||
buffer: [u8; 64],
|
||||
}
|
||||
|
||||
#[init(resources = [buffer])]
|
||||
fn init(cx: init::Context) -> init::LateResources {
|
||||
let buffer: &'static mut [u8; 64] = cx.resources.buffer;
|
||||
let ep0in = Ep0In::new(buffer);
|
||||
|
||||
#[init]
|
||||
fn init(_cx: init::Context) -> init::LateResources {
|
||||
let board = dk::init().unwrap();
|
||||
|
||||
usbd::init(board.power, &board.usbd);
|
||||
|
@ -32,8 +27,8 @@ const APP: () = {
|
|||
usbd::connect(&board.usbd);
|
||||
|
||||
init::LateResources {
|
||||
ep0in: board.ep0in,
|
||||
usbd: board.usbd,
|
||||
ep0in,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,18 +15,13 @@ use usb2::{GetDescriptor as Descriptor, StandardRequest as Request}; // crates.i
|
|||
#[rtfm::app(device = dk)]
|
||||
const APP: () = {
|
||||
struct Resources {
|
||||
#[init([0; 64])]
|
||||
buffer: [u8; 64],
|
||||
usbd: USBD,
|
||||
ep0in: Ep0In,
|
||||
state: State,
|
||||
}
|
||||
|
||||
#[init(resources = [buffer])]
|
||||
fn init(cx: init::Context) -> init::LateResources {
|
||||
let buffer: &'static mut [u8; 64] = cx.resources.buffer;
|
||||
let ep0in = Ep0In::new(buffer);
|
||||
|
||||
#[init]
|
||||
fn init(_cx: init::Context) -> init::LateResources {
|
||||
let board = dk::init().unwrap();
|
||||
|
||||
usbd::init(board.power, &board.usbd);
|
||||
|
@ -36,7 +31,7 @@ const APP: () = {
|
|||
init::LateResources {
|
||||
usbd: board.usbd,
|
||||
state: State::Default,
|
||||
ep0in,
|
||||
ep0in: board.ep0in,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,7 +67,7 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) {
|
|||
}
|
||||
}
|
||||
|
||||
fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> {
|
||||
fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, _state: &mut State) -> Result<(), ()> {
|
||||
let bmrequesttype = usbd.bmrequesttype.read().bits() as u8;
|
||||
let brequest = usbd.brequest.read().brequest().bits();
|
||||
let wlength = usbd::wlength(usbd);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use core::num::NonZeroU8;
|
||||
|
||||
use dk::{
|
||||
peripheral::USBD,
|
||||
usbd::{self, Ep0In, Event},
|
||||
|
@ -18,10 +20,7 @@ const APP: () = {
|
|||
|
||||
#[init]
|
||||
fn init(_cx: init::Context) -> init::LateResources {
|
||||
static mut BUFFER: [u8; 64] = [0; 64];
|
||||
|
||||
let board = dk::init().unwrap();
|
||||
let ep0in = Ep0In::new(BUFFER);
|
||||
|
||||
usbd::init(board.power, &board.usbd);
|
||||
|
||||
|
@ -30,7 +29,7 @@ const APP: () = {
|
|||
init::LateResources {
|
||||
usbd: board.usbd,
|
||||
state: State::Default,
|
||||
ep0in,
|
||||
ep0in: board.ep0in,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,9 +105,11 @@ fn ep0setup(usbd: &USBD, state: &mut State, ep0in: &mut Ep0In) -> Result<(), ()>
|
|||
|
||||
GetDescriptor::Configuration { index } => {
|
||||
if index == 0 {
|
||||
let desc = usb2::configuration::Descriptor {
|
||||
let mut full_desc = heapless::Vec::<u8, heapless::consts::U64>::new();
|
||||
|
||||
let conf_desc = usb2::configuration::Descriptor {
|
||||
wTotalLength: usb2::configuration::Descriptor::SIZE.into(),
|
||||
bNumInterfaces: 0,
|
||||
bNumInterfaces: NonZeroU8::new(1).unwrap(),
|
||||
bConfigurationValue: core::num::NonZeroU8::new(CONFIG_VAL).unwrap(),
|
||||
iConfiguration: None,
|
||||
bmAttributes: usb2::configuration::bmAttributes {
|
||||
|
@ -118,8 +119,22 @@ fn ep0setup(usbd: &USBD, state: &mut State, ep0in: &mut Ep0In) -> Result<(), ()>
|
|||
bMaxPower: 250, // 500 mA
|
||||
};
|
||||
|
||||
let bytes = desc.bytes();
|
||||
ep0in.start(&bytes[..core::cmp::min(bytes.len(), length.into())], usbd)?;
|
||||
let iface_desc = usb2::interface::Descriptor {
|
||||
bInterfaceNumber: 0,
|
||||
bAlternativeSetting: 0,
|
||||
bNumEndpoints: 0,
|
||||
bInterfaceClass: 0,
|
||||
bInterfaceSubClass: 0,
|
||||
bInterfaceProtocol: 0,
|
||||
iInterface: None,
|
||||
};
|
||||
|
||||
full_desc.extend_from_slice(&conf_desc.bytes()).unwrap();
|
||||
full_desc.extend_from_slice(&iface_desc.bytes()).unwrap();
|
||||
ep0in.start(
|
||||
&full_desc[..core::cmp::min(full_desc.len(), length.into())],
|
||||
usbd,
|
||||
)?;
|
||||
} else {
|
||||
// out of bounds access: stall the endpoint
|
||||
return Err(());
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
//! Hardware Abstraction Layer (HAL) for the nRF52840 Development Kit
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![deny(warnings)]
|
||||
#![no_std]
|
||||
|
||||
use core::{
|
||||
|
@ -21,7 +23,10 @@ use hal::{
|
|||
use log::{LevelFilter, Log};
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
|
||||
use crate::peripheral::{POWER, USBD};
|
||||
use crate::{
|
||||
peripheral::{POWER, USBD},
|
||||
usbd::Ep0In,
|
||||
};
|
||||
|
||||
mod errata;
|
||||
pub mod peripheral;
|
||||
|
@ -29,13 +34,20 @@ pub mod usbd;
|
|||
|
||||
/// Components on the board
|
||||
pub struct Board {
|
||||
/// LEDs
|
||||
pub leds: Leds,
|
||||
/// Radio interface
|
||||
// TODO put behind feature flag (off in advanced workshop)
|
||||
pub radio: Radio<'static>,
|
||||
/// Timer
|
||||
pub timer: Timer,
|
||||
/// USBD (Universal Serial Bus Device) peripheral
|
||||
// TODO put behind feature flag (off in beginner workshop)
|
||||
pub usbd: USBD,
|
||||
/// POWER (Power Supply) peripheral
|
||||
pub power: POWER,
|
||||
/// USB control endpoint 0
|
||||
pub ep0in: Ep0In,
|
||||
}
|
||||
|
||||
/// All LEDs on the board
|
||||
|
@ -149,7 +161,8 @@ pub fn init() -> Result<Board, ()> {
|
|||
cortex_m::Peripherals::take(),
|
||||
hal::target::Peripherals::take(),
|
||||
) {
|
||||
// NOTE(unsafe) this branch runs at most once
|
||||
// NOTE(static mut) this branch runs at most once
|
||||
static mut EP0IN_BUF: [u8; 64] = [0; 64];
|
||||
static mut CLOCKS: Option<Clocks<ExternalOscillator, ExternalOscillator, LfOscStarted>> =
|
||||
None;
|
||||
|
||||
|
@ -210,6 +223,7 @@ pub fn init() -> Result<Board, ()> {
|
|||
timer: Timer { inner: timer },
|
||||
usbd: periph.USBD,
|
||||
power: periph.POWER,
|
||||
ep0in: unsafe { Ep0In::new(&mut EP0IN_BUF) },
|
||||
})
|
||||
} else {
|
||||
Err(())
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
//! Low level access to the nRF52840 peripheral
|
||||
|
||||
pub use hal::target::{POWER, USBD};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use core::sync::atomic::{self, Ordering};
|
||||
//! USBD peripheral
|
||||
|
||||
use cortex_m::asm;
|
||||
use core::sync::atomic::{self, Ordering};
|
||||
|
||||
use crate::{
|
||||
errata,
|
||||
|
@ -14,17 +14,23 @@ pub struct Ep0In {
|
|||
}
|
||||
|
||||
impl Ep0In {
|
||||
pub fn new(buffer: &'static mut [u8; 64]) -> Self {
|
||||
/// # Safety
|
||||
/// Must be created at most once (singleton)
|
||||
pub(crate) unsafe fn new(buffer: &'static mut [u8; 64]) -> Self {
|
||||
Self {
|
||||
buffer,
|
||||
busy: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts a data transfer over endpoint 0
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if the last transfer was not finished by calling the `end` function
|
||||
pub fn start(&mut self, bytes: &[u8], usbd: &USBD) -> Result<(), ()> {
|
||||
if self.busy {
|
||||
log::error!("EP0IN: last transfer not completed");
|
||||
return Err(());
|
||||
panic!("EP0IN: last transfer has not completed");
|
||||
}
|
||||
|
||||
if bytes.len() > self.buffer.len() {
|
||||
|
@ -56,12 +62,17 @@ impl Ep0In {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Completes a data transfer
|
||||
///
|
||||
/// This function must be called after the EP0DATADONE event is raised
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if called before `start` or before the EP0DATADONE event is raised by
|
||||
/// the hardware
|
||||
pub fn end(&mut self, usbd: &USBD) {
|
||||
if usbd.events_ep0datadone.read().bits() == 0 {
|
||||
log::error!("Ep0In.end called before the EP0DATADONE event was raised");
|
||||
loop {
|
||||
asm::bkpt();
|
||||
}
|
||||
panic!("Ep0In.end called before the EP0DATADONE event was raised");
|
||||
} else {
|
||||
// DMA transfer complete
|
||||
dma_end();
|
||||
|
@ -77,7 +88,7 @@ impl Ep0In {
|
|||
//
|
||||
// This function call *must* be *followed* by a memory *store* operation. Memory operations that
|
||||
// follow this function call will *not* be moved, by the compiler or the instruction pipeline, to
|
||||
// *after* the function call.
|
||||
// *after* the function call.
|
||||
fn dma_start() {
|
||||
atomic::fence(Ordering::Release);
|
||||
}
|
||||
|
@ -87,21 +98,28 @@ fn dma_start() {
|
|||
//
|
||||
// This function call *must* be *preceded* by a memory *load* operation. Memory operations that
|
||||
// follow this function call will *not* be moved, by the compiler or the instruction pipeline, to
|
||||
// *before* the function call.
|
||||
// *before* the function call.
|
||||
fn dma_end() {
|
||||
atomic::fence(Ordering::Acquire);
|
||||
}
|
||||
|
||||
/// Initializes the USBD peripheral
|
||||
// NOTE will be called from user code; at that point the high frequency clock source has already
|
||||
// been configured to use to the external crystal
|
||||
// Reference: section 6.35.4 of the nRF52840 Product Specification
|
||||
pub fn init(power: POWER, usbd: &USBD) {
|
||||
let mut once = true;
|
||||
|
||||
// wait until the USB has been connected
|
||||
while power.events_usbdetected.read().bits() == 0 {
|
||||
power.events_usbdetected.reset();
|
||||
if once {
|
||||
log::info!("waiting for USB connection on port J3");
|
||||
once = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
power.events_usbdetected.reset();
|
||||
|
||||
// workaround silicon bug
|
||||
unsafe { errata::e187a() }
|
||||
|
@ -147,6 +165,7 @@ pub fn disconnect(usbd: &USBD) {
|
|||
usbd.usbpullup.reset();
|
||||
}
|
||||
|
||||
/// Stalls endpoint 0
|
||||
pub fn ep0stall(usbd: &USBD) {
|
||||
usbd.tasks_ep0stall.write(|w| w.tasks_ep0stall().set_bit());
|
||||
}
|
||||
|
@ -176,7 +195,7 @@ pub fn next_event(usbd: &USBD) -> Option<Event> {
|
|||
}
|
||||
|
||||
if usbd.events_ep0datadone.read().bits() != 0 {
|
||||
// this will be cleared elsewhere
|
||||
// this will be cleared by the `Ep0In.end` method
|
||||
// usbd.events_ep0datadone.reset();
|
||||
|
||||
return Some(Event::UsbEp0DataDone);
|
||||
|
@ -195,21 +214,22 @@ pub fn next_event(usbd: &USBD) -> Option<Event> {
|
|||
pub fn todo(usbd: &USBD) {
|
||||
disconnect(usbd);
|
||||
log::error!("unimplemented");
|
||||
loop {
|
||||
asm::bkpt()
|
||||
}
|
||||
crate::exit()
|
||||
}
|
||||
|
||||
/// Reads the WLENGTHL and WLENGTHH registers and returns the 16-bit WLENGTH component of a setup packet
|
||||
pub fn wlength(usbd: &USBD) -> u16 {
|
||||
u16::from(usbd.wlengthl.read().wlengthl().bits())
|
||||
| u16::from(usbd.wlengthh.read().wlengthh().bits()) << 8
|
||||
}
|
||||
|
||||
/// Reads the WINDEXL and WINDEXH registers and returns the 16-bit WINDEX component of a setup packet
|
||||
pub fn windex(usbd: &USBD) -> u16 {
|
||||
u16::from(usbd.windexl.read().windexl().bits())
|
||||
| u16::from(usbd.windexh.read().windexh().bits()) << 8
|
||||
}
|
||||
|
||||
/// Reads the WVALUEL and WVALUEH registers and returns the 16-bit WVALUE component of a setup packet
|
||||
pub fn wvalue(usbd: &USBD) -> u16 {
|
||||
u16::from(usbd.wvaluel.read().wvaluel().bits())
|
||||
| u16::from(usbd.wvalueh.read().wvalueh().bits()) << 8
|
||||
|
|
Loading…
Reference in a new issue