8000 USB implementation for Raspberry Pi Pico by TeodoraMiu · Pull Request #3310 · tock/tock · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

USB implementation for Raspberry Pi Pico #3310

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Dec 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions boards/raspberry_pi_pico/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,39 @@ PLATFORM=raspberry_pi_pico

include ../Makefile.common

OPENOCD=openocd
OPENOCD_INTERFACE=swd
OPENOCD_OPTIONS=-f openocd-$(OPENOCD_INTERFACE).cfg
# OPENOCD=openocd
# OPENOCD_INTERFACE=swd
# OPENOCD_OPTIONS=-f openocd-$(OPENOCD_INTERFACE).cfg

KERNEL=$(TOCK_ROOT_DIRECTORY)target/$(TARGET)/debug/$(PLATFORM).elf
KERNEL_WITH_APP=$(TOCK_ROOT_DIRECTORY)/target/$(TARGET)/debug/$(PLATFORM)-app.elf
KERNEL=$(TOCK_ROOT_DIRECTORY)/target/$(TARGET)/release/$(PLATFORM).elf
KERNEL_WITH_APP=$(TOCK_ROOT_DIRECTORY)/target/$(TARGET)/release/$(PLATFORM)-app.elf

BOOTSEL_FOLDER?=/media/$(USER)/RPI-RP2

# Default target for installing the kernel.
.PHONY: install
install: flash

.PHONY: flash-debug
flash-debug: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/debug/$(PLATFORM).elf
$(OPENOCD) $(OPENOCD_OPTIONS) -c "program $<; verify_image $<; reset; shutdown;"
elf2uf2 $< $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/debug/$(PLATFORM).uf2
if [ -d $(BOOTSEL_FOLDER) ];
then
cp $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/debug/$(PLATFORM)-app.uf2 $(BOOTSEL_FOLDER)"
else
@echo Please edit the BOOTSEL_FOLDER variable to point to you RPI RP2040 Flash Drive Folder
fi

.PHONY: flash
flash: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).elf
$(OPENOCD) $(OPENOCD_OPTIONS) -c "program $<; verify_image $<; reset; shutdown;"
elf2uf2 $< $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).uf2
@if [ -d $(BOOTSEL_FOLDER) ]; then cp $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).uf2 "$(BOOTSEL_FOLDER)"; else echo; echo Please edit the BOOTSEL_FOLDER variable to point to you Nano RP2040 Flash Drive Folder; fi

.PHONY: program
program: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/debug/$(PLATFORM).bin
program: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin
ifeq ($(APP),)
$(error Please define the APP variable with the TBF file to flash an application)
endif
arm-none-eabi-objcopy --update-section .apps=$(APP) $(KERNEL) $(KERNEL_WITH_APP)
$(OPENOCD) $(OPENOCD_OPTIONS) -c "program $(KERNEL_WITH_APP); verify_image $(KERNEL_WITH_APP); reset; shutdown;"

elf2uf2 $(KERNEL_WITH_APP) $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM)-app.uf2
@if [ -d $(BOOTSEL_FOLDER) ]; then cp $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM)-app.uf2 "$(BOOTSEL_FOLDER)"; else echo; echo Please edit the BOOTSEL_FOLDER variable to point to you Nano RP2040 Flash Drive Folder; fi
52 changes: 51 additions & 1 deletion boards/raspberry_pi_pico/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,59 @@ board developed by the Raspberry Pi Foundation and is based on the RP2040 chip.

First, follow the [Tock Getting Started guide](../../doc/Getting_Started.md)

## Installing elf2uf2

The Raspberry Pi Pico RP2040 uses UF2 files for flashing. Tock compiles to an ELF file.
The `elf2uf2` utility is needed to transform the Tock ELF file into an UF2 file.

To install `elf2uf2`, run the commands:

```bash
$ git clone https://github.com/raspberrypi/pico-sdk
$ cd pico-sdk
$ cd tools/elf2uf2
$ mkdir build
$ cd build
$ cmake ..
$ make
$ sudo cp elf2uf2 /usr/local/bin
```

## Flashing the kernel

