Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Copy pico_i2c_pio example from rp-hal #6

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#
# Cargo Configuration for the https://github.com/rp-rs/rp-hal.git repository.
#
# Copyright (c) The RP-RS Developers, 2021
#
# The copy in this repository is only used for compiling examples.
#
# This file is MIT or Apache-2.0 as per the repository README.md file
#

[build]
# Set the default target to match the Cortex-M0+ in the RP2040
target = "thumbv6m-none-eabi"

# Target specific options
[target.thumbv6m-none-eabi]
# Pass some extra options to rustc, some of which get passed on to the linker.
#
# * linker argument --nmagic turns off page alignment of sections (which saves
# flash space)
# * linker argument -Tlink.x tells the linker to use link.x as the linker
# script. This is usually provided by the cortex-m-rt crate, and by default
# the version in that crate will include a file called `memory.x` which
# describes the particular memory layout for your specific chip.
# * inline-threshold=5 makes the compiler more aggressive and inlining functions
# * no-vectorize-loops turns off the loop vectorizer (seeing as the M0+ doesn't
# have SIMD)
rustflags = [
"-C", "link-arg=--nmagic",
"-C", "link-arg=-Tlink.x",
"-C", "inline-threshold=5",
"-C", "no-vectorize-loops",
]

# This runner will make a UF2 file and then copy it to a mounted RP2040 in USB
# Bootloader mode:
runner = "elf2uf2-rs -d"

# This runner will find a supported SWD debug probe and flash your RP2040 over
# SWD:
# runner = "probe-run --chip RP2040"
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ embedded-time = "0.12.0"
nb = "1.0.0"
pio = "0.2.0"
rp2040-hal = "0.4.0"

[dev-dependencies]
panic-halt= "0.2.0"
rp-pico = "0.3.0"
cortex-m-rt = { version = "0.7" }
156 changes: 156 additions & 0 deletions examples/pico_i2c_pio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
//! # Pico I2C PIO Example
//!
//! Reads the temperature from an LM75B
//!
//! This read over I2C the temerature from an LM75B temperature sensor wired on pins 20 and 21
//! using the PIO peripheral as an I2C bus controller.
//! The pins used for the I2C can be remapped to any other pin available to the PIO0 peripheral.
//!
//! See the `Cargo.toml` file for Copyright and license details.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC the example was originally written by you, @ithinuel, so I guess this line still applies even after moving the example here.

Copy link
Member

@ithinuel ithinuel May 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's correct.

https://github.com/rp-rs/rp-hal/commits/main/boards/rp-pico/examples/pico_i2c_pio.rs shows there has been some changes from @jonathanpallant and @VictorKoenders. We may need approval from them as well ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My change was only to update the uart API


#![no_std]
#![no_main]

// The trait used by formatting macros like write! and writeln!
use core::fmt::Write as FmtWrite;

// The macro for our start-up function
use cortex_m_rt::entry;

// I2C HAL traits & Types.
use embedded_hal::blocking::i2c::{Operation, Read, Transactional, Write};

// 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 rp_pico::hal::prelude::*;

// A shorter alias for the Peripheral Access Crate, which provides low-level
// register access
use rp_pico::hal::pac;

// A shorter alias for the Hardware Abstraction Layer, which provides
// higher-level drivers.
use rp_pico::hal;

/// Prints the temperature received from the sensor
fn print_temperature(serial: &mut impl FmtWrite, temp: [u8; 2]) {
let temp_i16 = i16::from_be_bytes(temp) >> 5;
let temp_f32 = f32::from(temp_i16) * 0.125;

// Write formatted output but ignore any error.
let _ = writeln!(serial, "Temperature: {:0.2}°C", temp_f32);
}

/// 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, reads the temperature from
/// the attached LM75B using PIO0.
#[entry]
fn main() -> ! {
// Grab our singleton objects
let mut pac = pac::Peripherals::take().unwrap();

// Set up the watchdog driver - needed by the clock setup code
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);

// Configure the clocks
//
// The default is to generate a 125 MHz system clock
let clocks = hal::clocks::init_clocks_and_plls(
rp_pico::XOSC_CRYSTAL_FREQ,
pac.XOSC,
pac.CLOCKS,
pac.PLL_SYS,
pac.PLL_USB,
&mut pac.RESETS,
&mut watchdog,
)
.ok()
.unwrap();

// The single-cycle I/O block controls our GPIO pins
let sio = hal::Sio::new(pac.SIO);

// Set the pins up according to their function on this particular board
let pins = rp_pico::Pins::new(
pac.IO_BANK0,
pac.PADS_BANK0,
sio.gpio_bank0,
&mut pac.RESETS,
);

let uart_pins = (
// UART TX (characters sent from RP2040) on pin 1 (GPIO0)
pins.gpio0.into_mode::<hal::gpio::FunctionUart>(),
// UART RX (characters received by RP2040) on pin 2 (GPIO1)
pins.gpio1.into_mode::<hal::gpio::FunctionUart>(),
);

let mut uart = hal::uart::UartPeripheral::new(pac.UART0, uart_pins, &mut pac.RESETS)
.enable(
hal::uart::common_configs::_115200_8_N_1,
clocks.peripheral_clock.into(),
)
.unwrap();

let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS);

let mut i2c_pio = i2c_pio::I2C::new(
&mut pio,
pins.gpio20,
pins.gpio21,
sm0,
100_000.Hz(),
clocks.system_clock.freq(),
);

let mut temp = [0; 2];
i2c_pio
.read(0x48u8, &mut temp)
.expect("Failed to read from the peripheral");
print_temperature(&mut uart, temp);

i2c_pio
.write(0x48u8, &[0])
.expect("Failed to write to the peripheral");

let mut temp = [0; 2];
i2c_pio
.read(0x48u8, &mut temp)
.expect("Failed to read from the peripheral");
print_temperature(&mut uart, temp);

let mut config = [0];
let mut thyst = [0; 2];
let mut tos = [0; 2];
let mut temp = [0; 2];
let mut operations = [
Operation::Write(&[1]),
Operation::Read(&mut config),
Operation::Write(&[2]),
Operation::Read(&mut thyst),
Operation::Write(&[3]),
Operation::Read(&mut tos),
Operation::Write(&[0]),
Operation::Read(&mut temp),
];
i2c_pio
.exec(0x48u8, &mut operations)
.expect("Failed to run all operations");
print_temperature(&mut uart, temp);

loop {
cortex_m::asm::nop();
}
}

// End of file
17 changes: 17 additions & 0 deletions memory.x
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* This file is only used for compiling examples */

MEMORY {
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
RAM : ORIGIN = 0x20000000, LENGTH = 256K
}

EXTERN(BOOT2_FIRMWARE)

SECTIONS {
/* ### Boot loader */
.boot2 ORIGIN(BOOT2) :
{
KEEP(*(.boot2));
} > BOOT2
} INSERT BEFORE .text;