Skip to content

Commit

Permalink
added configurable, additional tick delay for 4021 shift register via…
Browse files Browse the repository at this point in the history
… Config (#638)
  • Loading branch information
stephenhensley authored Sep 20, 2024
1 parent 3a515be commit 2822c1c
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 16 deletions.
12 changes: 12 additions & 0 deletions examples/SR_4021/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Project Name
TARGET = SR_4021

# Sources
CPP_SOURCES = SR_4021.cpp

# Library Locations
LIBDAISY_DIR = ../..

# Core location, and generic Makefile.
SYSTEM_FILES_DIR = $(LIBDAISY_DIR)/core
include $(SYSTEM_FILES_DIR)/Makefile
88 changes: 88 additions & 0 deletions examples/SR_4021/SR_4021.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* SR 4021 Example
* This demonstrates the use of an CD4021 input shift register to read 8 buttons.
* Some auxillary code is included to debounce, and time the length presses.
*
* The AudioCallback is utilized to read the buttons at 1kHz.
* Values are output via the USB Micro port.
*/
#include "daisy_seed.h"

// Typedef for simplifcation of init/config
using ButtonSr = daisy::ShiftRegister4021<1, 1>;

// Period for printing button data over USB.
static constexpr uint32_t kUsbPrintPeriod = 250;

// Consts for pin locations on the seed -- customize as needed.
// The 4021 operates through "bit-banging" so any GPIO is usable.
static constexpr daisy::Pin kPinSrClk = daisy::seed::D7;
static constexpr daisy::Pin kPinSrData = daisy::seed::D19;
static constexpr daisy::Pin kPinSrLatch = daisy::seed::D21;
static constexpr daisy::Pin kCallbackPin = daisy::seed::D23;

// Global Variables
daisy::DaisySeed hw;
daisy::GPIO callback_pin;
ButtonSr btn_shiftreg;
uint8_t btn_data[8];
uint32_t btn_rising_edge_time[8];


void AudioCallback(daisy::AudioHandle::InputBuffer in,
daisy::AudioHandle::OutputBuffer out,
size_t size)
{
callback_pin.Write(true);
btn_shiftreg.Update();
for(size_t i = 0; i < 8; i++)
{
auto datum = btn_shiftreg.State(i);
btn_data[i] = (btn_data[i] << 1) | (datum ? 0 : 1);
if(btn_data[i] == 0x7f)
btn_rising_edge_time[i] = daisy::System::GetNow();
}
callback_pin.Write(false);
}

int main(void)
{
// Initialize the Daisy Seed hardware
hw.Init(true);

ButtonSr::Config sr_cfg;
sr_cfg.clk = kPinSrClk;
sr_cfg.latch = kPinSrLatch;
sr_cfg.data[0] = kPinSrData;
btn_shiftreg.Init(sr_cfg);

callback_pin.Init(kCallbackPin, daisy::GPIO::Mode::OUTPUT);

hw.StartAudio(AudioCallback);

hw.StartLog(false);

uint32_t now, usb_time;
now = usb_time = daisy::System::GetNow();

while(1)
{
now = daisy::System::GetNow();
if(now - usb_time > kUsbPrintPeriod)
{
// Do the printing of the stuff.
hw.PrintLine("Button Data:");
hw.PrintLine("------------");
for(size_t i = 0; i < 8; i++)
{
uint32_t timeheld
= btn_data[i] == 0xff ? now - btn_rising_edge_time[i] : 0;
hw.PrintLine("Button %d: %s -- %d",
i,
btn_data[i] == 0xff ? "Pressed" : "Released",
timeheld);
}
usb_time = now;
}
}
}
40 changes: 24 additions & 16 deletions src/dev/sr_4021.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace daisy
** @ingroup shiftregister
**
** CD4021B-Q1: CMOS 8-STAGE STATIC SHIFT REGISTER
**
**
** Supply Voltage: 3V to 18V
** Clock Freq: 3MHz at 5V (less at 3v3) -> 8.5MHz at 15V
** Pin Descriptions:
Expand All @@ -21,14 +21,14 @@ namespace daisy
** - P/!S - 9
** - Q[6-8] - 2, 12, 3
**
** Driver has support for daisy chaining and running up to 2 same-sized
** chains in parallel from a single set of clk/latch pins to reduce
** Driver has support for daisy chaining and running up to 2 same-sized
** chains in parallel from a single set of clk/latch pins to reduce
** pin/code overhead when using multiple devices.
**
** When dealing with multiple parallel/daisy-chained devices the
** When dealing with multiple parallel/daisy-chained devices the
** states of all inputs will be filled in the following order (example uses two chained and two parallel):
** data[chain0,parallel0], data[chain1,parallel0], data[chain0,parallel1], data[chain1,parallel1];
**
**
** When combining multiple daisy chained and parallel devices the number of devices chained should match
** for each parallel device chain.
**
Expand All @@ -43,6 +43,13 @@ class ShiftRegister4021
Pin clk; /**< Clock pin to attach to pin 10 of device(s) */
Pin latch; /**< Latch pin to attach to pin 9 of device(s) */
Pin data[num_parallel]; /**< Data Pin(s) */

/**
* DelayTicks between these actions helps to ensure stable timing
* for the connected device(s).
* Each tick is approx. 4.16ns at CPUFreq 480MHz
*/
uint32_t delay_ticks = 10;
};

ShiftRegister4021() {}
Expand All @@ -69,30 +76,31 @@ class ShiftRegister4021
/** Reads the states of all pins on the connected device(s) */
void Update()
{
clk_.Write(0);
latch_.Write(1);
System::DelayTicks(1);
latch_.Write(0);
uint32_t del_ticks = config_.delay_ticks;
clk_.Write(false);
latch_.Write(true);
System::DelayTicks(del_ticks);
latch_.Write(false);
uint32_t idx;
for(size_t i = 0; i < 8 * num_daisychained; i++)
{
clk_.Write(0);
System::DelayTicks(1);
clk_.Write(false);
System::DelayTicks(del_ticks);
for(size_t j = 0; j < num_parallel; j++)
{
idx = (8 * num_daisychained - 1) - i;
idx += (8 * num_daisychained * j);
states_[idx] = data_[j].Read();
}
clk_.Write(1);
System::DelayTicks(1);
clk_.Write(true);
System::DelayTicks(del_ticks);
}
}

/** returns the last read state of the input at the index.
/** returns the last read state of the input at the index.
** true indicates the pin is held HIGH.
**
** See above for the layout of data when using multiple
**
** See above for the layout of data when using multiple
** devices in series or parallel.
***/
inline bool State(int index) const { return states_[index]; }
Expand Down

0 comments on commit 2822c1c

Please sign in to comment.