With reference to this forum post
https://forum.electro-smith.com/t/how-to-use-a-gpio/545
Below is an example code segment for writing a byte of data to the 74HC595, in my example displaying byte of data on 8 leds.
There is some confusion about mapping Daisy pin names to actual STM32H7 pins
I’ll not go into the detail of this mapping. The above forum post explains it
The mappings can be found here
https://github.com/electro-smith/DaisyExamples/blob/master/seed/experimental/Seed3Test/Seed3Test.cpp
Example
But first look at the data sheet for the 74HC595
https://www.ti.com/lit/ds/symlink/sn74hc595.pdf
Here is a good description of what we have to do, it has a very nice animated image about shift registers.
https://lastminuteengineers.com/74hc595-shift-register-arduino-tutorial/
And this excellent one
https://protostack.com.au/2010/05/introduction-to-74hc595-shift-register-controlling-16-leds/
In this last link there is a good sequence type diagram of what we need to do, it’s just after the 74HC595 pin out diagram.
Note: The data byte is presented to the DS pin it is loaded into the serial buffer of the 74HC595 on the rising edge of a clock on the SH_CP pin.
Once all the data byte has been ‘clocked in’ the data is then latched to the 74HC595 output buffer/latch; this is done by pulsing the ST_CP pin. The output pins Qn then output logic high or low.
Further down this article there are two C code examples for the ATMega8.
This code has been refactored using a series of #defines. And tbh I find this difficult to read but it shows the code in relationship to the ‘sequence’ diagram.
C++ code example
I’ve kept my code a simple as I can, once you’ve got it working refactor as you see fit.
Here’s the small C++ class that uses three GPIO pins to write a bye of data to the 74HC595
First the header file leds.h
#pragma once
#define GPIO_4 { DSY_GPIOC, 9 }
#define GPIO_5 { DSY_GPIOC, 8 }
#define GPIO_6 { DSY_GPIOD, 2 }
class Leds
{
public:
Leds() {}
~Leds() {}
void Init();
void Write(uint8_t data);
private:
dsy_gpio_pin pins[3] = {
GPIO_4, GPIO_5, GPIO_6
};
dsy_gpio ledPins[3] ;
const uint8_t BITMASK = 0x1;
};
Here I’ve copied only the specific GPIO #defines required
On the Daisy Seed these map to the following pins
Looking at the Daisy Seed pin out diagram
https://github.com/electro-smith/Hardware/blob/master/resources/300ppi/DaisyPinoutRev4.png
I’m using the pin numbers nearest to the circuit board i.e. the numbers in black font
e.g. GPIO_4 == 4 black font number
In Leds.cpp there are some comments as to which Daisy pins connect to the corresponding 74HC595 pins.
Leds.cpp
#include "leds.h"
#pragma GCC push_options
#pragma GCC optimize ("O0")
/*
ledPins[0] GPIO_4 = 74HC595 SCK pin 11 (clock)
ledPins[1] GPIO_5 = 74HC595 EN pin 12 (chip enable / latch )
ledPins[2] GPIO_6 = 74HC595 SER pin 14 (data)
*/
void Leds::Init(){
//setup the pins as outputs
for(size_t i = 0; i < 3; i++) {
ledPins[i].pin = pins[i];
ledPins[i].mode = DSY_GPIO_MODE_OUTPUT_PP;
ledPins[i].pull = DSY_GPIO_NOPULL;
dsy_gpio_init(&ledPins[i]);
dsy_gpio_write(&ledPins[i], 1);
}
}
void Leds::Write(uint8_t data) {
//enable serial buffer , disable write to output buffer
dsy_gpio_write(&ledPins[1], 0);
for (uint8_t i = 0; i < 8; ++i) {
//check the least significant bit
//and write the data pin high or low
if ( (data & BITMASK) == BITMASK) {
dsy_gpio_write(&ledPins[2], 1);
}
else {
dsy_gpio_write(&ledPins[2], 0);
}
//shift data down one bit, i.e. parallel to serial
data >>= 1;
//clock low
dsy_gpio_write(&ledPins[0], 0);
dsy_system_delay(1);
//clock high
dsy_gpio_write(&ledPins[0], 1);
dsy_system_delay(1);
}
// after all 8 bits, latch data from 74HC595 serial buffer to its output with a pulse
dsy_gpio_write(&ledPins[1], 1);
dsy_system_delay(1);
dsy_gpio_write(&ledPins[1], 0);
}
#pragma GCC pop_options
Note:
#pragma GCC push_options
#pragma GCC optimize (“O0”)
I had to add this due to my complier options very aggressively optimising out what it thinks is redundant code.
These pragma’s effectively stop the compiler optimising this section of code.
This code is from a basic set of tests I have so it’s all a bit hacky
Leds::Init
This sets the GPIO pins as outputs and writes their outputs to high
Leds::Write(uint8_t data)
This takes a byte of data and in effect turns the parallel byte into a serial bit stream and latches it to the 74HC595.
The comments should describe what’s happening on the 3 pins and have a look at the ‘sequence ‘ diagram again
https://protostack.com.au/2010/05/introduction-to-74hc595-shift-register-controlling-16-leds/
The dsy_system_delay(1); delays are necessary to create the actual square wave type pulses. Please experiment with the delays and removing them , see what happens.
To implement the class, In main.cpp
#include "leds.h" static Leds leds; leds.Init(); leds.Write( 0b00000001 ); dsy_system_delay(500); leds.Write( 0b00000010); dsy_system_delay(500); leds.Write( 0b00000100 ); dsy_system_delay(500); leds.Write( 0b000001000 ); dsy_system_delay(500); leds.Write( 0b000010000 ); dsy_system_delay(500); leds.Write( 0b000100000 ); dsy_system_delay(500); leds.Write( 0b001000000 ); dsy_system_delay(500); leds.Write( 0b010000000 ); dsy_system_delay(500);/ leds.Write( 0b100000000 ); dsy_system_delay(500);
Or neater, the above leds_Write in a loop. I did say it’s a hack :- )
Additional Hardware wiring for the 74HC595
Look at this
https://mutable-instruments.net/modules/braids/downloads/braids_v50.pdf
From Emilie’s diagram the 74HC595 pin 10 is wired to digital 3.3v and pin 13 is grounded.
Ignore pin 9 if you’re using one 74HC595
Here’s Emilie’s code for her hardware.
https://github.com/pichenettes/eurorack/blob/master/braids/drivers/display.cc
Logic Analysers
It’s nice to be able to view the sequence of pulses / timings in real time, but logic analysers can be quite expense.
However, a couple of months ago I came across this unbelievably cheap logic analyser from Germany.
https://www.amazon.co.uk/AZDelivery-Logic-Analyzer-24MHz-download/dp/B01MUFRHQ2/ref=sr_1_4?dchild=1&keywords=logic+analyser&qid=1598692033&sr=8-4
It has accompanying software to download and run the thing. Takes about 5 minutes to read and get it working. It is simple to use.
It works perfectly ok for debugging GPIO pins, but obviously for fast processor clocking speeds you’d need an expensive logic analyser, big band width and capture speeds etc.
BTW, I’m not affiliated to the manufacture, I don’t get any monies etc., and as always “buyer beware”
One last point about accessing Daisy pins.
Pins can be accessed using GetPin();
hardware.GetPin(16);
Where hardware = static DaisySeed hardware;
Hope this helps, stay safe.