diff --git a/advanced/common/usb/src/lib.rs b/advanced/common/usb/src/lib.rs index 2685091..7e7b3b5 100644 --- a/advanced/common/usb/src/lib.rs +++ b/advanced/common/usb/src/lib.rs @@ -75,6 +75,7 @@ impl Request { Err(()) } } else { + log::warn!("unhandled case in `Request` parser"); Err(()) } } diff --git a/embedded-workshop-book/src/SUMMARY.md b/embedded-workshop-book/src/SUMMARY.md index 281be28..f84058b 100644 --- a/embedded-workshop-book/src/SUMMARY.md +++ b/embedded-workshop-book/src/SUMMARY.md @@ -60,4 +60,4 @@ - [`cargo-build` fails to link](./troubleshoot-cargo-build.md) - [`dongle-flash` is not working](./troubleshoot-dongle-flash.md) - [Dongle USB functionality is not working](./troubleshoot-usb-dongle.md) - - [USB error: Access denied](./troubleshoot-usb-error-access-denied.md) + - [`cargo run` errors](./troubleshoot-cargo-run.md) diff --git a/embedded-workshop-book/src/data-stage.md b/embedded-workshop-book/src/data-stage.md index 38b67db..9be3004 100644 --- a/embedded-workshop-book/src/data-stage.md +++ b/embedded-workshop-book/src/data-stage.md @@ -2,7 +2,9 @@ The next step is to respond to the GET_DESCRIPTOR request with a device descriptor. -✅ Open the file `src/bin/usb-3.rs`. Implement the response to the GET_DESCRIPTOR request. Use the following guide for assistance. +✅ Open the file `src/bin/usb-3.rs`. Implement the response to the GET_DESCRIPTOR request. Use the following guide for assistance. + +❗️ Keep the cable connected to the J3 port for the rest of the workshop To do this we'll use the `dk::usb::Ep0In` abstraction -- we'll look into what the abstraction does in a future section; for now we'll just use it. diff --git a/embedded-workshop-book/src/dma.md b/embedded-workshop-book/src/dma.md index fdeca13..7bfdf01 100644 --- a/embedded-workshop-book/src/dma.md +++ b/embedded-workshop-book/src/dma.md @@ -1,14 +1,14 @@ -# DMA +# Direct Memory Access -[What do endpoints have to do with dma] +🔎 this section covers the implementation of the `Ep0In` abstraction; it's not necessary to fully understand this section to continue working on the workshop. -[What is the task in this section?] +Let's zoom into the `Ep0In` abstraction we used in `usb-3.rs`. -Let's zoom into the `Ep0In` abstraction used in `usb-4.rs` next. +✅ Open the file. Use VSCode's "Go to Definition" to see the implementation of the `Ep0In.start()` method. -✅ Open the file. Use VSCode's "Go to Definition" to see the implementation of the `Ep0In.start()` method. +This is how data transfers over USB work on the nRF52840: for each endpoint there's a buffer in the USBD peripheral. Data sent by the host over USB to a particular endpoint will be stored in the corresponding endpoint buffer. Likewise, data stored in one of these endpoint buffers can be send to the host over USB from that particular endpoint. These buffers are not directly accessible by the CPU but data stored in RAM can be copied into these buffers; likewise, the contents of an endpoint buffer can be copied into RAM. A second peripheral, the Direct Memory Access (DMA) peripheral, can copy data between these endpoint buffers and RAM. The process of copying data in either direction is referred to as "a DMA transfer". -What this method does is start a DMA transfer to send `bytes` to the host. The data (`bytes`) is first copied into an internal buffer and then the DMA is configured to move the data from that internal buffer to the USBD peripheral. +What the `start` method does is start a DMA transfer to copy `bytes` into endpoint buffer IN 0; this makes the USBD peripheral send data to the host from endpoint IN 0 fs. The data (`bytes`), which may be located in Flash or RAM, is first copied into an internal buffer, allocated in RAM, and then the DMA is configured to move the data from this internal buffer to endpoint buffer 0 IN, which is part of the USBD peripheral. The signature of the `start()` method does *not* ensure that: diff --git a/embedded-workshop-book/src/setup-stage.md b/embedded-workshop-book/src/setup-stage.md index 4323822..1c16ea9 100644 --- a/embedded-workshop-book/src/setup-stage.md +++ b/embedded-workshop-book/src/setup-stage.md @@ -12,7 +12,9 @@ So that's what we'll do here. In `advanced/common/usb/lib.rs` you'll find starte The definition of `Descriptor::Configuration` as well as the associated test has been "commented out" using an `#[cfg(TODO)]` attribute because it is not handled by the firmware yet. Delete the `#[cfg(TODO)]` so that the unit tests can access it. This pattern is used for enum members and test functions throughout this workshop, so keep it in mind should you see it again. -✅ Parse the data of this SETUP stage. +✅ Parse the data of this SETUP stage. + +❗️ Keep the cable connected to the J3 port for the rest of the workshop Start with the GET_DESCRIPTOR request, which is described in detail in section 9.4.3 of the USB specification. All the constants you will need are described in Tables 9-3, 9-4 and 9-5. diff --git a/embedded-workshop-book/src/supporting-standard-requests.md b/embedded-workshop-book/src/supporting-standard-requests.md index 86380d8..5620b67 100644 --- a/embedded-workshop-book/src/supporting-standard-requests.md +++ b/embedded-workshop-book/src/supporting-standard-requests.md @@ -1,6 +1,6 @@ # USB-4: Supporting more Standard Requests -After responding to the `GET_DESCRIPTOR Device` request the host will start sending different requests. +After responding to the `GET_DESCRIPTOR Device` request the host will start sending different requests. ✅ Update the parser in `common/usb` so that it can handle the following requests: @@ -11,6 +11,8 @@ The starter `common/usb` code contains unit tests for these other requests as we ✅ For each green test, extend `usb-4.rs` to handle the new requests your parser is now able to recognize. **Make sure to read the next sections as you're working**, since they contain explanations about the concepts used and needed to complete this task. +❗️ Keep the cable connected to the J3 port for the rest of the workshop + If you need a reference, you can find solutions to parsing `GET_DESCRIPTOR Configuration` and `SET_CONFIGURATION` requests in the following files: - `advanced/common/usb/solution-get-descriptor-configuration.rs` diff --git a/embedded-workshop-book/src/troubleshoot-cargo-run-error.md b/embedded-workshop-book/src/troubleshoot-cargo-run-error.md new file mode 100644 index 0000000..ea0fe4b --- /dev/null +++ b/embedded-workshop-book/src/troubleshoot-cargo-run-error.md @@ -0,0 +1,28 @@ +# `cargo run` errors + +You may get one of these errors: + +- "Access denied (insufficient permissions)" (seen on macOS) +- "USB error while taking control over USB device: Resource busy" (seen on Linux) + +``` console +$ cargo run --bin usb-4 +Running `dk-run target/thumbv7em-none-eabi/debug/usb-4` +Error: An error specific to a probe type occured: USB error while taking control over USB device: Access denied (insufficient permissions) + +Caused by: + USB error while taking control over USB device: Access denied (insufficient permissions) +``` + +``` console +$ cargo run --bin usb-4 +Running `dk-run target/thumbv7em-none-eabi/debug/usb-4` +Error: An error specific to a probe type occured: USB error while taking control over USB device: Resource busy + +Caused by: + USB error while taking control over USB device: Resource busy +``` + +All of them have the same root issue: You have another instance of the `cargo run` process running. + +It is not possible to have two or more instances of `cargo run` running. Terminate the old instance before executing `cargo run`. If you are using VS Code click the garbage icon ("Kill Terminal") on the top right corner of the terminal output window (located on the bottom of the screen). diff --git a/embedded-workshop-book/src/troubleshoot-usb-error-access-denied.md b/embedded-workshop-book/src/troubleshoot-usb-error-access-denied.md deleted file mode 100644 index cbfb949..0000000 --- a/embedded-workshop-book/src/troubleshoot-usb-error-access-denied.md +++ /dev/null @@ -1,3 +0,0 @@ -## USB error while taking control over USB device: Access denied (insufficient permissions) - -If you get this Error when trying to run a different process, check if the old process is still running. If this is the case, end it. Try again. \ No newline at end of file diff --git a/embedded-workshop-book/src/usb-events.md b/embedded-workshop-book/src/usb-events.md index 26f6bea..38c1d92 100644 --- a/embedded-workshop-book/src/usb-events.md +++ b/embedded-workshop-book/src/usb-events.md @@ -2,12 +2,14 @@ The USBD peripheral on the nRF52840 contains a series of registers, called EVENTS registers, that indicate the reason for entering the USBD event handler. These events must be handled by the application to complete the enumeration process. -✅ Open the `firmware/src/bin/usb-1.rs` file. +✅ Open the `firmware/src/bin/usb-1.rs` file. In this starter code the USBD peripheral is initialized in `init` and a task, named `main`, is bound to the interrupt signal USBD. This task will be called every time a new USBD event needs to be handled. The `main` task uses `usbd::next_event()` to check all the event registers; if any event is set (occurred) then the function returns the event, represented by the `Event` enum, wrapped in the `Some` variant. This `Event` is then passed to the `on_event` function for further processing. ✅ Connect the USB cable to the port J3 then run the starter code. +❗️ Keep the cable connected to the J3 port for the rest of the workshop + Go to `fn on_event`, line 39. In this section you'll need to implement the following USB events until you reach the EP0SETUP event: - `USBRESET`. This event indicates that the host issued a USB reset signal. According to the USB specification this will move the device from any state to the `Default` state. Since we are currently not dealing with any other state, you can handle this state by doing nothing. @@ -27,4 +29,3 @@ INFO:usb_1 -- goal reached; move to the next section Do not overthink this exercise; it is not a trick question. There is very little to do and no new functionality to add. You can find the solution in the `usb-1-solution.rs` file. -