rp-rs / rp-hal Goto Github PK
View Code? Open in Web Editor NEWA Rust Embedded-HAL for the rp series microcontrollers
Home Page: https://crates.io/crates/rp2040-hal
A Rust Embedded-HAL for the rp series microcontrollers
Home Page: https://crates.io/crates/rp2040-hal
The clock systems are described in chapter 1.15 of the datasheet.
The clock block provides clocks to all parts of the SoC. Thus it defines how much time equals one clock cycle for different parts of the chip.
Clock glitches need to be avoided when changing the clock source, see chapter 2.15.3.2.
Also changing the clock speed will affect all connected components. E. g. halfing the divider for clk_peri
would double the baud rate of a running UART.
freeze
ing the clock speed. This should consume the clock path so it can not be changed while a device is using it. Example: stm32f30x-hal, also this blog article. But maybe there should be a way to get back control over the clock speeds.let p = rp2040::peripherals.take();
let mut resets = p.RESET;
let xosc = p.XOSC.with_osc(12.mhz());
let sys_pll = p.SYS_PLL
.input(xosc)
.output(125.mhz())
.freeze();
let clk_peri = p.CLK_PERI
.source(sys_pll.clone()) // Switching source() should be done with all the needed ceremony against glitches
.divide_by(42)
.enable()
.freeze();
let uart = p.UART0
.enable(&mut resets) // Lift reset and wait for ack, see chapter 2.14
.clk(clk_peri)
.baudrate(9600)
.finish();
uart.write_all("Hello world!");
Hi there,
I would be interested to help with this to learn more about Rust on embedded. However, it doesn't look like there is active progress here at the moment. Are you expectingg this project to take up activity again, or is it stalled for now?
And if I were to try to continue here. Which issue or PR should be the first thing to look into? I see there are two draft PRs. I would assume, they need more work to get merged? If so, what is missing?
Thanks 👋
We have no examples documenting usage of the watchdog peripheral.
It would be good to have a basic doc-example in watchdog.rs, and a complete example in the HAL
https://docs.rs/rp2040-hal/0.2.0/rp2040_hal/watchdog/index.html
In the current i2c implementation there are several asserts relating to buffer sizes, invalid addresses.
Line 255 in ee5e6ee
Need to validate that these are all necessary (with appropriate testing and documentation)
Also, rather than panic at runtime these should ideally be compile-time errors, or return appropriate error types that the caller can handle.
USB is described in section 4.1 of the datasheet.
I've started working on USB support, with the goal of a RP2040 driver for usb-device.
the blinky example in rp2040-hal doesn't seem to work. the example compiled just fine. and after converting it to .uf2 and move it to a pico board, the led on pin 25 doesn't blink at all.
It feels a bit weird that they are left hanging
let _spi_sclk = pins.gpio6.into_mode::<FunctionSpi>();
let _spi_mosi = pins.gpio7.into_mode::<FunctionSpi>();
let _spi_miso = pins.gpio4.into_mode::<FunctionSpi>();
let mut spi = Spi::<_, _, 8>::new(pac.SPI0).init(
&mut pac.RESETS,
SYS_HZ.Hz(),
16_000_000u32.Hz(),
&MODE_0,
);
Compare to i2c:
let sda_pin = pins.gpio18.into_mode::<FunctionI2C>();
let scl_pin = pins.gpio19.into_mode::<FunctionI2C>();
let mut i2c = I2C::i2c1(
peripherals.I2C1,
sda_pin,
scl_pin,
400.kHz(),
&mut peripherals.RESETS,
125_000_000.Hz(),
);
If this is desired i can implement it!
I have started trying to use RTIC v0.6.x with this hal with limited success. It would be great to have an example using RTIC with an external interrupt.
If someone has already done this in another project I would be happy to write the example, but my current work is failing.
Implement the DMA api for all the peripherals 📝
There are two SPI interfaces described in section 4.4 of the datasheet
Both interfaces support:
In pwm.rs
I saw:
pad.gpio[self.pin].write(|w| w.ie().set_bit());
pad.gpio[self.pin].write(|w| w.od().clear_bit());
My understanding of write
is that it does:
let w = register.defaults();
let w = closure(w);
register.set_bits(w);
So the second line (clearing od
) will undo the effects of the first. This should probably be:
pad.gpio[self.pin].modify(|_r, w| {
w.ie.set_bit();
w.od.clear_bit();
w
});
Does the bootrom table lookup code work? It's just that according to Datasheet section 2.8.3, the Bootrom stores the table addresses as 16-bit values - these need to be read as 16-bit values, then expanded to 32-bit, then converted to the appropriate pointer. I suspect the code as written will read 32-bits from the bootrom, and get thus get the pointer very wrong.
Now that we've landed PIO support, we should get a basic example up and going showing how to use it.
This is separate to any other, complex examples using PIO for specific tasks too.
Thinking about the benefits of switching to rust from c/c++ for the pico, a few basic things stand out as downsides to rust. The C/C++ SDK links the standard / and % operators to the onboard hardware divider. Im not 100% sure on the internals of the rust arm compiler and the HAL/PAC for the rp2040 but assumedly, unless manually implemented, the rust compiler will not be able to correctly use the hardware divider. This is most definitely the same with the firmware float implementations. Both of these additions would let rust programs be able to fully take over the full power of the rp2040 chip that currently is exclusive to the standard C/C++ SDK and Micropython implementation.
I found https://github.com/jannic/rp-microcontroller-rs, but I couldn't think of how else to let this group know :)
I would urge you to reach out and collaborate!
We have a HAL example for GPIO
https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/examples/gpio_in_out.rs
And some docs and examples in the pin documentation linked from the GPIO page
https://docs.rs/rp2040-hal/0.2.0/rp2040_hal/gpio/pin/index.html
It would be good to have some clear, basic examples of GPIO usage itself in gpio.rs
https://docs.rs/rp2040-hal/0.2.0/rp2040_hal/gpio/index.html
Collected suggested improvements from #31:
selfaux_source
macro. See: #31 (comment)set_self_aux_src
await_select
is a bit of a pain from a user perspective, as it requires knowing the internal clock number. Clock source switches probably should return a type that you can call await
on. See: #31 (comment)It looks like watchdog is configured incorrectly in init_clocks_and_plls
rp-hal/rp2040-hal/src/clocks/mod.rs
Line 320 in ffa9784
in datasheet it is that it should work at 1MHz (and alarms are using the same clock), therefore this should be set here to:
(xosc_crystal_freq / 1_000_000) as u8
currently it is trying write very big number (12MHz) to 8bits and as it is truncated it sets it to garbage value
There may be cases where you are using pioasm to compile your PIO code and you want to load a compiled PIO program into your Rust code (maybe also loading the same compiled PIO program in a C program).
We should have an example on how to do that.
Cargo.toml has a broken link, so the homepage link on crates.io gives a 404
After merging PR #29 we started running cargo test
on the CI host
This CI stage started failing on #24 with error message: Error: language item required, but not found: eh_personality
Link to CI failure https://github.com/rp-rs/rp-hal/pull/24/checks?check_run_id=2498172416
We would like to run tests that exercise embedded_hal traits, but these will not run in CI without providing them.
I could not find any other HAL attempting to run cargo test on the hosts CI, there are security/reliability issues with running HIL(hardware-in-loop) with CI on one of the developers systems, and I don't think linux-embedded-hal is sufficiently advanced that we can use it for this purpose.
My current proposal is that we stop running cargo test
as part of CI until we can determine how to do so without causing more harm than good.
I've created a PR #32 that does that, as well as breaking our current CI workload into multiple workflows to aid discovery
The datasheet covers GPIOs in chapter 2.19. The chips has two IO banks, bank 1 is used for the QSPI flash which could be covered separately. This issue covers IO bank 0 which can be used for general purpose IO.
The GPIOs can be used for these functions (chapter 2.19.2):
The following settings can be changed for each pin (chapter 2.19.4):
The input buffer and output driver can be disabled (which is mandatory when used with the ADC (chapter 4.9.1)).
To make it harder to misuse we could add the following as type parameters (similar to NRF HAL and the embedded book):
All pins have the same configurations listed above. So a trait that covers all these settings could make sense.
ToDo...
This is important to get the full power of the RP2040. However, there's a major issue, which is that symmetric multiprocessing is explicitly unsound in embedded Rust.
If you are working with the Pico SDK, you might have some PIO code written out in a .pio file. We should have an example of some Rust code that can load the .pio file at compile time.
See Chapter 4 Section 3 of the datasheet for more information.
Each I2C controller is based on a configuration of the Synopsys DW_apb_i2c (v2.01) IP. The following features are supported:
•Master or Slave (Default to Master mode)
•Standard mode, Fast mode or Fast mode plus
•Default slave address 0x055
•Supports 10-bit addressing in Master mode
•16-element transmit buffer
•16-element receive buffer
•Can be driven from DMA
•Can generate interrupts
Awaits #4
Currently RP2040 only support controller (master) mode.
Enabling this would allow to have two rp2040 talking to each other.
We have usage of SPI in the BSP for pico_explorer.
rp-hal/boards/pico_explorer/src/lib.rs
Lines 196 to 216 in db11231
We need to make a standalone example for this peripheral.
We have an example for i2c in the HAL crate https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/examples/i2c.rs
but no doc-example in https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/i2c.rs
This leaves our docs on the i2c peripheral very underwhelming
https://docs.rs/rp2040-hal/0.2.0/rp2040_hal/i2c/index.html
We haven't implemented the alarms at as all, and the current counter read implementation is not thread safe (as it uses the latched registers, which could race).
It needs to be changed to use the raw read registers and check for overflow like the C SDK and embassy-rp
I tried to write a PIO program that used sideset, but sideset assignments did not have any effect. It turns out that apparently it is necessary to set the pindir of the sideset pins before using them. The documentation calls the function pio_sm_set_pindirs_with_mask()
for that which takes a 32-bit bitmask and sets the pindir for all currently selected set
pins according to the mask. The following code is equivalent to that function, to be placed in StateMachine:
pub fn set_pindirs_with_mask(&self, mut pins: u32, pindir: u32) {
let mut pin = 0;
while pins != 0 {
if (pins & 1) != 0 {
// Select a single "set" pin.
self.sm().sm_pinctrl.write(|w| {
unsafe {
w.set_count().bits(1);
w.set_base().bits(pin as u8);
}
w
});
// Execute "set pindir, <dir>", where "dir" is 1 if the pin is in the mask.
self.sm().sm_instr.write(|w| {
unsafe {
w.sm0_instr().bits(0xe080 | ((pindir >> pin) & 0x1) as u16);
}
w
});
}
pin += 1;
pins = pins >> 1;
}
}
This function has the nice sideeffect that it often saves a set pindir, ...
instruction at the beginning of the program.
I do not know how to properly integrate such a function into the PIO abstraction - the Pico SDK implementation just saves and restores selected pins in that function. That, however, does not work if the state machine is currently active - although, if I understand it correctly, the current PIO abstraction does not try to provide any safeguards against such misuse? Other HALs use a lot more typestates for that.
PIO is covered in chapter 3 of the datasheet.
The RP2040 has two PIOs, each with four state machines. State machines in the same PIO share instruction memory and can communicate via IRQs.
The four state machines execute from a shared instruction memory. System software loads programs into this memory, configures the state machines and IO mapping, and then sets the states machines running. [...] From this point on, state machines are generally autonomous, and system software interacts through DMA, interrupts andcontrol registers, as with other peripherals on RP2040
Most likely a builder interface. There are a lot of options to set:
This issue should make it easier to get a quick overview on what parts of the chip are being worked on.
The hardware abstraction layer (HAL) provides ergonomic access to the peripherals of the RP2040 chip (e.g. UART, USB, GPIOs).
A peripheral that is not yet supported in the HAL can still be used with the peripheral access crate (PAC). It provides access to the raw registers which can then be used as described in the RP2040 datasheet.
A board support package allows easy setup of peripherals of a given board. It provides for example the clock frequency used on that board. Or it can provide named pins that match the markings and components of that board.
Note: all boards found so far use a 12Mhz crystal (XTAL), the built-in bootloader will not function with a different XTAL
Hi,
Can anyone provide example for setting up UART?
I'm having issue that I located (using led) to be in UartPeripheral::enable
(code probably panics or hangs the cpu)
I located that it cannot be invalid frequency (as I didn't unwrap error) and I didn't found anything obvious inside that could cause that.
Thanks
memory.x is only included by an INCLUDE memory.x
line in the cortex-m-rt link.x
file. Because we don't copy the file to ./target, the file is effectively only included by accident and only if you happen to be in the root of the git repo when you do the build.
Also, the sections are out of order which breaks raspberrypi/picotool#39
You have the system clock speed in the results of hal::clocks::init_clocks_and_plls
. But you can't just pass it to cortex_m::delay::Delay
. And it feels like you should be able to.
See section 2.3.1.5 of the reference manual for more info on this peripheral.
This is part of the SIO peripheral, and may require use of a mutex or the hardware spinlocks provided by the SIO to use safely. In the initial implementation, having it block until complete would be recommended.
You can also assume (for the initial implementation) that it's never used by interrupts or by the 2nd core.
Minimum deliverable should be standalone function(s) with examples that demonstrate that results match built-in / and % operators.
The only readme.md in the project is in the repository root.
This file does not get published to crates.io on release of the HAL or the BSP crates.
We should move the current readme into the HAL path, and create a new one in the base of the repo that provide links to the HAL/BSPs readme.md files, as well as links to matrix channel, projects of interest and other community info.
It is unclear to me how to use the UART peripherals. Specifically:
UartPeripheral::enable
? I cannot find anything about this online, only baud rate is mentioned.For testing i hooked up what i thought were the default tx and rx pins for UART0 (GP0 and GP1 respectively) to the rx and tx pins on a raspberry pi 3. Then i ran picocom on it with the same paramers as i use on the pi pico, baudrate 9600, data bits 8, stop bits 1, and parity none. I tried with frequencies 1, 1000 and 100000. Sometimes i would get some bogus output but most of the time there was nothing.
I'm not exactly experienced with embedded development so if i'm missing something obvious, do tell me.
let fmul = hal::rom_data::fmul();
let rom_result = fmul(x, y);
fmul has the value 0x64C
on my chip. But calling the fmul function crashes my program.
Currently for boards other than the Pico, rp2040-boot2-rs is referenced by a specific commit as no released version has the board specific second stage boot loader. This should be changed once the next release of rp2040-boot2-rs is available.
The pointers used to access GPIO interrupt registers are likely to be unsound (due to pointing outside of the original object).
Check if the original object in the PAC is an array, and if it isn't, convert it to an array then update src/gpio/reg.rs functions to index into it.
Originally posted by @9names in #147 (comment)
The current USB implementation does not handle RP2040-E5.
The description of the errata from the datasheet is as follows:
The USB bus RESET state is triggered by the host sending SE0 for 10ms to the device. The USB device
controller requires 800μs of idle ( J-state ) after a bus reset before moving to the CONNECTED state. Without
this idle time, the USB device does not connect and will not receive any packets from the host, and so
does not enumerate.
A device reset happens just after the device is plugged in. Although a host will wait before talking to a
reset device, other devices attached to the same USB hub may also be communicating with the host.
USB 2.0 and USB 3.0 hubs have one or more transaction translators, which facilitate low speed and full
speed transactions on a higher speed bus. It depends on the hub design, but a transaction translator is
usually shared between a few ports.
As the RP2040 USB device is full speed, its traffic when connected to a hub will come via a transaction
translator. This means that if you have another device plugged in next to an RP2040, the RP2040 is likely
to see some messages from the host addressed to the other device. If the device is not very active, for
example, a mouse that is polled every 8ms, this is not a problem. However some devices, such as a USB
serial port, are polled every 30-50μs. In this case the bus is very active, and will cause the RP2040 to never
exit RESET state and not connect.
There is a software workaround for this issue (see workaround section). A user can also work around this
by closing the USB serial port or any other offending devices while connecting their RP2040 and then re
opening their USB serial port.
On a larger hub, the problem may be fixed by moving the RP2040 far away (onto a different transaction
translator) from the offending device. For example, connecting the RP2040 to port 1 of a 7 port hub, and
connecting the USB serial console to port 7, may solve the issue. Connecting the RP2040 to a separate
USB hub to any busy devices will also fix the problem.
Use software to force USB device controller to see idle USB bus for 800μs to move the device from the
RESET state to the CONNECTED state. This fix uses internal debug logic that is connected to GPIO15 for a short
amount of time (~800μs). This forces the controller to see DP as a logical 1 (and DM and logical 0) to
make the USB Device controller believe there is a J-state on the USB bus. GPIO15 does not need to be tied
in any particular way for this fix to work. Instead, we can force the input path in software using the Section
2.19 input override feature. See https://github.com/raspberrypi/pico-sdk/tree/master/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c.
Hi all,
Keen to follow this hal. Have a few boards coming and might try to port some of my bluepill code to the rp to see how it goes (long term).
Shorter term, is there a blinky sample/example to getting started?. I suspect the rpi pico will be fairly popular, so would be good to have a guide helping people with the basics :)
Do people really need to know or care that the I2C struct lives in the rp2040-hal::i2c
module? Same for the other peripheral structures.
This occurred to me as the examples seem to contain a lot of tautologies.
We have an example of using the ADC as a temperature sensor as part of the pico_explorer_showcase example: https://github.com/rp-rs/rp-hal/blob/main/boards/pico_explorer/examples/pico_explorer_showcase.rs
But we have no standalone example for it in the HAL and no doc-example in adc.rs
https://docs.rs/rp2040-hal/0.2.0/rp2040_hal/adc/index.html
After #158 is merged, the HAL and each of the BSPs provide a memory.x file.
In review, Jannic asked
What happens if a binary crate (which depends on rp-hal) brings its own memory.x? Who gets priority?
Example: https://github.com/rp-rs/rp2040-project-template
which is a good question, and we should check to make sure that we can still do it and that the users memory.x gets priority
We're currently manually specifying which boot2 to use inside user/example code.
If the BSP exported a bootloader symbol, BSP examples could be generic.
Example
// alias for the bsp so we don't have to change as much code when changing targets
use feather_rp2040 as target_bsp;
#[link_section = ".boot2"]
#[used]
pub static BOOT2: [u8; 256] = target_bsp::BOOT_LOADER;
instead of a different
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GD25Q64CS;
for each board
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.