7 unstable releases (3 breaking)

0.4.1 Sep 9, 2024
0.4.0 Apr 28, 2024
0.3.0 Apr 17, 2024
0.2.0 Feb 11, 2024
0.1.1 Jan 18, 2024

#1635 in Embedded development


Used in rustsbi-jh7110

GPL-3.0-only

260KB
6.5K SLoC

JH71xx-HAL

jh71xx-hal is a HAL (hardware abstraction layer) crate for JH71xx-based SoCs from StarFive.

Currently, only the JH7110 SoC is supported. JH7100 appears to be discontinued, and the next SoC line from StarFive will be the JH81xx series.

Please submit changes if you would like to add support for the JH7100 SoC!

Usage

GPIO

GPIO configuration and access is fully supported:

use jh71xx_hal::{pac, gpio};
use embedded_hal::digital::{InputPin, OutputPin};

let dp = pac::Peripherals::take().unwrap();
let gpio0 = gpio::get_gpio(dp.sys_pinctrl.gpio_0());

// Configure as an enabled output
let mut gpio0_out = gpio0.into_enabled_output();

// Drive pin high
gpio0_out.set_high();
// Drive pin low
gpio0_out.set_low();

// Configure as an enabled input
let gpio0_in = gpio0_out.into_enabled_input();

// Configure as high-impedance input
let gpio0_in_high_z = gpio0_in.into_input_high_z();
// Configure as pull-up input
let gpio0_in_pull_up = gpio0_in_high_z.into_input_pull_up();
// Configure as pull-down input
let mut gpio0_in_pull_down = gpio0_in_pull_up.into_input_pull_down();

// Is pin low?
if gpio0_in_pull_down.is_low() {
    // do interesting GPIO stuff
}

// Is pin high?
if gpio0_in_pull_down.is_high() {
    // do interesting GPIO stuff
}

WIP: GPIO

JH7110 SoCs use a pin multiplexer to configure pins for specialized functionality (I2C, SPI, etc.).

Work is on-going to provide high-level interfaces to configure specialized functions for GPIO pins.

Low-level configuration can currently be achieved through the jh71xx-pac crate which is re-exported as jh71xx_hal::pac.

I2C

I2C configuration and access is fully supported.

use embedded_hal::i2c::{I2c as _, Operation};
use jh71xx_hal::{pac, i2c};

let dp = pac::Peripherals::take().unwrap();
let mut i2c0 = i2c::I2c::new(dp.i2c0);

// 7-bit address
let addr: u8 = 1;
let mut read_buf = [0u8; 1];
let ops = Operation::Read(&mut read_buf);

i2c0.transaction(addr, &mut [ops]).unwrap(); 

// 10-bit address
let addr: u16 = 1;

i2c0.transaction(addr, &mut [ops]).unwrap();

SPI

SPI configuration and access is fully supported.

use embedded_hal::spi::SpiBus;
use jh71xx_hal::{pac, spi};

let dp = pac::Peripherals::take().unwrap();

// 8-bit transactions
let mut spi0 = spi::Spi::<pac::Spi0, 8>::new(dp.spi0).unwrap();
let mut read_buf = [0u8; 1];
let write_buf = [0u8; 1];

// Read and write as separate transactions
spi0.read(read_buf.as_mut()).unwrap();
spi0.write(write_buf.as_ref()).unwrap();

// Read and write in the same call
spi0.transfer(read_buf.as_mut(), write_buf.as_ref()).unwrap();
// Write and read from the same buffer
// NOTE: writes happen first, since the read overwrites the buffer
spi0.transfer_in_place(read_buf.as_mut()).unwrap();

// Flushes read/write FIFOs, and waits for peripheral to become idle
spi0.flush().unwrap();

// 16-bit transactions
let mut spi1 = spi::Spi::<pac::Spi1, 16>::new(dp.spi1).unwrap();
let mut read_buf = [0u16; 1];
let write_buf = [0u16; 1];

// Read and write as separate transactions
spi1.read(read_buf.as_mut()).unwrap();
spi1.write(write_buf.as_ref()).unwrap();

// Read and write in the same call
spi1.transfer(read_buf.as_mut(), write_buf.as_ref()).unwrap();
// Write and read from the same buffer
// NOTE: writes happen first, since the read overwrites the buffer
spi1.transfer_in_place(read_buf.as_mut()).unwrap();

// Flushes read/write FIFOs, and waits for peripheral to become idle
spi1.flush().unwrap();

WIP: SPI

Currently, only 8- and 16-bit transfers are supported. The peripheral in the SoC supports 4- to 16-bit transfers.

TBD: should the interface support:

  • packed data transfers for efficiency (but increased complexity)
  • unpacked transfers for simplicity (but reduced efficiency)

Either way, the additional data sizes could be supported without breaking changes to the current API.

The ARM pl022 SSP SPI peripheral also supports "Slave" mode, which is outside the embedded-hal traits, but could still be useful to jh71xx-hal users.

Similarly, the peripheral supports the Texas Instruments Synchronous Serial and Microwire serial frame formats (currently unsupported).

PWM

PWM configuration and access is fully supported.

use embedded_hal::pwm::SetDutyCycle;
use jh71xx_hal::{pac, pwm};

let dp = pac::Peripherals::take().unwrap();
let mut pwm0 = pwm::Pwm::new(dp.pwm);

// Gets the maximum duty cycle
let max_cycle = pwm0.max_duty_cycle();
// Sets the PWM peripheral to a ~50% duty cycle
pwm0.set_duty_cycle(max_cycle / 2).unwrap();

Dependencies

~12MB
~268K SLoC