Skip to content

Parallel-In, Serial-Out Over SPI

According to the 74HC165 Datasheet, there are three pins that we need to set up to have a working minimal circuit.

  • SH/LD The Load input, active low. This pin loads the data from the parallel inputs and shifts it when high.
  • CLK The clock input. We will use this with the SPI peripheral.
  • QH The serial data output, corresponds to MISO

SPI Configuration

rust
let pl = gpioa.pa6.into_push_pull_output_in_state(PinState::High);

let miso = gpioc.pc11.into_alternate();
let sck = gpioc.pc10.into_alternate();

let mut spi3: Spi<SPI3, _, u8> = device.SPI3.spi(
    (sck, miso, NoMosi),
    spi::Config::new(MODE_0),
    10.kHz(),
    ccdr.peripheral.SPI3,
    &ccdr.clocks,
);

The rust code above initializes the pl (Parallel Load) pin into an high state, then sets up the SPI3 peripheral at 10kHz, with no MOSI pin, since we won't send anything back to the 74HC165.

Loading and Reading

Once everything is set up, we can load the data into the chip and shift. For this we will need to set the pl pin low for a short amount of time and then drive a clock signal to read the resulting byte.

rust
pub fn read_buttons(
    spi: &mut Spi<SPI3, spi::Enabled, u8>,
    pl: &mut gpio::gpioa::PA6<Output>,
    delay: &mut Delay,
) -> u8 {
    pl.set_low();
    delay.delay_us(5_u8);
    pl.set_high();

    let mut data: [u8; 1] = [0];
    // enables the clock and reads the response
    spi3.transfer(&mut data).unwrap();

    data[0]
}

The SN74HC165 also expects the user to drive the CLK INH (clock inhibit) pin low, we grounded that pin to enable the clock at all times.