The Raspberry Pi Pico can be programmed via an SWD connection, which requires the Pico to be connected to a regular Raspberry Pi device that exposes the necessary pins OR using another Raspberry Pi Pico set up in “Picoprobe” mode. The kernel is transferred to the Raspberry Pi Pico using a [custom version of OpenOCD](https://github.com/raspberrypi/openocd).
The Raspberry Pi Pico RP2040 Connect can be programmed using its bootloader, which requires an UF2 file.

### Enter BOOTSEL mode

To flash the Pico RP2040, it needs to be put into BOOTSEL mode. This will mount
a flash drive that allows one to copy a UF2 file. To enter BOOTSEL mode, press the BOOTSEL button and hold it while you connect the other end of the micro USB cable to your computer.

Then `cd` into `boards/raspberry_pi_pico` directory and run:

```bash
$ make flash

(or)

$ make flash-debug
```

> Note: The Makefile provides the BOOTSEL_FOLDER variable that points towards the mount point of
> the Pico RP2040 flash drive. By default, this is located in `/media/$(USER)/RP2040`. This might
> be different on several systems, make sure to adjust it.

## Flashing app

Enter BOOTSEL mode.

Apps are built out-of-tree. Once an app is built, you can add the path to it in the Makefile (APP variable), then run:
```bash
$ APP="<path to app's tbf file>" make flash-app
```

## Debugging

The Raspberry Pi Pico can also be programmed via an SWD connection, which requires the Pico to be connected to a regular Raspberry Pi device that exposes the necessary pins OR using another Raspberry Pi Pico set up in “Picoprobe” mode. The kernel is transferred to the Raspberry Pi Pico using a [custom version of OpenOCD](https://github.com/raspberrypi/openocd).

### Flashing Setup

Expand Down
4 changes: 2 additions & 2 deletions boards/raspberry_pi_pico/layout.ld
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ MEMORY
ram (rwx) : ORIGIN = 0x20004000, LENGTH = 240K */

/* boot from Flash */
rom (rx) : ORIGIN = 0x10000000, LENGTH = 128K
prog (rx) : ORIGIN = 0x10020000, LENGTH = 256K
rom (rx) : ORIGIN = 0x10000000, LENGTH = 256K
prog (rx) : ORIGIN = 0x10040000, LENGTH = 256K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 264K
}

Expand Down
64 changes: 54 additions & 10 deletions boards/raspberry_pi_pico/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use kernel::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClie
use kernel::hil::gpio::{Configure, FloatingState};
use kernel::hil::i2c::I2CMaster;
use kernel::hil::led::LedHigh;
use kernel::hil::usb::Client;
use kernel::platform::{KernelResources, SyscallDriverLookup};
use kernel::scheduler::round_robin::RoundRobinSched;
use kernel::syscall::SyscallDriver;
Expand Down Expand Up @@ -50,6 +51,15 @@ mod flash_bootloader;
#[link_section = ".stack_buffer"]
pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000];

// Function for the CDC/USB stack used to ask the MCU to reset into
// tockbootloader.
fn baud_rate_reset_bootloader_enter() {
// unsafe {
// cortexm0::scb::reset();
// }
// TODO reset into bootloader
}

