Using a 74HC595N with softSPI / bitbanging

All ESP8266 boards running MicroPython.
Official boards are the Adafruit Huzzah and Feather boards.
Target audience: MicroPython users with an ESP8266 board.
Post Reply
maxe
Posts: 8
Joined: Sun Jan 10, 2021 10:30 pm

Using a 74HC595N with softSPI / bitbanging

Post by maxe » Thu Jan 14, 2021 5:00 am

Hi there,

I try to make the 74HC595N work with the ESP-01. I currently do the following without success. The ESP-01 has 4 GPIO pins (GPIO0/2 + RXD(3) and TXD(1)). So to make the software SPI I hook up the following:

GPIO0 -> SER
GPIO2 -> RCLK
GPIO3 -> SRCLK

I pull SRCLR constantly high and I have for testing a single LED on Qa. The labels for the switch come from:

https://www.ti.com/lit/ds/scls041i/scls041i.pdf

For testing all I want is to turn on and off all 8 bits. I initialize the an SPI object as follows:

shiftSPI = SPI(-1, mosi=Pin(0), sck=Pin(2), miso=Pin(3))

I thought all I need now would be

shiftSPI.write(b'00000000')

To turn off all Qa-Qh but it is not working. Can anyone explain a little bit SPI in the context of the shift register and how to write the bits to it? Thanks a lot.

User avatar
pythoncoder
Posts: 4807
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Using a 74HC595N with softSPI / bitbanging

Post by pythoncoder » Thu Jan 14, 2021 5:14 am

The chip has two registers, an input shift register and an output latch register. You need to clock the data into the shift register, then pulse the RCLK line to copy the contents to the output register. So I reckon you need

MOSI -> SER
SCL -> SRCLK
GPIO -> RCLK

SRCLR\ and OE\ pulled up or linked to Vcc. You don't need to use MISO.

Clock the data out using SPI, then pulse the IO pin connected to RCLK to transfer the data to the output pins.
Peter Hinch

maxe
Posts: 8
Joined: Sun Jan 10, 2021 10:30 pm

Re: Using a 74HC595N with softSPI / bitbanging

Post by maxe » Thu Jan 14, 2021 5:26 am

For some reason it works now. The only thing is that you have to initialize the miso pin. So I just used GPIO5 which I can't access anyway.

GPIO0 = MOSI -> SER
GPIO3 = SCK -> SRCLK

GPIO2 = latch -> RCLK

3.3V -> SRCLR

OE -> empty

Code: Select all

from machine import Pin, SPI
shift = SPI(-1, sck=Pin(3), mosi=Pin(0), miso=Pin(5))
latch = Pin(2, Pin.OUT)

latch.off()
shift.write(b'11111111')
latch.on()

latch.off()
shift.write(b'00000000')
latch.on()
Thanks a lot for the help. Now it is all clear and easy.

maxe
Posts: 8
Joined: Sun Jan 10, 2021 10:30 pm

Re: Using a 74HC595N with softSPI / bitbanging

Post by maxe » Thu Jan 14, 2021 5:46 am

I just realized that there must also be something wrong in my code for accessing the outputs. I can control the first (Qa) but the others don't behave as expected. I thought:

shift.write(b'11111111')

would turn them all on. But that's not the case. Any idea?

User avatar
jimmo
Posts: 2080
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: Using a 74HC595N with softSPI / bitbanging

Post by jimmo » Fri Jan 15, 2021 4:08 am

maxe wrote:
Thu Jan 14, 2021 5:46 am
I just realized that there must also be something wrong in my code for accessing the outputs. I can control the first (Qa) but the others don't behave as expected. I thought:

shift.write(b'11111111')

would turn them all on. But that's not the case. Any idea?
Just to confirm -- b'11111111' means an array of bytes, each with the value one (i.e. 0000000100000001000000010000000100000001000000010000000100000001). Not a single byte with all bits set to 1.

Sounds like you maybe want

shift.write(b'\xff')

or

shift.write(bytes((0b11111111,))

maxe
Posts: 8
Joined: Sun Jan 10, 2021 10:30 pm

Re: Using a 74HC595N with softSPI / bitbanging

Post by maxe » Sat Jan 16, 2021 4:37 am

In case anyone tries something similar:

Code: Select all

#!/usr/bin/env python
from machine import SPI, Pin

class ShiftRegister():
        # For SPI:
        # MOSI -> SER
        # MISO -> Not used
        # SCK -> SRCLK
        # Latching -> RCLK
    def __init__(self, serPin, srclkPin, rclkPin, bits=8):
            # miso isn't used in SPI for 74HC595 set to inaccessible pin 5
            # software SPI / bitbanging for ESP8266 ESP-01
        if 5 in (serPin, srclkPin, rclkPin):
            raise ValueError('Pin 5 dummy miso pin')

        self.spi = SPI(-1, sck=Pin(srclkPin), mosi=Pin(serPin), miso=Pin(5), bits=bits)
        self.latchPin = Pin(rclkPin)

    def write(self, data):
        self.latchPin.off()
        self.spi.write(data)
        self.latchPin.on()

    def on(self, Qa=0, Qb=0, Qc=0, Qd=0, Qe=0, Qf=0, Qg=0, Qh=0):
        bitString = int(''.join(map(str, [Qh, Qg, Qf, Qe, Qd, Qc, Qb, Qa])),2)
        self.write(bytearray([bitString]))


User avatar
pythoncoder
Posts: 4807
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Using a 74HC595N with softSPI / bitbanging

Post by pythoncoder » Sat Jan 16, 2021 8:56 am

While your on() method works fine, it's not very efficient to use strings in this way. Another approach is this:

Code: Select all

def on(self, *p):
    a = 0
    for b in p:
        a <<= 1
        a |= b
    return a
This reduces allocations.
Peter Hinch

maxe
Posts: 8
Joined: Sun Jan 10, 2021 10:30 pm

Re: Using a 74HC595N with softSPI / bitbanging

Post by maxe » Sun Jan 17, 2021 4:11 am

Clever. Never heard about these operations. Really cool thanks.

User avatar
pythoncoder
Posts: 4807
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Using a 74HC595N with softSPI / bitbanging

Post by pythoncoder » Sun Jan 17, 2021 6:02 pm

I recommend getting thoroughly familiar with Python bitwise operations. They map closely onto machine code and are key to writing fast and efficient firmware. With typical sizes of operands they are non allocating, which means they can be used in interrupt service routines. All this means they are fast and lend themselves to optimisation with the native and viper code emitters.
Peter Hinch

Post Reply