Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 7323

SDK • How to read 74HC165 with spi_read_blocking() ?

$
0
0
I had recently sorted out using SPI from the SDK to interface with the 74HC595 in the forum post [SOLVED] Bewildered by SPI and 74HC595 used to drive 8 LED. All is well. So as the next exercise I thought I would use a 74HC165 to read the output of the 74HC595 and work out the clock delay between setting the parallel-out pins on the 595 and reading that information back in though the 165. And things didn't go as expected. The pinout and the shift, load sequences are fairly straight forward.
74hc165-pinout+sequence-fs8.png


The problem I'm having is trying to figure out the correct use of SPI_RX, SPI_TX and SPI_CS when working with spi_read_blocking(). The prototype for the function is:

Code:

int spi_read_blocking (spi_inst_t * spi, uint8_t repeated_tx_data, uint8_t * dst, size_t len)
The problem is what is being done with the uint8_t repeated_tx_data parameter and pinout? The very short description in the SDK docs say that 0 should usually work, but some applications like talking to SD cards require 0xff instead. All pins are configured as GPIO_FUNC_SPI (though I have tried SPI_CS as normal gpio out and tried manually pulling SH/LD low before the read - no change. I validate the return from spi_read_blocking() and it always returns 1-byte telling me it did read 8-bits of data (but what that data was was suspect, normally 0 or 255, but with 3, 7, 15, 31, 63, 127, etc.. just basic 255 shifted by x number of bits one way or the other)

As far as the pinout goes, does this mean the SPI_TX pin is connected to the SH/LD pin on the 74165 to handle pulling SH/LD low to capture the inputs? Or does the SPI_CS pin handle pulling SH/LD low before the spi_read_blocking() call read the data shifted out on Qh?

The spi_write_blocking() used with the 74HC595 linked above worked fine that way so I was expecting the treatment of the 165 chip would be similar. The key difference is the 165 isn't a true tri-state chip where the 595 is. For single-chip, non-chained used, that shouldn't matter, but with the Pi Zero 2W using ioctl access to the spi /dev/ filesystem nodes, you do need to use both spi0 and spi1 placing an extra read on spi1 before the read on spi0 to clock the SH/LD low then high so inputs are transferred to the buffer for reading out. I don't believe the pico lib needs this (but I tried it anyway - no change)

The code I'm attempting is shown below. The 165 is read on SPI1. The SPI0 config was there for driving the 74HC595, and also served as the test as was done on the Pi Zero 2W, so it is just boilerplate at this point. The SPI1 code can be configured to us the SPI_CS as GPIO_FUNC_SPI or as a normal gpio depending on whether define CS1nSHLD as it is now.

So my big question is "What triggers the SH/LD pin on the 165 low transferring the inputs to the internal buffer"? Is the purpose of the uint8_t repeated_tx_data intended for you to use the SPI_TX to connect to the 165 SH/LD pin to handle that, or do you connect SPI_CS to that to handle it similar to the 74HC595 setup. Or, do you need to use the SPI_CS pin as a general gpio out pin and manually pull SH/LD low and then high before the read? That's where I'm stuck.

The code I'm currently using along with 2-button to test read of the 74hc165 is:

Code:

#include <stdio.h>#include <stdint.h>#include <stdlib.h>#include "pico/stdlib.h"#include "hardware/spi.h"#define USERT          1      /* use repeating timer for output to stdout */#define RTDELAY      100      /* stdout updated every 100 ms (10Hz)       */                              /*------------------------------------------*/#define SPI_PORT    spi0      /* 74HC595 pinout:                          */#define SPI_CLK        2      /*  GP2   SRCLK  shift-register clock       */#define SPI_TX         3      /*  GP3   SER    serial data                */#define SPI_RX         4      /*  GP4   SH/LD  shift/load latch for read  */#define SPI_CS         5      /*  GP5   RCLK   latch clock                */                              /*                                          */#define SRCLR_PIN     10      /*  GP10  SRCLR  clear (pull hi/active low) */#define OE_PIN        11      /*  GP11  OE     output enable (pull low)   */                              /*                                          */#define CSnSPIFN      1       /* SPI_CS using GPIO_FUNC_SPI (optional)    */                              /*------------------------------------------*/#define CS1nSHLD                              /*------------------------------------------*/#define SPI1_PORT   spi1      /* 74HC165 pinout:                          */#define SPI1_CLK       6      /*  GP6   CLK    shift-register clock       */#define SPI1_TX        7      /*  GP7   SH/LD  shift/load latch for read  */#define SPI1_RX        8      /*  GP8   QH     serial data out            */#define SPI1_CS        9      /*  GP9   SH/LD  shift/load latch for read  */                              /*------------------------------------------*/static volatile uint8_t rxval = 0;      /* value read from 74hc165 input */#define DELAY        400      /* max delay (ms) betweed RCLK latch for 74HC595 */#define DELAYFIRST   800      /* for first count 0-255 if longer dealy wanted */static volatile uint16_t delay = DELAYFIRST;/* reverse the bits in byte, LSB to MSB or vice versa */uint8_t bitorderswap (uint8_t byte){  byte = ((byte & 0xf0) >> 4) | ((byte & 0x0f) << 4);  byte = ((byte & 0xcc) >> 2) | ((byte & 0x33) << 2);  return ((byte & 0xaa) >> 1) | ((byte & 0x55) << 1);}/** callback for stdout repeating_timer */bool timer_repeat_ms (struct repeating_timer *rt){  /* output current value and loop deay to stdout (in-place) */  printf ("  74hc165 : %3hhu\033[0K\r", rxval);  return true;}/* binary count 0-255 on LED attached as parallel outputs to the 74HC595 * shift-register, in between counts, the LEDs are traversed in sequence from * Qa to Qh illuminatng each LED, the delay for the count which loops in * decreasing manner from 400 ms to as low as 20 ms, is adjusted and the next * count begins. the output LED brightness can be controlled by PWM and the * GP26 ADC input captures the value for LED intensity and the LEDs brightness * is automatically adjusted with max-bright at 0-duty cycle and faint/off for * a 100% duty cycle provided by the SPI_OE (output enabled pin). * * the 74hc165 inputs are attached to each of the 74hc595 outputs to read the * value currently being output. the 74hc165 is driven by spi1. currently it * reads L (0) or H (255) on each read with other bit patterns 7, 15, 31, 63, * 127, 192, 240 and 254 at random intervals (those are 255 left/right shifted) */int main (void) {  uint8_t rxfailcnt = 0;  unsigned baudrate = 0;  int ret = 0;  stdio_init_all();  /* set SPI function on SPI_CLK, SPI_TX and optionally SPI_CS for 74hc595 */  gpio_set_function (SPI_CLK, GPIO_FUNC_SPI);  gpio_set_function (SPI_TX, GPIO_FUNC_SPI);  gpio_set_function (SPI_RX, GPIO_FUNC_SPI);  gpio_set_function (SPI_CS, GPIO_FUNC_SPI);  /* SPI initialization  (56KHz requested) */  baudrate = spi_init (SPI_PORT, 128 * 1000);  printf ("\n\nSPI baudrate  : %u\033[?25l\n", baudrate);  /* set SPI function for SPI CLK, QH and SH/LD for 74hc165 */  gpio_set_function (SPI1_CLK, GPIO_FUNC_SPI);  gpio_set_function (SPI1_TX, GPIO_FUNC_SPI);  gpio_set_function (SPI1_RX, GPIO_FUNC_SPI);#ifndef CS1nSHLD  gpio_set_function (SPI1_CS, GPIO_FUNC_SPI);#else  gpio_init (SPI1_CS);  gpio_set_dir (SPI1_CS, GPIO_OUT);  gpio_put (SPI1_CS, 1);#endif  baudrate = spi_init (SPI1_PORT, 128 * 1000);  printf ("SPI1 baudrate : %u\033[?25l\n\n", baudrate);  /* test read with waveform polarity reversed */  // spi_set_format (SPI1_PORT, 8, 1, 0, SPI_MSB_FIRST);  /* add timer_repeat_ms for 5Hz consule text update */  repeating_timer_t rt    = { .delay_us = 0 };  void *data = NULL;  add_repeating_timer_ms (RTDELAY, timer_repeat_ms, data, &rt);  while (1) {    uint8_t rxtmp = 0;      /* raw value from 74hc165 */    sleep_ms (delay);    /* trigger shift/load with spi0 */    // ret = spi_read_blocking (SPI_PORT, 0, &rxtmp, sizeof rxtmp);#ifdef CS1nSHLD    gpio_put (SPI1_CS, 0);    sleep_ms (2);    gpio_put (SPI1_CS, 1);    sleep_ms (1);#endif    /* read data from 74hc165, validate return */    ret = spi_read_blocking (SPI1_PORT, 0, &rxtmp, sizeof rxtmp);    if (ret == sizeof rxtmp) {      rxval = rxtmp;      // rxval = bitorderswap (rxtmp);     /* MSB first to LSB first */    }    else {  /* handle read error */      rxfailcnt += 1;      printf ("\n\033[0Kerror: spi_read_blocking() returned : %d  "              "(%3hhu)\033[2A\n", ret, rxfailcnt);    }  }}
I've obviously wrapped myself around the axle on this one and need a bit of guidance who has figured out how to read from the 74HC165 using SPI.

Statistics: Posted by drankinatty — Mon Aug 04, 2025 8:14 am — Replies 2 — Views 58



Viewing all articles
Browse latest Browse all 7323

Trending Articles