// Manually setting the boot header section that contains the FCB header
#[used]
#[link_section = ".flash_bootloader"]
Expand Down Expand Up @@ -253,9 +263,6 @@ pub unsafe fn main() {
let peripherals = get_peripherals();
peripherals.resolve_dependencies();

// Set the UART used for panic
io::WRITER.set_uart(&peripherals.uart0);

// Reset all peripherals except QSPI (we might be booting from Flash), PLL USB and PLL SYS
peripherals.resets.reset_all_except(&[
Peripheral::IOQSpi,
Expand Down Expand Up @@ -312,7 +319,7 @@ pub unsafe fn main() {
let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability);

let dynamic_deferred_call_clients =
static_init!([DynamicDeferredCallClientState; 2], Default::default());
static_init!([DynamicDeferredCallClientState; 3], Default::default());
let dynamic_deferred_caller = static_init!(
DynamicDeferredCall,
DynamicDeferredCall::new(dynamic_deferred_call_clients)
Expand All @@ -329,14 +336,48 @@ pub unsafe fn main() {
)
.finalize(components::alarm_component_static!(RPTimer));

// UART
// Create a shared UART channel for kernel debug.
let uart_mux = components::console::UartMuxComponent::new(
&peripherals.uart0,
115200,
// CDC
let strings = static_init!(
[&str; 3],
[
"Raspberry Pi", // Manufacturer
"Pico - TockOS", // Product
"00000000000000000", // Serial number
]
);

let cdc = components::cdc::CdcAcmComponent::new(
&peripherals.usb,
//capsules::usb::cdc::MAX_CTRL_PACKET_SIZE_RP2040,
64,
0x0,
0x1,
strings,
mux_alarm,
dynamic_deferred_caller,
Some(&baud_rate_reset_bootloader_enter),
)
.finalize(components::uart_mux_component_static!());
.finalize(components::cdc_acm_component_static!(
rp2040::usb::UsbCtrl,
rp2040::timer::RPTimer
));

// UART
// Create a shared UART channel for kernel debug.

let uart_mux = components::console::UartMuxComponent::new(cdc, 115200, dynamic_deferred_caller)
.finalize(components::uart_mux_component_static!());

// Uncomment this to use UART as an output
// let uart_mux2 = components::console::UartMuxComponent::new(
// &peripherals.uart0,
// 115200,
// dynamic_deferred_caller,
// )
// .finalize(components::uart_mux_component_static!());

// Set the UART used for panic
io::WRITER.set_uart(&peripherals.uart0);

// Setup the console.
let console = components::console::ConsoleComponent::new(
Expand All @@ -349,6 +390,9 @@ pub unsafe fn main() {
components::debug_writer::DebugWriterComponent::new(uart_mux)
.finalize(components::debug_writer_component_static!());

cdc.enable();
cdc.attach();

let gpio = GpioComponent::new(
board_kernel,
capsules::gpio::DRIVER_NUM,
Expand Down
10 changes: 9 additions & 1 deletion chips/rp2040/src/chip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ use kernel::platform::chip::InterruptService;
use crate::adc;
use crate::clocks::Clocks;
use crate::deferred_call_tasks::DeferredCallTask;
use crate::gpio::{RPPins, SIO};
use crate::gpio::{RPGpio, RPPins, SIO};
use crate::i2c;
use crate::interrupts;
use crate::resets::Resets;
use crate::spi;
use crate::sysinfo;
use crate::timer::RPTimer;
use crate::uart::Uart;
use crate::usb;
use crate::watchdog::Watchdog;
use crate::xosc::Xosc;
use cortexm0p::{interrupt_mask, CortexM0P, CortexMVariant};
Expand Down Expand Up @@ -131,6 +132,7 @@ pub struct Rp2040DefaultPeripherals<'a> {
pub spi0: spi::Spi<'a>,
pub sysinfo: sysinfo::SysInfo,
pub i2c0: i2c::I2c<'a>,
pub usb: usb::UsbCtrl<'a>,
}

impl<'a> Rp2040DefaultPeripherals<'a> {
Expand All @@ -149,13 +151,15 @@ impl<'a> Rp2040DefaultPeripherals<'a> {
spi0: spi::Spi::new_spi0(),
sysinfo: sysinfo::SysInfo::new(),
i2c0: i2c::I2c::new_i2c0(),
usb: usb::UsbCtrl::new(),
}
}

pub fn resolve_dependencies(&'a self) {
self.spi0.set_clocks(&self.clocks);
self.uart0.set_clocks(&self.clocks);
self.i2c0.resolve_dependencies(&self.clocks, &self.resets);
self.usb.set_gpio(self.pins.get_pin(RPGpio::GPIO15));
}
}

Expand Down Expand Up @@ -186,6 +190,10 @@ impl InterruptService<DeferredCallTask> for Rp2040DefaultPeripherals<'_> {
self.adc.handle_interrupt();
true
}
interrupts::USBCTRL_IRQ => {
self.usb.handle_interrupt();
true
}
interrupts::IO_IRQ_BANK0 => {
self.pins.handle_interrupt();
true
Expand Down
25 changes: 25 additions & 0 deletions chips/rp2040/src/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,31 @@ impl<'a> RPGpioPin<'a> {
pub fn handle_interrupt(&self) {
self.client.map(|client| client.fired());
}

// needed for usb errata https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#RP2040-E5

pub fn start_usb_errata(&self) -> (u32, u32) {
let prev_ctrl = self.gpio_registers.pin[self.pin].ctrl.get();
let prev_pad = self.gpio_pad_registers.gpio_pad[self.pin].get();

self.gpio_pad_registers.gpio_pad[self.pin].modify(GPIO_PAD::PUE::SET + GPIO_PAD::PDE::SET);
self.gpio_registers.pin[self.pin]
.ctrl
.modify(GPIOx_CTRL::OEOVER::Disable);

self.set_function(GpioFunction::GPCK);

self.gpio_registers.pin[self.pin]
.ctrl
.modify(GPIOx_CTRL::INOVER::DriveHigh);

(prev_ctrl, prev_pad)
}

pub fn finish_usb_errata(&self, prev_ctrl: u32, prev_pad: u32) {
self.gpio_registers.pin[self.pin].ctrl.set(prev_ctrl);
self.gpio_pad_registers.gpio_pad[self.pin].set(prev_pad);
}
}

impl<'a> hil::gpio::Interrupt<'a> for RPGpioPin<'a> {
Expand Down
1 change: 1 addition & 0 deletions chips/rp2040/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub mod spi;
pub mod sysinfo;
pub mod timer;
pub mod uart;
pub mod usb;
pub mod watchdog;
pub mod xosc;

Expand Down
Loading
0