From c7cbd7c6cd689de358142d8501a0f5c1aefd38c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean=20Fran=C3=A7ois=20CASSAN?= Date: Wed, 4 Mar 2020 18:48:06 +0100 Subject: [PATCH] Shiftregister implementation (#135) * Basic support of SIPO shift register * typo * add example of shiftregister for arduino and nucleo * Fix build flag for nucleof103rb * Fix wrong data pin configuration * Change README.md for Shift registers * Add API for individual register's output pin * Rewrite shift register example to show ShiftPin usage * Fix target for shiftregister example smoke test * Fix type in makefile * Add shiftregister compatble IC * Edit comment and readme --- Makefile | 2 + README.md | 3 +- examples/shiftregister/main.go | 124 +++++++++++++++++++++++++++++++++ shiftregister/shiftregister.go | 93 +++++++++++++++++++++++++ 4 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 examples/shiftregister/main.go create mode 100644 shiftregister/shiftregister.go diff --git a/Makefile b/Makefile index ee46143..75544dd 100644 --- a/Makefile +++ b/Makefile @@ -121,5 +121,7 @@ smoke-test: @md5sum ./build/test.hex tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/l9110x/speed/main.go @md5sum ./build/test.hex + tinygo build -size short -o ./build/test.hex -target=nucleo-f103rb ./examples/shiftregister/main.go + @md5sum ./build/test.hex test: clean fmt-check smoke-test diff --git a/README.md b/README.md index 8399edc..9745707 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,8 @@ The following 44 devices are supported. | [PCD8544 display](http://eia.udg.edu/~forest/PCD8544_1.pdf) | SPI | | [Resistive Touchscreen (4-wire)](http://ww1.microchip.com/downloads/en/Appnotes/doc8091.pdf) | GPIO | | [Semihosting](https://wiki.segger.com/Semihosting) | Debug | -| [Shift register](https://en.wikipedia.org/wiki/Shift_register#Parallel-in_serial-out_\(PISO\)) | GPIO | +| [Shift register (PISO)](https://en.wikipedia.org/wiki/Shift_register#Parallel-in_serial-out_\(PISO\)) | GPIO | +| [Shift registers (SIPO)](https://en.wikipedia.org/wiki/Shift_register#Serial-in_parallel-out_(SIPO)) | GPIO | | [SHT3x Digital Humidity Sensor](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/0_Datasheets/Humidity/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C | | [SSD1306 OLED display](https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf) | I2C / SPI | | [SSD1331 TFT color display](https://www.crystalfontz.com/controllers/SolomonSystech/SSD1331/381/) | SPI | diff --git a/examples/shiftregister/main.go b/examples/shiftregister/main.go new file mode 100644 index 0000000..9ab8515 --- /dev/null +++ b/examples/shiftregister/main.go @@ -0,0 +1,124 @@ +package main + +import ( + "machine" + "time" + + "tinygo.org/x/drivers/shiftregister" +) + +func main() { + d := shiftregister.New( + shiftregister.EIGHT_BITS, + machine.PA6, // D12 Pin latch connected to ST_CP of 74HC595 (12) + machine.PA7, // D11 Pin clock connected to SH_CP of 74HC595 (11) + machine.PB6, // D10 Pin data connected to DS of 74HC595 (14) + ) + d.Configure() + + for { + + // Examples using masks. This method writes all pins state at once. + + // All pins High + d.WriteMask(0xFF) + delay() + + // All pins Low + d.WriteMask(0x00) + delay() + + // Some fun with masks + for _, pattern := range patterns { + d.WriteMask(pattern) + shortDelay() + } + delay() + d.WriteMask(0x00) + + // Examples using individually addressable pin API. This method is slower than using mask + // because all register's pins state are send for is p.Set() call. + + // Set register's pin #4 + d.GetShiftPin(4).High() + delay() + d.GetShiftPin(4).Low() + delay() + + // Get an individual pin and use it + pin := d.GetShiftPin(7) + pin.High() + delay() + pin.Low() + delay() + + // Prepare an array of pin attached to the register + pins := [8]*shiftregister.ShiftPin{} + for p := 0; p < 8; p++ { + pins[p] = d.GetShiftPin(p) + } + + for p := 7; p >= 0; p-- { + pins[p].Low() + shortDelay() + pins[p].High() + } + + for p := 7; p >= 0; p-- { + pins[p].High() + time.Sleep(100 * time.Millisecond) + pins[p].Low() + } + delay() + } +} + +func delay() { + time.Sleep(500 * time.Millisecond) +} +func shortDelay() { + time.Sleep(100 * time.Millisecond) +} + +var patterns = []uint32{ + 0b00000001, + 0b00000010, + 0b00000100, + 0b00001000, + 0b00010000, + 0b00100000, + 0b01000000, + 0b10000000, + 0b10000001, + 0b10000010, + 0b10000100, + 0b10001000, + 0b10010000, + 0b10100000, + 0b11000000, + 0b11000001, + 0b11000010, + 0b11000100, + 0b11001000, + 0b11010000, + 0b11100000, + 0b11100001, + 0b11100010, + 0b11100100, + 0b11101000, + 0b11110000, + 0b11110001, + 0b11110010, + 0b11110100, + 0b11111000, + 0b11111001, + 0b11111010, + 0b11111100, + 0b11111101, + 0b11111110, + 0b11111111, + 0b00000000, + 0b11111111, + 0b00000000, + 0b11111111, +} diff --git a/shiftregister/shiftregister.go b/shiftregister/shiftregister.go new file mode 100644 index 0000000..95f1f20 --- /dev/null +++ b/shiftregister/shiftregister.go @@ -0,0 +1,93 @@ +// Package shiftregister is for 8bit shift output register using 3 GPIO pins like SN74ALS164A, SN74AHC594, SN74AHC595, ... +package shiftregister + +import ( + "machine" +) + +type NumberBit int8 + +// Bit number of the register +const ( + EIGHT_BITS NumberBit = 8 + SIXTEEN_BITS NumberBit = 16 + THIRTYTWO_BITS NumberBit = 32 +) + +// Device holds pin number +type Device struct { + latch, clock, out machine.Pin // IC wiring + bits NumberBit // Pin number + mask uint32 // keep all pins state +} + +// ShiftPin is the implementation of the ShiftPin interface. +// ShiftPin provide an interface like regular machine.Pin +type ShiftPin struct { + mask uint32 // Bit representing the pin + d *Device // Reference to the register +} + +// New returns a new shift output register device +func New(Bits NumberBit, Latch, Clock, Out machine.Pin) *Device { + return &Device{ + latch: Latch, + clock: Clock, + out: Out, + bits: Bits, + } +} + +// Configure set hardware configuration +func (d *Device) Configure() { + d.latch.Configure(machine.PinConfig{Mode: machine.PinOutput}) + d.clock.Configure(machine.PinConfig{Mode: machine.PinOutput}) + d.out.Configure(machine.PinConfig{Mode: machine.PinOutput}) + d.latch.High() +} + +// WriteMask applies mask's bits to register's outputs pin +// mask's MSB set Q1, LSB set Q8 (for 8 bits mask) +func (d *Device) WriteMask(mask uint32) { + d.mask = mask // Keep the mask for individual addressing + d.latch.Low() + for i := 0; i < int(d.bits); i++ { + d.clock.Low() + d.out.Set(mask&1 != 0) + mask = mask >> 1 + d.clock.High() + } + d.latch.High() +} + +// GetShiftPin return an individually addressable pin +func (d *Device) GetShiftPin(pin int) *ShiftPin { + if pin < 0 || pin > int(d.bits) { + panic("invalid pin number") + } + return &ShiftPin{ + mask: 1 << pin, + d: d, + } + +} + +// Set changes the value of this register pin. +func (p ShiftPin) Set(value bool) { + d := p.d + if value { + d.WriteMask(d.mask | p.mask) + } else { + d.WriteMask(d.mask & ^p.mask) + } +} + +// High sets this shift register pin to high. +func (p ShiftPin) High() { + p.Set(true) +} + +// Low sets this shift register pin to low. +func (p ShiftPin) Low() { + p.Set(false) +}