Merge pull request #128 from 42-technology-ltd/update-pico-examples

Update Pico BSP examples
This commit is contained in:
Jonathan Pallant 2021-09-22 09:06:44 +01:00 committed by GitHub
commit 58242bcc00
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 1030 additions and 217 deletions

View file

@ -186,7 +186,7 @@ to intervene to uphold that code of conduct.
The contents of this repository are dual-licensed under the _MIT OR Apache The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the 2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 when you re-use this code. See `MIT` or `APACHE2.0` for more Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence. information on each specific licence.
Any submissions to this project (e.g. as Pull Requests) must be made available Any submissions to this project (e.g. as Pull Requests) must be made available

View file

@ -1 +1,94 @@
Adafruit Macropad Board Support Crate # [adafruit_macropad] - Board Support for the [Adafruit Macropad]
You should include this crate if you are writing code that you want to run on
an [Adafruit Macropad] - a 3x4 keyboard and OLED combo board from Adafruit.
This crate includes the [rp2040-hal], but also configures each pin of the
RP2040 chip according to how it is connected up on the Feather.
[adafruit_macropad]: https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit_macropad
[Adafruit Macropad]: https://www.adafruit.com/product/5128
[rp2040-hal]: https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal
[Raspberry Pi Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/
## Using
To use this crate, your `Cargo.toml` file should contain:
```toml
adafruit_macropad = { git = "https://github.com/rp-rs/rp-hal.git" }
```
In your program, you will need to call `adafruit_macropad::Pins::new` to create
a new `Pins` structure. This will set up all the GPIOs for any on-board
devices. See the [examples](./examples) folder for more details.
## Examples
### General Instructions
To compile an example, clone the _rp-hal_ repository and run:
```console
rp-hal/boards/adafruit_macropad $ cargo build --release --example <name>
```
You will get an ELF file called
`./target/thumbv6m-none-eabi/release/examples/<name>`, where the `target`
folder is located at the top of the _rp-hal_ repository checkout. Normally
you would also need to specify `--target=thumbv6m-none-eabi` but when
building examples from this git repository, that is set as the default.
If you want to convert the ELF file to a UF2 and automatically copy it to the
USB drive exported by the RP2040 bootloader, simply boot your board into
bootloader mode and run:
```console
rp-hal/boards/adafruit_macropad $ cargo run --release --example <name>
```
If you get an error about not being able to find `elf2uf2-rs`, try:
```console
$ cargo install elf2uf2-rs, then repeating the `cargo run` command above.
```
### [feather_blinky](./examples/feather_blinky.rs)
Flashes the Feather's on-board LED on and off.
## Contributing
Contributions are what make the open source community such an amazing place to
be learn, inspire, and create. Any contributions you make are **greatly
appreciated**.
The steps are:
1. Fork the Project by clicking the 'Fork' button at the top of the page.
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
3. Make some changes to the code or documentation.
4. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
5. Push to the Feature Branch (`git push origin feature/AmazingFeature`)
6. Create a [New Pull Request](https://github.com/rp-rs/rp-hal/pulls)
7. An admin will review the Pull Request and discuss any changes that may be required.
8. Once everyone is happy, the Pull Request can be merged by an admin, and your work is part of our project!
## Code of Conduct
Contribution to this crate is organized under the terms of the [Rust Code of
Conduct][CoC], and the maintainer of this crate, the [rp-rs team], promises
to intervene to uphold that code of conduct.
[CoC]: CODE_OF_CONDUCT.md
[rp-rs team]: https://github.com/orgs/rp-rs/teams/rp-rs
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -1 +1,94 @@
Adafruit Feather RP2040 Board Support Crate # [feather_rp2040] - Board Support for the [Adafruit Feather RP2040]
You should include this crate if you are writing code that you want to run on
an [Adafruit Feather RP2040] - a Feather form-factor RP2040 board from Adafruit.
This crate includes the [rp2040-hal], but also configures each pin of the
RP2040 chip according to how it is connected up on the Feather.
[Adafruit Feather RP2040]: https://www.adafruit.com/product/4884
[feather_rp2040]: https://github.com/rp-rs/rp-hal/tree/main/boards/feather_rp2040
[rp2040-hal]: https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal
[Raspberry Pi Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/
## Using
To use this crate, your `Cargo.toml` file should contain:
```toml
feather_rp2040 = { git = "https://github.com/rp-rs/rp-hal.git" }
```
In your program, you will need to call `feather_rp2040::Pins::new` to create
a new `Pins` structure. This will set up all the GPIOs for any on-board
devices. See the [examples](./examples) folder for more details.
## Examples
### General Instructions
To compile an example, clone the _rp-hal_ repository and run:
```console
rp-hal/boards/feather_rp2040 $ cargo build --release --example <name>
```
You will get an ELF file called
`./target/thumbv6m-none-eabi/release/examples/<name>`, where the `target`
folder is located at the top of the _rp-hal_ repository checkout. Normally
you would also need to specify `--target=thumbv6m-none-eabi` but when
building examples from this git repository, that is set as the default.
If you want to convert the ELF file to a UF2 and automatically copy it to the
USB drive exported by the RP2040 bootloader, simply boot your board into
bootloader mode and run:
```console
rp-hal/boards/feather_rp2040 $ cargo run --release --example <name>
```
If you get an error about not being able to find `elf2uf2-rs`, try:
```console
$ cargo install elf2uf2-rs, then repeating the `cargo run` command above.
```
### [feather_blinky](./examples/feather_blinky.rs)
Flashes the Feather's on-board LED on and off.
## Contributing
Contributions are what make the open source community such an amazing place to
be learn, inspire, and create. Any contributions you make are **greatly
appreciated**.
The steps are:
1. Fork the Project by clicking the 'Fork' button at the top of the page.
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
3. Make some changes to the code or documentation.
4. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
5. Push to the Feature Branch (`git push origin feature/AmazingFeature`)
6. Create a [New Pull Request](https://github.com/rp-rs/rp-hal/pulls)
7. An admin will review the Pull Request and discuss any changes that may be required.
8. Once everyone is happy, the Pull Request can be merged by an admin, and your work is part of our project!
## Code of Conduct
Contribution to this crate is organized under the terms of the [Rust Code of
Conduct][CoC], and the maintainer of this crate, the [rp-rs team], promises
to intervene to uphold that code of conduct.
[CoC]: CODE_OF_CONDUCT.md
[rp-rs team]: https://github.com/orgs/rp-rs/teams/rp-rs
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -4,7 +4,7 @@ You should include this crate if you are writing code that you want to run on
a [Raspberry Pi Pico] - the original launch PCB for the RP2040 chip. a [Raspberry Pi Pico] - the original launch PCB for the RP2040 chip.
This crate includes the [rp2040-hal], but also configures each pin of the This crate includes the [rp2040-hal], but also configures each pin of the
RP2040 chip according to how it is connected up on the Pro Micro RP2040. RP2040 chip according to how it is connected up on the Pico.
[Raspberry Pi Pico]: https://www.raspberrypi.org/products/raspberry-pi-pico/ [Raspberry Pi Pico]: https://www.raspberrypi.org/products/raspberry-pi-pico/
[pico]: https://github.com/rp-rs/rp-hal/tree/main/boards/pico [pico]: https://github.com/rp-rs/rp-hal/tree/main/boards/pico
@ -123,7 +123,7 @@ to intervene to uphold that code of conduct.
The contents of this repository are dual-licensed under the _MIT OR Apache The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the 2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 when you re-use this code. See `MIT` or `APACHE2.0` for more Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence. information on each specific licence.
Any submissions to this project (e.g. as Pull Requests) must be made available Any submissions to this project (e.g. as Pull Requests) must be made available

View file

@ -1,35 +1,66 @@
//! Blinks the LED on a Pico board //! # Pico Blinky Example
//! //!
//! This will blink an LED attached to GP25, which is the pin the Pico uses for the on-board LED. //! Blinks the LED on a Pico board.
//!
//! This will blink an LED attached to GP25, which is the pin the Pico uses for
//! the on-board LED.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
#![no_std] #![no_std]
#![no_main] #![no_main]
// The macro for our start-up function
use cortex_m_rt::entry; use cortex_m_rt::entry;
// GPIO traits
use embedded_hal::digital::v2::OutputPin; use embedded_hal::digital::v2::OutputPin;
// Time handling traits
use embedded_time::rate::*; use embedded_time::rate::*;
// Ensure we halt the program on panic (if we don't mention this crate it won't
// be linked)
use panic_halt as _; use panic_halt as _;
use pico::{
hal::{ // Pull in any important traits
clocks::{init_clocks_and_plls, Clock}, use pico::hal::prelude::*;
pac,
sio::Sio, // A shorter alias for the Peripheral Access Crate, which provides low-level
watchdog::Watchdog, // register access
}, use pico::hal::pac;
Pins, XOSC_CRYSTAL_FREQ,
}; // A shorter alias for the Hardware Abstraction Layer, which provides
// higher-level drivers.
use pico::hal;
/// The linker will place this boot block at the start of our program image. We
/// need this to help the ROM bootloader get our code up and running.
#[link_section = ".boot2"] #[link_section = ".boot2"]
#[used] #[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
/// Entry point to our bare-metal application.
///
/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
/// as soon as all global variables are initialised.
///
/// The function configures the RP2040 peripherals, then blinks the LED in an
/// infinite loop.
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
// Grab our singleton objects
let mut pac = pac::Peripherals::take().unwrap(); let mut pac = pac::Peripherals::take().unwrap();
let core = pac::CorePeripherals::take().unwrap(); let core = pac::CorePeripherals::take().unwrap();
let mut watchdog = Watchdog::new(pac.WATCHDOG); // Set up the watchdog driver - needed by the clock setup code
let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks_and_plls( // Configure the clocks
XOSC_CRYSTAL_FREQ, //
// Our default is 12 MHz crystal input, 125 MHz system clock
let clocks = hal::clocks::init_clocks_and_plls(
pico::XOSC_CRYSTAL_FREQ,
pac.XOSC, pac.XOSC,
pac.CLOCKS, pac.CLOCKS,
pac.PLL_SYS, pac.PLL_SYS,
@ -40,17 +71,25 @@ fn main() -> ! {
.ok() .ok()
.unwrap(); .unwrap();
// The delay object lets us wait for specified amounts of time (in
// milliseconds)
let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer()); let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer());
let sio = Sio::new(pac.SIO); // The single-cycle I/O block controls our GPIO pins
let pins = Pins::new( let sio = hal::sio::Sio::new(pac.SIO);
// Set the pins up according to their function on this particular board
let pins = pico::Pins::new(
pac.IO_BANK0, pac.IO_BANK0,
pac.PADS_BANK0, pac.PADS_BANK0,
sio.gpio_bank0, sio.gpio_bank0,
&mut pac.RESETS, &mut pac.RESETS,
); );
// Set the LED to be an output
let mut led_pin = pins.led.into_push_pull_output(); let mut led_pin = pins.led.into_push_pull_output();
// Blink the LED at 1 Hz
loop { loop {
led_pin.set_high().unwrap(); led_pin.set_high().unwrap();
delay.delay_ms(500); delay.delay_ms(500);
@ -58,3 +97,5 @@ fn main() -> ! {
delay.delay_ms(500); delay.delay_ms(500);
} }
} }
// End of file

View file

@ -1,18 +1,37 @@
//! Blinks the LED on a Pico board //! # Pico Countdown Blinky Example
//! //!
//! This will blink an LED attached to GP25, which is the pin the Pico uses for the on-board LED. //! Blinks the LED on a Pico board, using an RP2040 Timer in Count-down mode.
//!
//! This will blink an LED attached to GP25, which is the pin the Pico uses for
//! the on-board LED.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
#![no_std] #![no_std]
#![no_main] #![no_main]
use cortex_m::prelude::_embedded_hal_timer_CountDown; // The macro for our start-up function
use cortex_m_rt::entry; use cortex_m_rt::entry;
use cortex_m::prelude::*;
// GPIO traits
use embedded_hal::digital::v2::OutputPin; use embedded_hal::digital::v2::OutputPin;
// Traits for converting integers to amounts of time
use embedded_time::duration::Extensions; use embedded_time::duration::Extensions;
// Ensure we halt the program on panic (if we don't mention this crate it won't
// be linked)
use panic_halt as _; use panic_halt as _;
use pico::{
hal::{self as hal, clocks::init_clocks_and_plls, pac, sio::Sio, watchdog::Watchdog}, // A shorter alias for the Peripheral Access Crate, which provides low-level
XOSC_CRYSTAL_FREQ, // register access
}; use pico::hal::pac;
// A shorter alias for the Hardware Abstraction Layer, which provides
// higher-level drivers.
use pico::hal;
#[link_section = ".boot2"] #[link_section = ".boot2"]
#[used] #[used]
@ -20,11 +39,17 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
// Grab our singleton objects
let mut pac = pac::Peripherals::take().unwrap(); let mut pac = pac::Peripherals::take().unwrap();
let mut watchdog = Watchdog::new(pac.WATCHDOG);
let _clocks = init_clocks_and_plls( // Set up the watchdog driver - needed by the clock setup code
XOSC_CRYSTAL_FREQ, let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG);
// Configure the clocks
//
// Our default is 12 MHz crystal input, 125 MHz system clock
let _clocks = hal::clocks::init_clocks_and_plls(
pico::XOSC_CRYSTAL_FREQ,
pac.XOSC, pac.XOSC,
pac.CLOCKS, pac.CLOCKS,
pac.PLL_SYS, pac.PLL_SYS,
@ -35,26 +60,32 @@ fn main() -> ! {
.ok() .ok()
.unwrap(); .unwrap();
// Configure the Timer peripheral in count-down mode
let timer = hal::timer::Timer::new(pac.TIMER); let timer = hal::timer::Timer::new(pac.TIMER);
let mut count_down = timer.count_down(); let mut count_down = timer.count_down();
let sio = Sio::new(pac.SIO); // The single-cycle I/O block controls our GPIO pins
let pins = hal::gpio::Pins::new( let sio = hal::sio::Sio::new(pac.SIO);
// Set the pins up according to their function on this particular board
let pins = pico::Pins::new(
pac.IO_BANK0, pac.IO_BANK0,
pac.PADS_BANK0, pac.PADS_BANK0,
sio.gpio_bank0, sio.gpio_bank0,
&mut pac.RESETS, &mut pac.RESETS,
); );
let mut led_pin = pins.gpio25.into_push_pull_output();
let mut led_pin = pins.led.into_push_pull_output();
// Blink the LED at 1 Hz
loop { loop {
// LED on, and wait for 500ms
led_pin.set_high().unwrap(); led_pin.set_high().unwrap();
// wait for 500ms
count_down.start(500.milliseconds()); count_down.start(500.milliseconds());
let _ = nb::block!(count_down.wait()); let _ = nb::block!(count_down.wait());
// LED off, and wait for 500ms
led_pin.set_low().unwrap(); led_pin.set_low().unwrap();
// wait for 500ms
count_down.start(500.milliseconds()); count_down.start(500.milliseconds());
let _ = nb::block!(count_down.wait()); let _ = nb::block!(count_down.wait());
} }

View file

@ -1,36 +1,74 @@
//! Toggle LED based on GPIO input //! # Pico GPIO In/Out Example
//! //!
//! This will control an LED on GP25 based on a button hooked up to GP15. The button should be tied //! Toggles the LED based on GPIO input.
//! to ground, as the input pin is pulled high internally by this example. When the button is //!
//! pressed, the LED will turn off. //! This will control an LED on GP25 based on a button hooked up to GP15. The
//! button should cause the line to be grounded, as the input pin is pulled high
//! internally by this example. When the button is pressed, the LED will turn
//! off.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
#![no_std] #![no_std]
#![no_main] #![no_main]
// The macro for our start-up function
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embedded_hal::digital::v2::{InputPin, OutputPin};
use hal::pac;
use hal::sio::Sio;
use panic_halt as _;
use pico::{hal, Pins};
// GPIO traits
use embedded_hal::digital::v2::{InputPin, OutputPin};
// Ensure we halt the program on panic (if we don't mention this crate it won't
// be linked)
use panic_halt as _;
// A shorter alias for the Peripheral Access Crate, which provides low-level
// register access
use pico::hal::pac;
// A shorter alias for the Hardware Abstraction Layer, which provides
// higher-level drivers.
use pico::hal;
/// The linker will place this boot block at the start of our program image. We
/// need this to help the ROM bootloader get our code up and running.
#[link_section = ".boot2"] #[link_section = ".boot2"]
#[used] #[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
/// Entry point to our bare-metal application.
///
/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
/// as soon as all global variables are initialised.
///
/// The function configures the RP2040 peripherals, then just reads the button
/// and sets the LED appropriately.
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
// Grab our singleton objects
let mut pac = pac::Peripherals::take().unwrap(); let mut pac = pac::Peripherals::take().unwrap();
let sio = Sio::new(pac.SIO); // Note - we don't do any clock set-up in this example. The RP2040 will run
let pins = Pins::new( // at it's default clock speed.
// The single-cycle I/O block controls our GPIO pins
let sio = hal::sio::Sio::new(pac.SIO);
// Set the pins up according to their function on this particular board
let pins = pico::Pins::new(
pac.IO_BANK0, pac.IO_BANK0,
pac.PADS_BANK0, pac.PADS_BANK0,
sio.gpio_bank0, sio.gpio_bank0,
&mut pac.RESETS, &mut pac.RESETS,
); );
// Our LED output
let mut led_pin = pins.led.into_push_pull_output(); let mut led_pin = pins.led.into_push_pull_output();
// Our button input
let button_pin = pins.bootsel.into_pull_down_input(); let button_pin = pins.bootsel.into_pull_down_input();
// Run forever, setting the LED according to the button
loop { loop {
if button_pin.is_low().unwrap() { if button_pin.is_low().unwrap() {
led_pin.set_high().unwrap(); led_pin.set_high().unwrap();
@ -39,3 +77,5 @@ fn main() -> ! {
} }
} }
} }
// End of file

View file

@ -1,40 +1,72 @@
//! Blinks the LED on a Pico board //! # Pico PWM Blink Example
//! //!
//! This will fade in/out the LED attached to GP25, which is the pin the Pico uses for the on-board LED. //! Fades the LED on a Pico board using the PWM peripheral.
//!
//! This will fade in/out the LED attached to GP25, which is the pin the Pico
//! uses for the on-board LED.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
#![no_std] #![no_std]
#![no_main] #![no_main]
// The macro for our start-up function
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embedded_hal::PwmPin;
use embedded_time::fixed_point::FixedPoint;
use panic_halt as _;
use pico::{
hal::{
clocks::{init_clocks_and_plls, Clock},
pac,
pwm::*,
watchdog::Watchdog,
},
Pins, XOSC_CRYSTAL_FREQ,
};
use rp2040_hal::sio::Sio;
// GPIO traits
use embedded_hal::PwmPin;
// Time handling traits
use embedded_time::rate::*;
// Ensure we halt the program on panic (if we don't mention this crate it won't
// be linked)
use panic_halt as _;
// Pull in any important traits
use pico::hal::prelude::*;
// A shorter alias for the Peripheral Access Crate, which provides low-level
// register access
use pico::hal::pac;
// A shorter alias for the Hardware Abstraction Layer, which provides
// higher-level drivers.
use pico::hal;
/// The linker will place this boot block at the start of our program image. We
/// need this to help the ROM bootloader get our code up and running.
#[link_section = ".boot2"] #[link_section = ".boot2"]
#[used] #[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
// The minimum PWM value (i.e. LED brightness) we want
const LOW: u16 = 0; const LOW: u16 = 0;
// The maximum PWM value (i.e. LED brightness) we want
const HIGH: u16 = 25000; const HIGH: u16 = 25000;
/// Entry point to our bare-metal application.
///
/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
/// as soon as all global variables are initialised.
///
/// The function configures the RP2040 peripherals, then fades the LED in an
/// infinite loop.
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
// Grab our singleton objects
let mut pac = pac::Peripherals::take().unwrap(); let mut pac = pac::Peripherals::take().unwrap();
let core = pac::CorePeripherals::take().unwrap(); let core = pac::CorePeripherals::take().unwrap();
let mut watchdog = Watchdog::new(pac.WATCHDOG); // Set up the watchdog driver - needed by the clock setup code
let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks_and_plls( // Configure the clocks
XOSC_CRYSTAL_FREQ, //
// Our default is 12 MHz crystal input, 125 MHz system clock
let clocks = hal::clocks::init_clocks_and_plls(
pico::XOSC_CRYSTAL_FREQ,
pac.XOSC, pac.XOSC,
pac.CLOCKS, pac.CLOCKS,
pac.PLL_SYS, pac.PLL_SYS,
@ -45,34 +77,42 @@ fn main() -> ! {
.ok() .ok()
.unwrap(); .unwrap();
let sio = Sio::new(pac.SIO); // The single-cycle I/O block controls our GPIO pins
let pins = Pins::new( let sio = hal::sio::Sio::new(pac.SIO);
// Set the pins up according to their function on this particular board
let pins = pico::Pins::new(
pac.IO_BANK0, pac.IO_BANK0,
pac.PADS_BANK0, pac.PADS_BANK0,
sio.gpio_bank0, sio.gpio_bank0,
&mut pac.RESETS, &mut pac.RESETS,
); );
// The delay object lets us wait for specified amounts of time (in
// milliseconds)
let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer()); let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer());
// Init PWMs // Init PWMs
let mut pwm_slices = Slices::new(pac.PWM, &mut pac.RESETS); let mut pwm_slices = hal::pwm::Slices::new(pac.PWM, &mut pac.RESETS);
// Configure PWM4 // Configure PWM4
let pwm = &mut pwm_slices.pwm4; let pwm = &mut pwm_slices.pwm4;
pwm.set_ph_correct(); pwm.set_ph_correct();
pwm.enable(); pwm.enable();
// Use B channel (which outputs to GPIO 25) // Output channel B on PWM4 to the LED pin
let channel = &mut pwm.channel_b; let channel = &mut pwm.channel_b;
channel.output_to(pins.led); channel.output_to(pins.led);
// Infinite loop, fading LED up and down
loop { loop {
// Ramp brightness up
for i in (LOW..=HIGH).skip(100) { for i in (LOW..=HIGH).skip(100) {
delay.delay_us(8); delay.delay_us(8);
channel.set_duty(i); channel.set_duty(i);
} }
// Ramp brightness down
for i in (LOW..=HIGH).rev().skip(100) { for i in (LOW..=HIGH).rev().skip(100) {
delay.delay_us(8); delay.delay_us(8);
channel.set_duty(i); channel.set_duty(i);
@ -81,3 +121,5 @@ fn main() -> ! {
delay.delay_ms(500); delay.delay_ms(500);
} }
} }
// End of file

View file

@ -1,30 +1,64 @@
//! Creates a USB Serial device on a Pico board. //! # Pico USB Serial Example
//! //!
//! This will create a USB Serial device echoing anything it receives converting to caps the ASCII //! Creates a USB Serial device on a Pico board, with the USB driver running in
//! alphabetical caracters. //! the main thread.
//!
//! This will create a USB Serial device echoing anything it receives. Incoming
//! ASCII characters are converted to upercase, so you can tell it is working
//! and not just local-echo!
//!
//! See the `Cargo.toml` file for Copyright and licence details.
#![no_std] #![no_std]
#![no_main] #![no_main]
// The macro for our start-up function
use cortex_m_rt::entry; use cortex_m_rt::entry;
// Ensure we halt the program on panic (if we don't mention this crate it won't
// be linked)
use panic_halt as _; use panic_halt as _;
use pico::{
hal::{clocks::init_clocks_and_plls, pac, timer::Timer, usb::UsbBus, watchdog::Watchdog}, // A shorter alias for the Peripheral Access Crate, which provides low-level
XOSC_CRYSTAL_FREQ, // register access
}; use pico::hal::pac;
// A shorter alias for the Hardware Abstraction Layer, which provides
// higher-level drivers.
use pico::hal;
// USB Device support
use usb_device::{class_prelude::*, prelude::*}; use usb_device::{class_prelude::*, prelude::*};
// USB Communications Class Device support
use usbd_serial::SerialPort; use usbd_serial::SerialPort;
/// The linker will place this boot block at the start of our program image. We
/// need this to help the ROM bootloader get our code up and running.
#[link_section = ".boot2"] #[link_section = ".boot2"]
#[used] #[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
/// Entry point to our bare-metal application.
///
/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
/// as soon as all global variables are initialised.
///
/// The function configures the RP2040 peripherals, then echoes any characters
/// received over USB Serial.
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
// Grab our singleton objects
let mut pac = pac::Peripherals::take().unwrap(); let mut pac = pac::Peripherals::take().unwrap();
let mut watchdog = Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks_and_plls( // Set up the watchdog driver - needed by the clock setup code
XOSC_CRYSTAL_FREQ, let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG);
// Configure the clocks
//
// Our default is 12 MHz crystal input, 125 MHz system clock
let clocks = hal::clocks::init_clocks_and_plls(
pico::XOSC_CRYSTAL_FREQ,
pac.XOSC, pac.XOSC,
pac.CLOCKS, pac.CLOCKS,
pac.PLL_SYS, pac.PLL_SYS,
@ -35,15 +69,19 @@ fn main() -> ! {
.ok() .ok()
.unwrap(); .unwrap();
let timer = Timer::new(pac.TIMER); // Set up the USB driver
let usb_bus = UsbBusAllocator::new(UsbBus::new( let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new(
pac.USBCTRL_REGS, pac.USBCTRL_REGS,
pac.USBCTRL_DPRAM, pac.USBCTRL_DPRAM,
clocks.usb_clock, clocks.usb_clock,
true, true,
&mut pac.RESETS, &mut pac.RESETS,
)); ));
// Set up the USB Communications Class Device driver
let mut serial = SerialPort::new(&usb_bus); let mut serial = SerialPort::new(&usb_bus);
// Create a USB device with a fake VID and PID
let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd)) let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd))
.manufacturer("Fake company") .manufacturer("Fake company")
.product("Serial port") .product("Serial port")
@ -51,36 +89,41 @@ fn main() -> ! {
.device_class(2) // from: https://www.usb.org/defined-class-codes .device_class(2) // from: https://www.usb.org/defined-class-codes
.build(); .build();
let timer = hal::timer::Timer::new(pac.TIMER);
let mut said_hello = false; let mut said_hello = false;
loop { loop {
// A welcome message at the beginning
if !said_hello && timer.get_counter() >= 2_000_000 { if !said_hello && timer.get_counter() >= 2_000_000 {
said_hello = true; said_hello = true;
let _ = serial.write(b"HelloWorld!\r\n"); let _ = serial.write(b"Hello, World!\r\n");
}
if !usb_dev.poll(&mut [&mut serial]) {
continue;
} }
// Check for new data
if usb_dev.poll(&mut [&mut serial]) {
let mut buf = [0u8; 64]; let mut buf = [0u8; 64];
let _ = serial.read(&mut buf).map(|count| { match serial.read(&mut buf) {
if count == 0 { Err(_e) => {
return; // Do nothing
} }
Ok(0) => {
// Echo back in upper case // Do nothing
buf.iter_mut().take(count).for_each(|c| {
if let 0x61..=0x7a = *c {
*c &= !0x20;
} }
Ok(count) => {
// Convert to upper case
buf.iter_mut().take(count).for_each(|b| {
b.make_ascii_uppercase();
}); });
// Send back to the host
let mut wr_ptr = &buf[..count]; let mut wr_ptr = &buf[..count];
while !wr_ptr.is_empty() { while !wr_ptr.is_empty() {
let _ = serial.write(wr_ptr).map(|len| { let _ = serial.write(wr_ptr).map(|len| {
wr_ptr = &wr_ptr[len..]; wr_ptr = &wr_ptr[len..];
}); });
} }
}); }
}
}
} }
} }
// End of file

View file

@ -1,49 +1,86 @@
//! Creates a USB Serial device on a Pico board, with the USB driver running in the USB interrupt //! # Pico USB Serial (with Interrupts) Example
//! //!
//! This will create a USB Serial device echoing anything it receives converting to caps the ASCII //! Creates a USB Serial device on a Pico board, with the USB driver running in
//! alphabetical caracters. //! the USB interrupt.
//!
//! This will create a USB Serial device echoing anything it receives. Incoming
//! ASCII characters are converted to upercase, so you can tell it is working
//! and not just local-echo!
//!
//! See the `Cargo.toml` file for Copyright and licence details.
#![no_std] #![no_std]
#![no_main] #![no_main]
use crate::pac::interrupt; // The macro for our start-up function
use cortex_m_rt::entry; use cortex_m_rt::entry;
// The macro for marking our interrupt functions
use pico::hal::pac::interrupt;
// GPIO traits
use embedded_hal::digital::v2::OutputPin;
// Time handling traits
use embedded_time::rate::*;
// Ensure we halt the program on panic (if we don't mention this crate it won't
// be linked)
use panic_halt as _; use panic_halt as _;
use pico::{
hal::{ // Pull in any important traits
self, use pico::hal::prelude::*;
clocks::{init_clocks_and_plls, Clock},
pac, // A shorter alias for the Peripheral Access Crate, which provides low-level
sio::Sio, // register access
usb::UsbBus, use pico::hal::pac;
watchdog::Watchdog,
}, // A shorter alias for the Hardware Abstraction Layer, which provides
XOSC_CRYSTAL_FREQ, // higher-level drivers.
}; use pico::hal;
// USB Device support
use usb_device::{class_prelude::*, prelude::*}; use usb_device::{class_prelude::*, prelude::*};
// USB Communications Class Device support
use usbd_serial::SerialPort; use usbd_serial::SerialPort;
/// The linker will place this boot block at the start of our program image. We
/// need this to help the ROM bootloader get our code up and running.
#[link_section = ".boot2"] #[link_section = ".boot2"]
#[used] #[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
// Static data so that it can be accessed in both main and interrupt context /// The USB Device Driver (shared with the interrupt).
static mut USB_DEVICE: Option<UsbDevice<UsbBus>> = None; static mut USB_DEVICE: Option<UsbDevice<hal::usb::UsbBus>> = None;
static mut USB_BUS: Option<UsbBusAllocator<UsbBus>> = None;
static mut USB_SERIAL: Option<SerialPort<UsbBus>> = None;
static mut SAID_HELLO: bool = false;
// Blinky-related imports, not needed for USB /// The USB Bus Driver (shared with the interrupt).
use embedded_hal::digital::v2::OutputPin; static mut USB_BUS: Option<UsbBusAllocator<hal::usb::UsbBus>> = None;
use embedded_time::rate::*;
use pico::Pins;
/// The USB Serial Device Driver (shared with the interrupt).
static mut USB_SERIAL: Option<SerialPort<hal::usb::UsbBus>> = None;
/// Entry point to our bare-metal application.
///
/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
/// as soon as all global variables are initialised.
///
/// The function configures the RP2040 peripherals, then blinks the LED in an
/// infinite loop.
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
// Grab our singleton objects
let mut pac = pac::Peripherals::take().unwrap(); let mut pac = pac::Peripherals::take().unwrap();
let mut watchdog = Watchdog::new(pac.WATCHDOG); let core = pac::CorePeripherals::take().unwrap();
let clocks = init_clocks_and_plls( // Set up the watchdog driver - needed by the clock setup code
XOSC_CRYSTAL_FREQ, let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG);
// Configure the clocks
//
// Our default is 12 MHz crystal input, 125 MHz system clock
let clocks = hal::clocks::init_clocks_and_plls(
pico::XOSC_CRYSTAL_FREQ,
pac.XOSC, pac.XOSC,
pac.CLOCKS, pac.CLOCKS,
pac.PLL_SYS, pac.PLL_SYS,
@ -54,7 +91,8 @@ fn main() -> ! {
.ok() .ok()
.unwrap(); .unwrap();
let usb_bus = UsbBusAllocator::new(UsbBus::new( // Set up the USB driver
let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new(
pac.USBCTRL_REGS, pac.USBCTRL_REGS,
pac.USBCTRL_DPRAM, pac.USBCTRL_DPRAM,
clocks.usb_clock, clocks.usb_clock,
@ -62,24 +100,30 @@ fn main() -> ! {
&mut pac.RESETS, &mut pac.RESETS,
)); ));
unsafe { unsafe {
// Note (safety): This is safe as interrupts haven't been started yet
USB_BUS = Some(usb_bus); USB_BUS = Some(usb_bus);
} }
let serial = SerialPort::new(unsafe { USB_BUS.as_ref().unwrap() }); // Grab a reference to the USB Bus allocator. We are promising to the
// compiler not to take mutable access to this global variable whilst this
// reference exists!
let bus_ref = unsafe { USB_BUS.as_ref().unwrap() };
// Set up the USB Communications Class Device driver
let serial = SerialPort::new(bus_ref);
unsafe { unsafe {
USB_SERIAL = Some(serial); USB_SERIAL = Some(serial);
} }
let usb_dev = UsbDeviceBuilder::new( // Create a USB device with a fake VID and PID
unsafe { USB_BUS.as_ref().unwrap() }, let usb_dev = UsbDeviceBuilder::new(bus_ref, UsbVidPid(0x16c0, 0x27dd))
UsbVidPid(0x16c0, 0x27dd),
)
.manufacturer("Fake company") .manufacturer("Fake company")
.product("Serial port") .product("Serial port")
.serial_number("TEST") .serial_number("TEST")
.device_class(2) // from: https://www.usb.org/defined-class-codes .device_class(2) // from: https://www.usb.org/defined-class-codes
.build(); .build();
unsafe { unsafe {
// Note (safety): This is safe as interrupts haven't been started yet
USB_DEVICE = Some(usb_dev); USB_DEVICE = Some(usb_dev);
} }
@ -88,20 +132,28 @@ fn main() -> ! {
pac::NVIC::unmask(hal::pac::Interrupt::USBCTRL_IRQ); pac::NVIC::unmask(hal::pac::Interrupt::USBCTRL_IRQ);
}; };
// No more USB code after this point in main! // No more USB code after this point in main! We can do anything we want in
// We can do anything we want in here since USB is handled // here since USB is handled in the interrupt - let's blink an LED!
// in the interrupt - let's blink an LED.
let core = pac::CorePeripherals::take().unwrap(); // The delay object lets us wait for specified amounts of time (in
// milliseconds)
let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer()); let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer());
let sio = Sio::new(pac.SIO); // The single-cycle I/O block controls our GPIO pins
let pins = Pins::new( let sio = hal::sio::Sio::new(pac.SIO);
// Set the pins up according to their function on this particular board
let pins = pico::Pins::new(
pac.IO_BANK0, pac.IO_BANK0,
pac.PADS_BANK0, pac.PADS_BANK0,
sio.gpio_bank0, sio.gpio_bank0,
&mut pac.RESETS, &mut pac.RESETS,
); );
// Set the LED to be an output
let mut led_pin = pins.led.into_push_pull_output(); let mut led_pin = pins.led.into_push_pull_output();
// Blink the LED at 1 Hz
loop { loop {
led_pin.set_high().unwrap(); led_pin.set_high().unwrap();
delay.delay_ms(500); delay.delay_ms(500);
@ -110,37 +162,55 @@ fn main() -> ! {
} }
} }
/// This function is called whenever the USB Hardware generates an Interrupt
/// Request.
///
/// We do all our USB work under interrupt, so the main thread can continue on
/// knowing nothing about USB.
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[interrupt] #[interrupt]
unsafe fn USBCTRL_IRQ() { unsafe fn USBCTRL_IRQ() {
let mut buf = [0u8; 64]; use core::sync::atomic::{AtomicBool, Ordering};
/// Note whether we've already printed the "hello" message.
static SAID_HELLO: AtomicBool = AtomicBool::new(false);
// Grab the global objects. This is OK as we only access them under interrupt.
let usb_dev = USB_DEVICE.as_mut().unwrap(); let usb_dev = USB_DEVICE.as_mut().unwrap();
let serial = USB_SERIAL.as_mut().unwrap(); let serial = USB_SERIAL.as_mut().unwrap();
if !SAID_HELLO { // Say hello exactly once on start-up
SAID_HELLO = true; if !SAID_HELLO.load(Ordering::Relaxed) {
let _ = serial.write(b"HelloWorld!\r\n"); SAID_HELLO.store(true, Ordering::Relaxed);
let _ = serial.write(b"Hello, World!\r\n");
} }
// Poll the USB driver with all of our supported USB Classes
if usb_dev.poll(&mut [serial]) { if usb_dev.poll(&mut [serial]) {
let _ = serial.read(&mut buf).map(|count| { let mut buf = [0u8; 64];
if count == 0 { match serial.read(&mut buf) {
return; Err(_e) => {
// Do nothing
} }
Ok(0) => {
// Echo back in upper case // Do nothing
buf.iter_mut().take(count).for_each(|c| {
if let 0x61..=0x7a = *c {
*c &= !0x20;
} }
Ok(count) => {
// Convert to upper case
buf.iter_mut().take(count).for_each(|b| {
b.make_ascii_uppercase();
}); });
// Send back to the host
let mut wr_ptr = &buf[..count]; let mut wr_ptr = &buf[..count];
while !wr_ptr.is_empty() { while !wr_ptr.is_empty() {
let _ = serial.write(wr_ptr).map(|len| { let _ = serial.write(wr_ptr).map(|len| {
wr_ptr = &wr_ptr[len..]; wr_ptr = &wr_ptr[len..];
}); });
} }
}); }
}
} }
} }
// End of file

View file

@ -1,39 +1,84 @@
//! # Pico USB 'Twitchy' Mouse Example
//!
//! Creates a USB HID Class Poiting device (i.e. a virtual mouse) on a Pico
//! board, with the USB driver running in the main thread.
//!
//! It generates movement reports which will twitch the cursor up and down by a
//! few pixels, several times a second.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
//!
//! This is a port of //! This is a port of
//! https://github.com/atsamd-rs/atsamd/blob/master/boards/itsybitsy_m0/examples/twitching_usb_mouse.rs //! https://github.com/atsamd-rs/atsamd/blob/master/boards/itsybitsy_m0/examples/twitching_usb_mouse.rs
#![no_std] #![no_std]
#![no_main] #![no_main]
use cortex_m::interrupt::free as disable_interrupts; // The macro for our start-up function
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embedded_time::fixed_point::FixedPoint;
// The macro for marking our interrupt functions
use pico::hal::pac::interrupt;
// Ensure we halt the program on panic (if we don't mention this crate it won't
// be linked)
use panic_halt as _; use panic_halt as _;
use pico::{
hal::{ // Pull in any important traits
self, use embedded_time::fixed_point::FixedPoint;
clocks::{init_clocks_and_plls, Clock}, use pico::hal::prelude::*;
pac::{self, interrupt},
usb::UsbBus, // A shorter alias for the Peripheral Access Crate, which provides low-level
watchdog::Watchdog, // register access
}, use pico::hal::pac;
XOSC_CRYSTAL_FREQ,
}; // A shorter alias for the Hardware Abstraction Layer, which provides
use usb_device::bus::UsbBusAllocator; // higher-level drivers.
use usb_device::prelude::*; use pico::hal;
// USB Device support
use usb_device::{class_prelude::*, prelude::*};
// USB Human Interface Device (HID) Class support
use usbd_hid::descriptor::generator_prelude::*; use usbd_hid::descriptor::generator_prelude::*;
use usbd_hid::descriptor::MouseReport; use usbd_hid::descriptor::MouseReport;
use usbd_hid::hid_class::HIDClass; use usbd_hid::hid_class::HIDClass;
/// The linker will place this boot block at the start of our program image. We
/// need this to help the ROM bootloader get our code up and running.
#[link_section = ".boot2"] #[link_section = ".boot2"]
#[used] #[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
/// The USB Device Driver (shared with the interrupt).
static mut USB_DEVICE: Option<UsbDevice<hal::usb::UsbBus>> = None;
/// The USB Bus Driver (shared with the interrupt).
static mut USB_BUS: Option<UsbBusAllocator<hal::usb::UsbBus>> = None;
/// The USB Human Interface Device Driver (shared with the interrupt).
static mut USB_HID: Option<HIDClass<hal::usb::UsbBus>> = None;
/// Entry point to our bare-metal application.
///
/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
/// as soon as all global variables are initialised.
///
/// The function configures the RP2040 peripherals, then submits cursor movement
/// updates periodically.
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
// Grab our singleton objects
let mut pac = pac::Peripherals::take().unwrap(); let mut pac = pac::Peripherals::take().unwrap();
let mut watchdog = Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks_and_plls( // Set up the watchdog driver - needed by the clock setup code
XOSC_CRYSTAL_FREQ, let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG);
// Configure the clocks
//
// Our default is 12 MHz crystal input, 125 MHz system clock
let clocks = hal::clocks::init_clocks_and_plls(
pico::XOSC_CRYSTAL_FREQ,
pac.XOSC, pac.XOSC,
pac.CLOCKS, pac.CLOCKS,
pac.PLL_SYS, pac.PLL_SYS,
@ -44,7 +89,8 @@ fn main() -> ! {
.ok() .ok()
.unwrap(); .unwrap();
let usb_bus = UsbBusAllocator::new(UsbBus::new( // Set up the USB driver
let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new(
pac.USBCTRL_REGS, pac.USBCTRL_REGS,
pac.USBCTRL_DPRAM, pac.USBCTRL_DPRAM,
clocks.usb_clock, clocks.usb_clock,
@ -52,67 +98,79 @@ fn main() -> ! {
&mut pac.RESETS, &mut pac.RESETS,
)); ));
unsafe { unsafe {
// Note (safety): This is safe as interrupts haven't been started yet
USB_BUS = Some(usb_bus); USB_BUS = Some(usb_bus);
} }
let usb_hid = HIDClass::new( // Grab a reference to the USB Bus allocator. We are promising to the
unsafe { USB_BUS.as_ref().unwrap() }, // compiler not to take mutable access to this global variable whilst this
MouseReport::desc(), // reference exists!
60, let bus_ref = unsafe { USB_BUS.as_ref().unwrap() };
);
// Set up the USB HID Class Device driver, providing Mouse Reports
let usb_hid = HIDClass::new(bus_ref, MouseReport::desc(), 60);
unsafe { unsafe {
// Note (safety): This is safe as interrupts haven't been started yet.
USB_HID = Some(usb_hid); USB_HID = Some(usb_hid);
} }
let usb_dev = UsbDeviceBuilder::new( // Create a USB device with a fake VID and PID
unsafe { USB_BUS.as_ref().unwrap() }, let usb_dev = UsbDeviceBuilder::new(bus_ref, UsbVidPid(0x16c0, 0x27da))
UsbVidPid(0x16c0, 0x27dd),
)
.manufacturer("Fake company") .manufacturer("Fake company")
.product("Twitchy Mousey") .product("Twitchy Mousey")
.serial_number("TEST") .serial_number("TEST")
.device_class(0xEF) // misc .device_class(0xEF) // misc
.build(); .build();
unsafe { unsafe {
// Note (safety): This is safe as interrupts haven't been started yet
USB_DEVICE = Some(usb_dev); USB_DEVICE = Some(usb_dev);
} }
unsafe { unsafe {
// Enable the USB interrupt
pac::NVIC::unmask(hal::pac::Interrupt::USBCTRL_IRQ); pac::NVIC::unmask(hal::pac::Interrupt::USBCTRL_IRQ);
}; };
let core = pac::CorePeripherals::take().unwrap(); let core = pac::CorePeripherals::take().unwrap();
let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer()); let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer());
// Move the cursor up and down every 200ms
loop { loop {
delay.delay_ms(100); delay.delay_ms(100);
push_mouse_movement(MouseReport {
let rep_up = MouseReport {
x: 0, x: 0,
y: 4, y: 4,
buttons: 0, buttons: 0,
wheel: 0, wheel: 0,
}) };
.ok() push_mouse_movement(rep_up).ok().unwrap_or(0);
.unwrap_or(0);
delay.delay_ms(100); delay.delay_ms(100);
push_mouse_movement(MouseReport {
let rep_down = MouseReport {
x: 0, x: 0,
y: -4, y: -4,
buttons: 0, buttons: 0,
wheel: 0, wheel: 0,
}) };
.ok() push_mouse_movement(rep_down).ok().unwrap_or(0);
.unwrap_or(0);
} }
} }
static mut USB_DEVICE: Option<UsbDevice<UsbBus>> = None; /// Submit a new mouse movement report to the USB stack.
static mut USB_BUS: Option<UsbBusAllocator<UsbBus>> = None; ///
static mut USB_HID: Option<HIDClass<UsbBus>> = None; /// We do this with interrupts disabled, to avoid a race hazard with the USB IRQ.
fn push_mouse_movement(report: MouseReport) -> Result<usize, usb_device::UsbError> { fn push_mouse_movement(report: MouseReport) -> Result<usize, usb_device::UsbError> {
disable_interrupts(|_| unsafe { USB_HID.as_mut().map(|hid| hid.push_input(&report)) }).unwrap() cortex_m::interrupt::free(|_| unsafe {
// Now interrupts are disabled, grab the global variable and, if
// available, send it a HID report
USB_HID.as_mut().map(|hid| hid.push_input(&report))
})
.unwrap()
} }
/// This function is called whenever the USB Hardware generates an Interrupt
/// Request.
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[interrupt] #[interrupt]
unsafe fn USBCTRL_IRQ() { unsafe fn USBCTRL_IRQ() {
@ -121,3 +179,5 @@ unsafe fn USBCTRL_IRQ() {
let usb_hid = USB_HID.as_mut().unwrap(); let usb_hid = USB_HID.as_mut().unwrap();
usb_dev.poll(&mut [usb_hid]); usb_dev.poll(&mut [usb_hid]);
} }
// End of file

View file

@ -1 +1,95 @@
Pimoroni Pico Explorer Board Support Crate # [pico_explorer] - Board Support for the [Pimoroni Pico Explorer]
You should include this crate if you are writing code that you want to run on
a [Pimoroni Pico Explorer] - a board featuring a small LCD screen, a
breadboard and some breakout headers.
This crate includes the [rp2040-hal], but also configures each pin of the
RP2040 chip according to how it is connected up on the Pico Explorer.
[Pimoroni Pico Explorer]: https://shop.pimoroni.com/products/pico-explorer-base
[pico_explorer]: https://github.com/rp-rs/rp-hal/tree/main/boards/pico_explorer
[rp2040-hal]: https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal
[Raspberry Pi Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/
## Using
To use this crate, your `Cargo.toml` file should contain:
```toml
pico_explorer = { git = "https://github.com/rp-rs/rp-hal.git" }
```
In your program, you will need to call `pico_explorer::Pins::new` to create
a new `Pins` structure. This will set up all the GPIOs for any on-board
devices. See the [examples](./examples) folder for more details.
## Examples
### General Instructions
To compile an example, clone the _rp-hal_ repository and run:
```console
rp-hal/boards/pico_explorer $ cargo build --release --example <name>
```
You will get an ELF file called
`./target/thumbv6m-none-eabi/release/examples/<name>`, where the `target`
folder is located at the top of the _rp-hal_ repository checkout. Normally
you would also need to specify `--target=thumbv6m-none-eabi` but when
building examples from this git repository, that is set as the default.
If you want to convert the ELF file to a UF2 and automatically copy it to the
USB drive exported by the RP2040 bootloader, simply boot your board into
bootloader mode and run:
```console
rp-hal/boards/pico_explorer $ cargo run --release --example <name>
```
If you get an error about not being able to find `elf2uf2-rs`, try:
```console
$ cargo install elf2uf2-rs, then repeating the `cargo run` command above.
```
### [pico_explorer_showcase](./examples/pico_explorer_showcase.rs)
Displays the current temperature on the Pico Explorer's on-board LCD screen.
## Contributing
Contributions are what make the open source community such an amazing place to
be learn, inspire, and create. Any contributions you make are **greatly
appreciated**.
The steps are:
1. Fork the Project by clicking the 'Fork' button at the top of the page.
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
3. Make some changes to the code or documentation.
4. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
5. Push to the Feature Branch (`git push origin feature/AmazingFeature`)
6. Create a [New Pull Request](https://github.com/rp-rs/rp-hal/pulls)
7. An admin will review the Pull Request and discuss any changes that may be required.
8. Once everyone is happy, the Pull Request can be merged by an admin, and your work is part of our project!
## Code of Conduct
Contribution to this crate is organized under the terms of the [Rust Code of
Conduct][CoC], and the maintainer of this crate, the [rp-rs team], promises
to intervene to uphold that code of conduct.
[CoC]: CODE_OF_CONDUCT.md
[rp-rs team]: https://github.com/orgs/rp-rs/teams/rp-rs
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -14,6 +14,15 @@ cortex-m = "0.7.2"
rp2040-hal = { path = "../../rp2040-hal", version = "0.2.0"} rp2040-hal = { path = "../../rp2040-hal", version = "0.2.0"}
cortex-m-rt = { version = "0.7", optional = true } cortex-m-rt = { version = "0.7", optional = true }
[dev-dependencies]
embedded-time = "0.12.0"
panic-halt= "0.2.0"
embedded-hal ="0.2.5"
cortex-m-rtic = "0.6.0-alpha.5"
rp2040-boot2 = "0.1.2"
nb = "1.0"
[features] [features]
default = ["rt"] default = ["rt"]
rt = ["cortex-m-rt","rp2040-hal/rt"] rt = ["cortex-m-rt","rp2040-hal/rt"]

View file

@ -1 +1,96 @@
Pimoroni Pico Lipo 16mb Board Support Crate # [pico_lipo_16mb] - Board Support for the [Pimoroni Pico Lipo 16MB]
You should include this crate if you are writing code that you want to run on
a [Pimoroni Pico Lipo 16MB] - a board with USB-C, STEMMA QT/Qwiic connectors,
plus a Li-Po battery charging circuit.
This crate includes the [rp2040-hal], but also configures each pin of the
RP2040 chip according to how it is connected up on the Pico Lipo.
Note that if you use this crate the compiler will expect the full 16MB flash
space, and so it may not work if you only have the 4MB variant.
[Pimoroni Pico Lipo 16MB]: https://shop.pimoroni.com/products/pimoroni-pico-lipo?variant=39335427080275
[pico_lipo_16mb]: https://github.com/rp-rs/rp-hal/tree/main/boards/pico_lipo_16mb
## Using
To use this crate, your `Cargo.toml` file should contain:
```toml
pico_lipo_16mb = { git = "https://github.com/rp-rs/rp-hal.git" }
```
In your program, you will need to call `pico_lipo_16mb::Pins::new` to create
a new `Pins` structure. This will set up all the GPIOs for any on-board
devices. See the [examples](./examples) folder for more details.
## Examples
### General Instructions
To compile an example, clone the _rp-hal_ repository and run:
```console
rp-hal/boards/pico_lipo_16mb $ cargo build --release --example <name>
```
You will get an ELF file called
`./target/thumbv6m-none-eabi/release/examples/<name>`, where the `target`
folder is located at the top of the _rp-hal_ repository checkout. Normally
you would also need to specify `--target=thumbv6m-none-eabi` but when
building examples from this git repository, that is set as the default.
If you want to convert the ELF file to a UF2 and automatically copy it to the
USB drive exported by the RP2040 bootloader, simply boot your board into
bootloader mode and run:
```console
rp-hal/boards/pico_lipo_16mb $ cargo run --release --example <name>
```
If you get an error about not being able to find `elf2uf2-rs`, try:
```console
$ cargo install elf2uf2-rs, then repeating the `cargo run` command above.
```
### [pico_lipo_16mb_blinky](./examples/pico_lipo_16mb_blinky.rs)
Flashes the Pico Lipo's on-board LED on and off.
## Contributing
Contributions are what make the open source community such an amazing place to
be learn, inspire, and create. Any contributions you make are **greatly
appreciated**.
The steps are:
1. Fork the Project by clicking the 'Fork' button at the top of the page.
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
3. Make some changes to the code or documentation.
4. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
5. Push to the Feature Branch (`git push origin feature/AmazingFeature`)
6. Create a [New Pull Request](https://github.com/rp-rs/rp-hal/pulls)
7. An admin will review the Pull Request and discuss any changes that may be required.
8. Once everyone is happy, the Pull Request can be merged by an admin, and your work is part of our project!
## Code of Conduct
Contribution to this crate is organized under the terms of the [Rust Code of
Conduct][CoC], and the maintainer of this crate, the [rp-rs team], promises
to intervene to uphold that code of conduct.
[CoC]: CODE_OF_CONDUCT.md
[rp-rs team]: https://github.com/orgs/rp-rs/teams/rp-rs
## License
The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence.
Any submissions to this project (e.g. as Pull Requests) must be made available
under these terms.

View file

@ -0,0 +1,101 @@
//! # Pimoroni Pico Lipo Blinky Example
//!
//! Blinks the LED on a Pimoroni Pico Lipo 16MB board.
//!
//! This will blink an LED attached to GPIO25, which is the pin the Pico Lipo uses
//! for the on-board LED.
//!
//! See the `Cargo.toml` file for Copyright and licence details.
#![no_std]
#![no_main]
// The macro for our start-up function
use cortex_m_rt::entry;
// GPIO traits
use embedded_hal::digital::v2::OutputPin;
// Time handling traits
use embedded_time::rate::*;
// Ensure we halt the program on panic (if we don't mention this crate it won't
// be linked)
use panic_halt as _;
// Pull in any important traits
use pico_lipo_16_mb::hal::prelude::*;
// A shorter alias for the Peripheral Access Crate, which provides low-level
// register access
use pico_lipo_16_mb::hal::pac;
// A shorter alias for the Hardware Abstraction Layer, which provides
// higher-level drivers.
use pico_lipo_16_mb::hal;
/// The linker will place this boot block at the start of our program image. We
/// need this to help the ROM bootloader get our code up and running.
#[link_section = ".boot2"]
#[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
/// Entry point to our bare-metal application.
///
/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
/// as soon as all global variables are initialised.
///
/// The function configures the RP2040 peripherals, then blinks the LED in an
/// infinite loop.
#[entry]
fn main() -> ! {
// Grab our singleton objects
let mut pac = pac::Peripherals::take().unwrap();
let core = pac::CorePeripherals::take().unwrap();
// Set up the watchdog driver - needed by the clock setup code
let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG);
// Configure the clocks
//
// Our default is 12 MHz crystal input, 125 MHz system clock
let clocks = hal::clocks::init_clocks_and_plls(
pico_lipo_16_mb::XOSC_CRYSTAL_FREQ,
pac.XOSC,
pac.CLOCKS,
pac.PLL_SYS,
pac.PLL_USB,
&mut pac.RESETS,
&mut watchdog,
)
.ok()
.unwrap();
// The delay object lets us wait for specified amounts of time (in
// milliseconds)
let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer());
// The single-cycle I/O block controls our GPIO pins
let sio = hal::sio::Sio::new(pac.SIO);
// Set the pins up according to their function on this particular board
let pins = pico_lipo_16_mb::Pins::new(
pac.IO_BANK0,
pac.PADS_BANK0,
sio.gpio_bank0,
&mut pac.RESETS,
);
// Set the LED to be an output
let mut led_pin = pins.led.into_push_pull_output();
// Blink the LED at 1 Hz
loop {
led_pin.set_high().unwrap();
delay.delay_ms(500);
led_pin.set_low().unwrap();
delay.delay_ms(500);
}
}
// End of file

View file

@ -1,6 +1,6 @@
#![no_std] #![no_std]
extern crate rp2040_hal as hal; pub use rp2040_hal as hal;
#[cfg(feature = "rt")] #[cfg(feature = "rt")]
extern crate cortex_m_rt; extern crate cortex_m_rt;

View file

@ -87,7 +87,7 @@ to intervene to uphold that code of conduct.
The contents of this repository are dual-licensed under the _MIT OR Apache The contents of this repository are dual-licensed under the _MIT OR Apache
2.0_ License. That means you can chose either the MIT licence or the 2.0_ License. That means you can chose either the MIT licence or the
Apache-2.0 when you re-use this code. See `MIT` or `APACHE2.0` for more Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more
information on each specific licence. information on each specific licence.
Any submissions to this project (e.g. as Pull Requests) must be made available Any submissions to this project (e.g. as Pull Requests) must be made available

View file

@ -1 +1,2 @@
//! Prelude //! Prelude
pub use crate::clocks::Clock as _rphal_clocks_Clock;