Accessing Shift Registers

Date:

2017-08-18

Intro

Driving LEDs or 7-Segment Registers can be done in several ways. This document explains, how to interface them with shift registers. A shift register will receive 8 bit of data on a connection with 2 signals: data and clock. After the complete byte has been transfered, a third signal, latch, can be used to assert the newly received byte on the corresponding 8 output pins. A shift register is, in a way, a serial to parallel converter. Interestingly, shift registers can be chained.

For example, one can transfer 4 Bytes through a chain of 4 shift register chips. After the transfer asserting the latch signal will make the transfered bytes appear on all the output pins simultaneously.

I strongly prefer shift registers and thus continuous signals on LEDs over the multiplexing (and thus flickering) methods.

Code Details

We need to define 3 pins corresponding to the acutal hardware layout:

\ abakus display
PORTD 2 portpin: sr_latch
PORTD 3 portpin: sr_clock
PORTD 4 portpin: sr_data

Then +sr will set the pins up correctly (never assume that pins are setup in a specific way before you start using them):

: +sr
  sr_latch pin_output  sr_latch high
  sr_clock pin_output  sr_clock low
  sr_data  pin_output  sr_data  high
;

bit>sr will clock out just one bit and nothing else:

: bit>sr ( bit -- )
  if sr_data high else sr_data low then
  sr_clock high  sr_clock low
;

The shift registers I use expect the most significant bit first. This could be otherwise. So byte>sr clock out one byte. The loop can be written differently, of course.

: get.bit ( byte pos -- bit )
  1 swap lshift    \ -- byte bitmask
  and              \ -- bit
;

\ clock one byte out, MSB first!
: byte>sr ( byte -- )
  0 7 do
    dup i get.bit   \ 7 6 5 ... 0: MSB first!
    bit>sr
  -1 +loop
  drop
;

So far data is transfered, but not asserted onto the output pins. So >sr adds asserting a low pulse on pin latch:

: >sr
  byte>sr
  sr_latch low sr_latch high
;

Putting it all together

The main program will know, how many shift registers are chained (if any), thus a function like n>sr will be needed: clock out a known number of bytes, then assert the latch signal.

: n>sr  ( c1 .. cn n -- )
  0 ?do
    byte>sr
  loop
  sr_latch low sr_latch high
;

The Code

 1\ 2017-05-10 shiftregister.fs
 2\
 3\ Written in 2017 by Erich Wälde <erich.waelde@forth-ev.de>
 4\
 5\ To the extent possible under law, the author(s) have dedicated
 6\ all copyright and related and neighboring rights to this software
 7\ to the public domain worldwide. This software is distributed
 8\ without any warranty.
 9\
10\ You should have received a copy of the CC0 Public Domain
11\ Dedication along with this software. If not, see
12\ <http://creativecommons.org/publicdomain/zero/1.0/>.
13\
14\
15\ needs pin definitions
16\     PORTD 2 portpin: sr_latch
17\     PORTD 3 portpin: sr_clock
18\     PORTD 4 portpin: sr_data
19\ words:
20\     +sr ( -- )     \ enable shift register
21\     emit.sr ( n -- )     \ transfer 1 Byte
22\     type.sr ( xn-1 .. x0 n -- )  \ n Bytes
23
24: +sr
25  sr_latch pin_output  sr_latch high
26  sr_clock pin_output  sr_clock low
27  sr_data  pin_output  sr_data  high
28;
29
30: bit>sr ( bit -- )
31  if sr_data high else sr_data low then
32  sr_clock high  sr_clock low
33;
34
35: get.bit ( byte pos -- bit )
36  1 swap lshift    \ -- byte bitmask
37  and              \ -- bit
38;
39
40\ clock one byte out, MSB first!
41: byte>sr ( byte -- )
42  0 7 do
43    dup i get.bit
44    bit>sr
45  -1 +loop
46  drop
47;