Giter Club home page Giter Club logo

rp-hal's People

Contributors

9names avatar akiyukiokayasu avatar anall avatar andrewh42 avatar archusr64 avatar asaffisher avatar contradict avatar devsnek avatar eolder avatar gip-gip avatar hardiesoft avatar hmvp avatar ithinuel avatar jannic avatar jenntoo avatar jlpettersson avatar jonathanpallant avatar jonil avatar jsgf avatar liamolucko avatar mgottschlag avatar nashenas88 avatar nelsonapenn avatar nic0w avatar nilclass avatar sizurka avatar thejpster avatar tommy-gilligan avatar victorkoenders avatar weirdconstructor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rp-hal's Issues

Allow setup of the clocks block

The clock systems are described in chapter 1.15 of the datasheet.

Use cases

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 sources

  • Ring Oscilator (ROSC, chapter 2.17)
  • Crystal Oscilator (XOSC, chapter 2.16)
  • USB- and System-PLL (referencing XOSC, chapter 2.18)
  • External GPIO

Switching clock sources

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.

Implementation ideas

  • Allow freezeing 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.
  • Peripherals (e.g. UART) should be able to take the correct clock setting (maybe defined via the type) to be used when setting up e.g. baudrates.
  • Another example: stm32h7xx-hal docs.rs
  • Crate for durations and rate: embedded-time

Mockup

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!");

Current state?

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 👋

Improve i2c error handling

In the current i2c implementation there are several asserts relating to buffer sizes, invalid addresses.

assert!(bytes.len() < 256 && bytes.len() > 0);

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 Support

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.

Blinky.rs doesn't work

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.

Should the Spi new function take ownership of the spi pins?

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!

Add RTIC Example

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.

SPI support

There are two SPI interfaces described in section 4.4 of the datasheet

Both interfaces support:

  • Master or slave mode
  • Programmable clock and word size
  • Programmable choice of GPIO pins
  • Separate transmit, receive, overflow and receive timeout interrupts

Issues when setting bits in registers

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
});

Bootrom functions

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.

Missing example for PIO

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.

Support for hardware divider and firmware float support

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.

Clocks improvements

Collected suggested improvements from #31:

  • Rename selfaux_source macro. See: #31 (comment)
  • Better name/handling around aux sources and glitchless mux: See discussion: #31 (comment)
    • Better name for set_self_aux_src
    • Possibly: Prevent aux-aux transition while the aux source is active on the clocks with glitchless muxes. (Per datasheet: clock glitches on these should be avoided at all costs as the CPU or other important logic is possibly currently running off of the clock.)
    • Possibly: Prevent clock source switches on a running clock w/o the glitchless mux. (Per datasheet: disable the clock, wait 2 cycles of source clock, switch the (aux) source, re-enable clock, wait 2 clock cycles of new source)
  • 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)

Watchdog timer set to garbage

It looks like watchdog is configured incorrectly in init_clocks_and_plls

watchdog.enable_tick_generation(xosc_crystal_freq as u8);

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

PIO example which loads a .hex (compile PIO asm) file

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.

Running tests on CI

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

Add control for GPIOs

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.

Use cases

The GPIOs can be used for these functions (chapter 2.19.2):

  • Control/read pin level (SIO, chapter 2.3.1)
  • Connecting a pin to a peripheral (PIO, SPI, UART, I2C, PWM, ADC, USB Vbus control)
  • Use as an interrupt (chapter 2.19.3)

The following settings can be changed for each pin (chapter 2.19.4):

  • Output drive strength
  • Output slew rate
  • Schmitt trigger
  • Pull-up/down
  • Signal and direction inversion and override

The input buffer and output driver can be disabled (which is mandatory when used with the ADC (chapter 4.9.1)).

Implementation ideas

Type states

To make it harder to misuse we could add the following as type parameters (similar to NRF HAL and the embedded book):

  • Function selection (In-/Output (SIO), PIO[01], SPI[01]-(Rx|Tx|...), ...)
  • Pull-Up/Down (only for Inputs)

Traits

All pins have the same configurations listed above. So a trait that covers all these settings could make sense.

Interrupts

ToDo...

PIO example which loads a .pio file

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.

I2C Support

I2C Peripheral Support:

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

Implementation:

Awaits #4

Example for SPI

We have usage of SPI in the BSP for pico_explorer.

let dc = internal_pins.spi_miso.into_push_pull_output();
let cs = internal_pins.lcd_cs.into_push_pull_output();
let spi_sclk = internal_pins.spi_sclk.into_mode::<FunctionSpi>();
let spi_mosi = internal_pins.spi_mosi.into_mode::<FunctionSpi>();
let spi_screen = Spi::<_, _, 8>::new(spi0).init(
resets,
125_000_000u32.Hz(),
16_000_000u32.Hz(),
&MODE_0,
);
let spii_screen = SPIInterface::new(spi_screen, dc, cs);
let mut screen = ST7789::new(spii_screen, DummyPin, 240, 240);
screen.init(delay).unwrap();
screen
.set_orientation(st7789::Orientation::Portrait)
.unwrap();
screen.clear(Rgb565::BLACK).unwrap();

We need to make a standalone example for this peripheral.

Timer module support

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

PIO sideset does not work (wrong pindir)

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

PIO is covered in chapter 3 of the datasheet.

Overview

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

Implementation

Most likely a builder interface. There are a lot of options to set:

  • wrap top
  • wrap bottom
  • side en
  • side pindir
  • jmp pin
  • out sticky
  • inline out enabled
  • inline out bits
  • in base
  • out base
  • out count
  • set base
  • set count
  • sideset base
  • sideset count
  • fjoin rx
  • fjoin tx
  • autopush enabled
  • autopull enabled
  • autopush threshold
  • autopull threshold
  • out shift direction
  • in shift direction
  • clock divider

HAL tracking issue

This issue should make it easier to get a quick overview on what parts of the chip are being worked on.

HAL

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.

Not yet available

  • CPU
    • Core voltage regulator
    • Sysinfo
  • Peripherals
    • SSI

Basic support

Needs docs / examples

  • Clocks and Resets

BSPs

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

Not yet available

Supported

UART example

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 only included by accident

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

Clocks/Delay papercut.

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.

Add a blinky example using the HAL

Can be implemented after the following parts have been implemented:

  • GPIO (#4)
  • Resets
  • Clocks (#6)

Use cases:

  • Starting point for fresh projects
  • Getting a quick overview of the HAL

Hardware Divider/Modulo support

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.

readme.md files for repo and subprojects

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.

UART example?

It is unclear to me how to use the UART peripherals. Specifically:

  • What does the frequency parameter mean when calling UartPeripheral::enable? I cannot find anything about this online, only baud rate is mentioned.
  • What pins are used for the peripherals? The rp2040 datasheet mentions that multiple pins can be used.

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.

fmul crashes chip

    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.

Need to update references to rp2040-boot2-rs

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.

GPIO interrupt register accesses may be unsound

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)

USB enumeration errata

The current USB implementation does not handle RP2040-E5.
The description of the errata from the datasheet is as follows:

USB device fails to exit RESET state on busy USB bus

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.

Workaround

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.

Blinky example?

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 :)

Consider re-exporting SPI, I2C, etc at the top-level.

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.

BSPs should handle rp2040_boot2

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.