mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2024-12-24 05:01:31 +11:00
Merge pull request #128 from 42-technology-ltd/update-pico-examples
Update Pico BSP examples
This commit is contained in:
commit
58242bcc00
|
@ -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
|
||||
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.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
||||
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/
|
||||
[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
|
||||
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.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
|
|
|
@ -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_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 _;
|
||||
use pico::{
|
||||
hal::{
|
||||
clocks::{init_clocks_and_plls, Clock},
|
||||
pac,
|
||||
sio::Sio,
|
||||
watchdog::Watchdog,
|
||||
},
|
||||
Pins, XOSC_CRYSTAL_FREQ,
|
||||
};
|
||||
|
||||
// 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"]
|
||||
#[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();
|
||||
|
||||
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(
|
||||
XOSC_CRYSTAL_FREQ,
|
||||
// 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.CLOCKS,
|
||||
pac.PLL_SYS,
|
||||
|
@ -40,17 +71,25 @@ fn main() -> ! {
|
|||
.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());
|
||||
|
||||
let sio = Sio::new(pac.SIO);
|
||||
let pins = Pins::new(
|
||||
// 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.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);
|
||||
|
@ -58,3 +97,5 @@ fn main() -> ! {
|
|||
delay.delay_ms(500);
|
||||
}
|
||||
}
|
||||
|
||||
// End of 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_main]
|
||||
|
||||
use cortex_m::prelude::_embedded_hal_timer_CountDown;
|
||||
// The macro for our start-up function
|
||||
use cortex_m_rt::entry;
|
||||
|
||||
use cortex_m::prelude::*;
|
||||
|
||||
// GPIO traits
|
||||
use embedded_hal::digital::v2::OutputPin;
|
||||
|
||||
// Traits for converting integers to amounts of time
|
||||
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 pico::{
|
||||
hal::{self as hal, clocks::init_clocks_and_plls, pac, sio::Sio, watchdog::Watchdog},
|
||||
XOSC_CRYSTAL_FREQ,
|
||||
};
|
||||
|
||||
// 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;
|
||||
|
||||
#[link_section = ".boot2"]
|
||||
#[used]
|
||||
|
@ -20,11 +39,17 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
|
|||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
// Grab our singleton objects
|
||||
let mut pac = pac::Peripherals::take().unwrap();
|
||||
let mut watchdog = Watchdog::new(pac.WATCHDOG);
|
||||
|
||||
let _clocks = init_clocks_and_plls(
|
||||
XOSC_CRYSTAL_FREQ,
|
||||
// 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::XOSC_CRYSTAL_FREQ,
|
||||
pac.XOSC,
|
||||
pac.CLOCKS,
|
||||
pac.PLL_SYS,
|
||||
|
@ -35,26 +60,32 @@ fn main() -> ! {
|
|||
.ok()
|
||||
.unwrap();
|
||||
|
||||
// Configure the Timer peripheral in count-down mode
|
||||
let timer = hal::timer::Timer::new(pac.TIMER);
|
||||
let mut count_down = timer.count_down();
|
||||
|
||||
let sio = Sio::new(pac.SIO);
|
||||
let pins = hal::gpio::Pins::new(
|
||||
// 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.PADS_BANK0,
|
||||
sio.gpio_bank0,
|
||||
&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 {
|
||||
// LED on, and wait for 500ms
|
||||
led_pin.set_high().unwrap();
|
||||
// wait for 500ms
|
||||
count_down.start(500.milliseconds());
|
||||
let _ = nb::block!(count_down.wait());
|
||||
|
||||
// LED off, and wait for 500ms
|
||||
led_pin.set_low().unwrap();
|
||||
// wait for 500ms
|
||||
count_down.start(500.milliseconds());
|
||||
let _ = nb::block!(count_down.wait());
|
||||
}
|
||||
|
|
|
@ -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
|
||||
//! to ground, as the input pin is pulled high internally by this example. When the button is
|
||||
//! pressed, the LED will turn off.
|
||||
//! Toggles the LED based on GPIO input.
|
||||
//!
|
||||
//! 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_main]
|
||||
|
||||
// The macro for our start-up function
|
||||
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"]
|
||||
#[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 just reads the button
|
||||
/// and sets the LED appropriately.
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
// Grab our singleton objects
|
||||
let mut pac = pac::Peripherals::take().unwrap();
|
||||
|
||||
let sio = Sio::new(pac.SIO);
|
||||
let pins = Pins::new(
|
||||
// Note - we don't do any clock set-up in this example. The RP2040 will run
|
||||
// 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.PADS_BANK0,
|
||||
sio.gpio_bank0,
|
||||
&mut pac.RESETS,
|
||||
);
|
||||
|
||||
// Our LED output
|
||||
let mut led_pin = pins.led.into_push_pull_output();
|
||||
|
||||
// Our button input
|
||||
let button_pin = pins.bootsel.into_pull_down_input();
|
||||
|
||||
// Run forever, setting the LED according to the button
|
||||
loop {
|
||||
if button_pin.is_low().unwrap() {
|
||||
led_pin.set_high().unwrap();
|
||||
|
@ -39,3 +77,5 @@ fn main() -> ! {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// End of 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_main]
|
||||
|
||||
// The macro for our start-up function
|
||||
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"]
|
||||
#[used]
|
||||
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
|
||||
|
||||
// The minimum PWM value (i.e. LED brightness) we want
|
||||
const LOW: u16 = 0;
|
||||
|
||||
// The maximum PWM value (i.e. LED brightness) we want
|
||||
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]
|
||||
fn main() -> ! {
|
||||
// Grab our singleton objects
|
||||
let mut pac = pac::Peripherals::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(
|
||||
XOSC_CRYSTAL_FREQ,
|
||||
// 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.CLOCKS,
|
||||
pac.PLL_SYS,
|
||||
|
@ -45,34 +77,42 @@ fn main() -> ! {
|
|||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let sio = Sio::new(pac.SIO);
|
||||
let pins = Pins::new(
|
||||
// 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.PADS_BANK0,
|
||||
sio.gpio_bank0,
|
||||
&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());
|
||||
|
||||
// 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
|
||||
let pwm = &mut pwm_slices.pwm4;
|
||||
pwm.set_ph_correct();
|
||||
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;
|
||||
channel.output_to(pins.led);
|
||||
|
||||
// Infinite loop, fading LED up and down
|
||||
loop {
|
||||
// Ramp brightness up
|
||||
for i in (LOW..=HIGH).skip(100) {
|
||||
delay.delay_us(8);
|
||||
channel.set_duty(i);
|
||||
}
|
||||
|
||||
// Ramp brightness down
|
||||
for i in (LOW..=HIGH).rev().skip(100) {
|
||||
delay.delay_us(8);
|
||||
channel.set_duty(i);
|
||||
|
@ -81,3 +121,5 @@ fn main() -> ! {
|
|||
delay.delay_ms(500);
|
||||
}
|
||||
}
|
||||
|
||||
// End of 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
|
||||
//! alphabetical caracters.
|
||||
//! Creates a USB Serial device on a Pico board, with the USB driver running in
|
||||
//! 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_main]
|
||||
|
||||
// The macro for our start-up function
|
||||
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 pico::{
|
||||
hal::{clocks::init_clocks_and_plls, pac, timer::Timer, usb::UsbBus, watchdog::Watchdog},
|
||||
XOSC_CRYSTAL_FREQ,
|
||||
};
|
||||
|
||||
// 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;
|
||||
|
||||
// USB Device support
|
||||
use usb_device::{class_prelude::*, prelude::*};
|
||||
|
||||
// USB Communications Class Device support
|
||||
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"]
|
||||
#[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 echoes any characters
|
||||
/// received over USB Serial.
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
// Grab our singleton objects
|
||||
let mut pac = pac::Peripherals::take().unwrap();
|
||||
let mut watchdog = Watchdog::new(pac.WATCHDOG);
|
||||
|
||||
let clocks = init_clocks_and_plls(
|
||||
XOSC_CRYSTAL_FREQ,
|
||||
// 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::XOSC_CRYSTAL_FREQ,
|
||||
pac.XOSC,
|
||||
pac.CLOCKS,
|
||||
pac.PLL_SYS,
|
||||
|
@ -35,15 +69,19 @@ fn main() -> ! {
|
|||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let timer = Timer::new(pac.TIMER);
|
||||
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_DPRAM,
|
||||
clocks.usb_clock,
|
||||
true,
|
||||
&mut pac.RESETS,
|
||||
));
|
||||
|
||||
// Set up the USB Communications Class Device driver
|
||||
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))
|
||||
.manufacturer("Fake company")
|
||||
.product("Serial port")
|
||||
|
@ -51,36 +89,41 @@ fn main() -> ! {
|
|||
.device_class(2) // from: https://www.usb.org/defined-class-codes
|
||||
.build();
|
||||
|
||||
let timer = hal::timer::Timer::new(pac.TIMER);
|
||||
let mut said_hello = false;
|
||||
loop {
|
||||
// A welcome message at the beginning
|
||||
if !said_hello && timer.get_counter() >= 2_000_000 {
|
||||
said_hello = true;
|
||||
let _ = serial.write(b"HelloWorld!\r\n");
|
||||
}
|
||||
|
||||
if !usb_dev.poll(&mut [&mut serial]) {
|
||||
continue;
|
||||
let _ = serial.write(b"Hello, World!\r\n");
|
||||
}
|
||||
|
||||
// Check for new data
|
||||
if usb_dev.poll(&mut [&mut serial]) {
|
||||
let mut buf = [0u8; 64];
|
||||
let _ = serial.read(&mut buf).map(|count| {
|
||||
if count == 0 {
|
||||
return;
|
||||
match serial.read(&mut buf) {
|
||||
Err(_e) => {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
// Echo back in upper case
|
||||
buf.iter_mut().take(count).for_each(|c| {
|
||||
if let 0x61..=0x7a = *c {
|
||||
*c &= !0x20;
|
||||
Ok(0) => {
|
||||
// Do nothing
|
||||
}
|
||||
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];
|
||||
while !wr_ptr.is_empty() {
|
||||
let _ = serial.write(wr_ptr).map(|len| {
|
||||
wr_ptr = &wr_ptr[len..];
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// End of 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
|
||||
//! alphabetical caracters.
|
||||
//! Creates a USB Serial device on a Pico board, with the USB driver running in
|
||||
//! 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_main]
|
||||
|
||||
use crate::pac::interrupt;
|
||||
// The macro for our start-up function
|
||||
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 pico::{
|
||||
hal::{
|
||||
self,
|
||||
clocks::{init_clocks_and_plls, Clock},
|
||||
pac,
|
||||
sio::Sio,
|
||||
usb::UsbBus,
|
||||
watchdog::Watchdog,
|
||||
},
|
||||
XOSC_CRYSTAL_FREQ,
|
||||
};
|
||||
|
||||
// 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;
|
||||
|
||||
// USB Device support
|
||||
use usb_device::{class_prelude::*, prelude::*};
|
||||
|
||||
// USB Communications Class Device support
|
||||
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"]
|
||||
#[used]
|
||||
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
|
||||
|
||||
// Static data so that it can be accessed in both main and interrupt context
|
||||
static mut USB_DEVICE: Option<UsbDevice<UsbBus>> = None;
|
||||
static mut USB_BUS: Option<UsbBusAllocator<UsbBus>> = None;
|
||||
static mut USB_SERIAL: Option<SerialPort<UsbBus>> = None;
|
||||
static mut SAID_HELLO: bool = false;
|
||||
/// The USB Device Driver (shared with the interrupt).
|
||||
static mut USB_DEVICE: Option<UsbDevice<hal::usb::UsbBus>> = None;
|
||||
|
||||
// Blinky-related imports, not needed for USB
|
||||
use embedded_hal::digital::v2::OutputPin;
|
||||
use embedded_time::rate::*;
|
||||
use pico::Pins;
|
||||
/// The USB Bus Driver (shared with the interrupt).
|
||||
static mut USB_BUS: Option<UsbBusAllocator<hal::usb::UsbBus>> = None;
|
||||
|
||||
/// 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]
|
||||
fn main() -> ! {
|
||||
// Grab our singleton objects
|
||||
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(
|
||||
XOSC_CRYSTAL_FREQ,
|
||||
// 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::XOSC_CRYSTAL_FREQ,
|
||||
pac.XOSC,
|
||||
pac.CLOCKS,
|
||||
pac.PLL_SYS,
|
||||
|
@ -54,7 +91,8 @@ fn main() -> ! {
|
|||
.ok()
|
||||
.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_DPRAM,
|
||||
clocks.usb_clock,
|
||||
|
@ -62,24 +100,30 @@ fn main() -> ! {
|
|||
&mut pac.RESETS,
|
||||
));
|
||||
unsafe {
|
||||
// Note (safety): This is safe as interrupts haven't been started yet
|
||||
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 {
|
||||
USB_SERIAL = Some(serial);
|
||||
}
|
||||
|
||||
let usb_dev = UsbDeviceBuilder::new(
|
||||
unsafe { USB_BUS.as_ref().unwrap() },
|
||||
UsbVidPid(0x16c0, 0x27dd),
|
||||
)
|
||||
// Create a USB device with a fake VID and PID
|
||||
let usb_dev = UsbDeviceBuilder::new(bus_ref, UsbVidPid(0x16c0, 0x27dd))
|
||||
.manufacturer("Fake company")
|
||||
.product("Serial port")
|
||||
.serial_number("TEST")
|
||||
.device_class(2) // from: https://www.usb.org/defined-class-codes
|
||||
.build();
|
||||
unsafe {
|
||||
// Note (safety): This is safe as interrupts haven't been started yet
|
||||
USB_DEVICE = Some(usb_dev);
|
||||
}
|
||||
|
||||
|
@ -88,20 +132,28 @@ fn main() -> ! {
|
|||
pac::NVIC::unmask(hal::pac::Interrupt::USBCTRL_IRQ);
|
||||
};
|
||||
|
||||
// No more USB code after this point in main!
|
||||
// We can do anything we want in here since USB is handled
|
||||
// in the interrupt - let's blink an LED.
|
||||
let core = pac::CorePeripherals::take().unwrap();
|
||||
// No more USB code after this point in main! We can do anything we want in
|
||||
// here since USB is handled in the interrupt - let's blink an LED!
|
||||
|
||||
// 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 sio = Sio::new(pac.SIO);
|
||||
let pins = Pins::new(
|
||||
// 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.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);
|
||||
|
@ -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)]
|
||||
#[interrupt]
|
||||
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 serial = USB_SERIAL.as_mut().unwrap();
|
||||
|
||||
if !SAID_HELLO {
|
||||
SAID_HELLO = true;
|
||||
let _ = serial.write(b"HelloWorld!\r\n");
|
||||
// Say hello exactly once on start-up
|
||||
if !SAID_HELLO.load(Ordering::Relaxed) {
|
||||
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]) {
|
||||
let _ = serial.read(&mut buf).map(|count| {
|
||||
if count == 0 {
|
||||
return;
|
||||
let mut buf = [0u8; 64];
|
||||
match serial.read(&mut buf) {
|
||||
Err(_e) => {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
// Echo back in upper case
|
||||
buf.iter_mut().take(count).for_each(|c| {
|
||||
if let 0x61..=0x7a = *c {
|
||||
*c &= !0x20;
|
||||
Ok(0) => {
|
||||
// Do nothing
|
||||
}
|
||||
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];
|
||||
while !wr_ptr.is_empty() {
|
||||
let _ = serial.write(wr_ptr).map(|len| {
|
||||
wr_ptr = &wr_ptr[len..];
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// End of 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
|
||||
//! https://github.com/atsamd-rs/atsamd/blob/master/boards/itsybitsy_m0/examples/twitching_usb_mouse.rs
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use cortex_m::interrupt::free as disable_interrupts;
|
||||
// The macro for our start-up function
|
||||
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 pico::{
|
||||
hal::{
|
||||
self,
|
||||
clocks::{init_clocks_and_plls, Clock},
|
||||
pac::{self, interrupt},
|
||||
usb::UsbBus,
|
||||
watchdog::Watchdog,
|
||||
},
|
||||
XOSC_CRYSTAL_FREQ,
|
||||
};
|
||||
use usb_device::bus::UsbBusAllocator;
|
||||
use usb_device::prelude::*;
|
||||
|
||||
// Pull in any important traits
|
||||
use embedded_time::fixed_point::FixedPoint;
|
||||
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;
|
||||
|
||||
// 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::MouseReport;
|
||||
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"]
|
||||
#[used]
|
||||
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]
|
||||
fn main() -> ! {
|
||||
// Grab our singleton objects
|
||||
let mut pac = pac::Peripherals::take().unwrap();
|
||||
let mut watchdog = Watchdog::new(pac.WATCHDOG);
|
||||
|
||||
let clocks = init_clocks_and_plls(
|
||||
XOSC_CRYSTAL_FREQ,
|
||||
// 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::XOSC_CRYSTAL_FREQ,
|
||||
pac.XOSC,
|
||||
pac.CLOCKS,
|
||||
pac.PLL_SYS,
|
||||
|
@ -44,7 +89,8 @@ fn main() -> ! {
|
|||
.ok()
|
||||
.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_DPRAM,
|
||||
clocks.usb_clock,
|
||||
|
@ -52,67 +98,79 @@ fn main() -> ! {
|
|||
&mut pac.RESETS,
|
||||
));
|
||||
unsafe {
|
||||
// Note (safety): This is safe as interrupts haven't been started yet
|
||||
USB_BUS = Some(usb_bus);
|
||||
}
|
||||
|
||||
let usb_hid = HIDClass::new(
|
||||
unsafe { USB_BUS.as_ref().unwrap() },
|
||||
MouseReport::desc(),
|
||||
60,
|
||||
);
|
||||
// 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 HID Class Device driver, providing Mouse Reports
|
||||
let usb_hid = HIDClass::new(bus_ref, MouseReport::desc(), 60);
|
||||
unsafe {
|
||||
// Note (safety): This is safe as interrupts haven't been started yet.
|
||||
USB_HID = Some(usb_hid);
|
||||
}
|
||||
|
||||
let usb_dev = UsbDeviceBuilder::new(
|
||||
unsafe { USB_BUS.as_ref().unwrap() },
|
||||
UsbVidPid(0x16c0, 0x27dd),
|
||||
)
|
||||
// Create a USB device with a fake VID and PID
|
||||
let usb_dev = UsbDeviceBuilder::new(bus_ref, UsbVidPid(0x16c0, 0x27da))
|
||||
.manufacturer("Fake company")
|
||||
.product("Twitchy Mousey")
|
||||
.serial_number("TEST")
|
||||
.device_class(0xEF) // misc
|
||||
.build();
|
||||
unsafe {
|
||||
// Note (safety): This is safe as interrupts haven't been started yet
|
||||
USB_DEVICE = Some(usb_dev);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// Enable the USB interrupt
|
||||
pac::NVIC::unmask(hal::pac::Interrupt::USBCTRL_IRQ);
|
||||
};
|
||||
let core = pac::CorePeripherals::take().unwrap();
|
||||
let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer());
|
||||
|
||||
// Move the cursor up and down every 200ms
|
||||
loop {
|
||||
delay.delay_ms(100);
|
||||
push_mouse_movement(MouseReport {
|
||||
|
||||
let rep_up = MouseReport {
|
||||
x: 0,
|
||||
y: 4,
|
||||
buttons: 0,
|
||||
wheel: 0,
|
||||
})
|
||||
.ok()
|
||||
.unwrap_or(0);
|
||||
};
|
||||
push_mouse_movement(rep_up).ok().unwrap_or(0);
|
||||
|
||||
delay.delay_ms(100);
|
||||
push_mouse_movement(MouseReport {
|
||||
|
||||
let rep_down = MouseReport {
|
||||
x: 0,
|
||||
y: -4,
|
||||
buttons: 0,
|
||||
wheel: 0,
|
||||
})
|
||||
.ok()
|
||||
.unwrap_or(0);
|
||||
};
|
||||
push_mouse_movement(rep_down).ok().unwrap_or(0);
|
||||
}
|
||||
}
|
||||
|
||||
static mut USB_DEVICE: Option<UsbDevice<UsbBus>> = None;
|
||||
static mut USB_BUS: Option<UsbBusAllocator<UsbBus>> = None;
|
||||
static mut USB_HID: Option<HIDClass<UsbBus>> = None;
|
||||
|
||||
/// Submit a new mouse movement report to the USB stack.
|
||||
///
|
||||
/// 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> {
|
||||
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)]
|
||||
#[interrupt]
|
||||
unsafe fn USBCTRL_IRQ() {
|
||||
|
@ -121,3 +179,5 @@ unsafe fn USBCTRL_IRQ() {
|
|||
let usb_hid = USB_HID.as_mut().unwrap();
|
||||
usb_dev.poll(&mut [usb_hid]);
|
||||
}
|
||||
|
||||
// End of 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.
|
||||
|
|
|
@ -14,6 +14,15 @@ cortex-m = "0.7.2"
|
|||
rp2040-hal = { path = "../../rp2040-hal", version = "0.2.0"}
|
||||
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]
|
||||
default = ["rt"]
|
||||
rt = ["cortex-m-rt","rp2040-hal/rt"]
|
|
@ -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.
|
||||
|
|
101
boards/pico_lipo_16mb/examples/pico_lipo_16mb_blinky.rs
Normal file
101
boards/pico_lipo_16mb/examples/pico_lipo_16mb_blinky.rs
Normal 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
|
|
@ -1,6 +1,6 @@
|
|||
#![no_std]
|
||||
|
||||
extern crate rp2040_hal as hal;
|
||||
pub use rp2040_hal as hal;
|
||||
|
||||
#[cfg(feature = "rt")]
|
||||
extern crate cortex_m_rt;
|
||||
|
|
|
@ -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
|
||||
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.
|
||||
|
||||
Any submissions to this project (e.g. as Pull Requests) must be made available
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
//! Prelude
|
||||
pub use crate::clocks::Clock as _rphal_clocks_Clock;
|
||||
|
|
Loading…
Reference in a new issue