One-Chip ADSR using the ATTINY1616

Readers: If you'd like to build the ADSR experimenter's board featured in this post, please go to PCBWAY's Community pages--gerber file; KiCAD 10 project/pcb/schematic/library files, Arduino .INO file, modified .h and .cpp helper files, B.O.M., and more, are here.  

You can also help out this blog immensely by checking out PCBWAY using the link here. Thanks!

==============

This one started when DIY rockstar--this guy's kung fu is the best--TJimmyChonga--emailed me about an earlevel C++ library that abstracts analog synthesizer ADSR functionality into a compact C++ library--articles documenting the library begin here; zip of the CPP and H files are here.

Experimenter's PCB for the earlevel ADSR library, and probably a lot more AudioDiWHY fun. 


Looking over the code, I guessed it might be easy to use an ATTINY1616 --that's a <$1USB MCU, folks--to create an entire ADSR since the ATTINY1616 has ample ADC's and a single reliable 8-bit DAC built-in.  

Designed it, gerbered it, got it fabbed, built it. Fast, fast, fast...Good news--yep, it worked.

THE DESIGN

Instead of breadboarding, which drives me nuts, I drew up a 99 x 99 mm PCB "experimenters board" using Kicad10.  

I added 3.5mm input and output jacks; a shottky diode clamp for the trigger input (so a 10V or 12V gate signal didn't blow up the input pin on the MCU) and a few pots....I buffered the output using a DIP TL071....simple stuff; for a lot of this design, anything will do. 


....for future expansion, remaining GPIO was brought out to JST connectors....

As usual, a 3-pin JST in series with a 470 ohm resistor was used for the UPDI programming input.

I included a 7805 regulator, although I could have gotten that from the Euro power cable, but, hey, why bother.

I chose mostly thru-hole for the build since I have tons of THT in my junk box.

Happiness is bubblewrapped brand new PCB's from this blog's patient sponsor, PCBWAY, where ten 2-sided PCB's less than 100x100mm can still be purchased for $5USD. Are you kidding me?

THIS BLOG'S SPONSOR

The gerber got sent off to this blog's trusty sponsor, PCBWAY and back it came with alacrity.  The shameless plug:


--why bother breadboarding when you can throw your ideas into Kicad, ship them off to PCBWAY and get lotsa boards back to mess around with. If they don't work, don't swear, don't stomp around, don't cry....e-waste them in an environmentally friendly way and try again. What's your time worth? 

Prototyping with PCB's is faster and a heck of a lot more fun then breadboarding....wait, there's more! Kicad experts: check out PCBWAY's 2026 Kicad Design Contest--really nice schwag and cash prizes may be yours.

Back to it....

PROOF OF CONCEPT

Since nobody codes any more I used Claude Code to put together the Arduino sketch for a 3 pot ADSR Proof of Concept--Attack, Sustain and Decay/Release--some bugs at first but easily fixed. 



The output worked surprisingly well--nice analog-sounding log response....I thought 8 bits wasn't going to get it done and the output would be "stair stepped" but: it was fine.

For the PCB, there were a couple of stupid mistakes but overall this one was easy--maybe too easy.  

Testing the POC board with the AudioDiWHY dual MS20 filter (post here). Overall the Proof of Concept single chip ADSR, using the C++ Earlevel library, worked a lot better than expected.

OUTRO

In general, the heavy lifting was all done with the ATTINY1616--if I hard coded the ADSR values, jammed 5V from my bench into the MCU, and didn't care about input or output levels, this was literally a one-chip/$1USD design....if there's a lower parts count ADSR out there, I haven't seen it.

OK, whatever....the question, what to do next.  

The fact that the entire EG lives on a single inexpensive MCU means I can sprinkle the damn things all over--add it to a filter, add it to a VCA, add it to a mixer.  

But I also see adding various logic outputs to this--end of attack, end of release--and using them to trigger other events.  

Also it should be easy to modify the DAC to produce linear outputs, log outputs, or whatever you want in-between.

Or, I could go full Behringer and rip off + remarket someone else's design--how about The Intelligel Quadra (4 AR's with clever I/O) with expander, allowing VC of attack and decay, this module sold for something like $300 before being discontinued? I figure I could recreate it using a 4x ATTINY's for something like $30USD?  And add sustain to each of the 4 AR's?   

Make it itty bitty/Eurorack so only folks with tiny little fingers can use it.  

Finally, I'd need to say it was made by "Bellinger" and call it something like "Quad Fumer"--indeed--too easy.

  


KICAD 10: Hierarchical Sheets and Blocks: Lay 'Em Out Once, Use 'Em Over and Over

Readers: today's post assumes you have a working knowledge of Kicad, an incredible open source EDA program. If not, this post might be pea soup. Newbies: watch a great Kicad tutorial here.  And--previous audioDiWHY posts focusing on Kicad are here, here, here and here


I have read that good engineering is modular engineering. Is good audio synthesis modular audio synthesis? 

Not sure.

Kicad--our beloved schematic capture/PCB layout/simulation software--has recently added some great features in making bits of your previous designs reusable--a huge timesaver.  

Let's go over this.

"Hierarchical Sheets"

....let you put subcircuits into other designs, treating the subcircuit as a "black box"--don't worry what's in the box, just enjoy what it can do....you expose I/O between your black box and main design using "hierarchical labels."
  • Because I'm lazy, I will abbreviate hierarchical sheets going forward as "HS"
  • Create a new project, this will contain your HS.
  • In the schematic (.sch file), put whatever components you want in your HS--you are creating a normal schematic at this point.
  • For I/O you need to share outside your HS issue the command: "Place" > "add hierarchical labels"


  • Save the schematic.
Next--Create a new parent project; in the next few steps, we are going to embed the "HS" content into it.
  • In the parent's .sch file, click on this icon on the right:

  • using this tool, draw a box inside the parent schematic. 
  • You will see a blue box...this represents the HS:



  • A properties dialog appears (if you don't see it, select the "Untitled_Sheet" and then tap the letter "e".)
  • Give the HS a name
  •  in "sheetfile" click on the folder icon and navigate to the kicad_sch file you created initially, the one that contains your HS.

  • At this point you might see dialogs about using relative filenames and something about database tables being messed up (?).  
  • Pretend you didn't see any of that and click OK twice.
  • Still in the parent schematic, click on this icon on the right:

  • Click on the HS box; the I/O pins ("hierarchical labels") created in the the source .sch file appear in the parent schematic--they are placed sequentially
  • Create the rest of the parent schematic and wire it to your HS.
In the screenshot below I ran a DC simulation on a parent schematic containing a hierarchical sheet; the HS contained a single 100k resistor with "in" and "out" labels. 

The simulated DC voltages in dark red show that this works--the 100K resistor in the HS is hidden from view but is part of the simualtion.
This is an OC simulation--DC values--not to be confused with "OCD"
 


DESIGN BLOCKS

....allow you to create a subcircuit, save it in its own library, and import it into future designs. 

This feature showed up in Kicad 9 (See the video here). 

With Kicad 10, you can put schematic and traces into a single design block.

And--again, due to indolence/laziness, I will call "design blocks" going forward "blocks". Have a nice day.  

Organizing blocks: Blocks are organized into libraries, same idea as Kicad symbols.  Each block is a folder containing a json description file and file(s) for the .sch and/or .pcb components.  

For both the people out there who are interested--get a zip of my custom blocks from Github, here.

Creating a block: select some or all of your design, then right click on "blocks" 




From the drop down, choose "Save Selection as Design Block"





But! Be careful about "hide library tree", if you click that, the entire block's user interface section disappears. This threw me at first. I had to go back to view > panels > design blocks to make it reappear.  
 
Tidbit: By clicking "New Library" you can also choose if you want the block to be visible in the current project only or globally (all projects); the default is global:


Viewing existing Blocks: from the schematic editor View > panels > make sure "design blocks" is checked.... you see something like this (your block names will be different....)


Using existing blocksDouble left click on a block, drag it into your schematic, creating a group of components and wires.

Editing blocks:

  • Select either PCB 
  • Right clock inside the block and say Grouping > ungroup
  • Edit.

Before



After: now it's editable components like everything else in the schematic.


NOW: A WORD FROM THIS BLOG'S SPONSOR

OK, you just created something awesome using these new Kicad 10 tools and need to get some PCB's, then get them assembled.

For this, check out this blog's sponsor, PCBWAY, who can fabricate the PCB's, do the component assembly, and then, do everything else.

In addition to top shelf PCB fabrication they also do fantastic work with 3D printing, injection molding, and much more. 

And!!! Kicad Mavens (you must be if you've made it this far?): run, don't walk, and submit your Kicad masterpiece to PCBWAY'S Kicad PCB Design Contest--winners get cash and/or RPi goodies. Check out the contest here.

As always--you can help this blog by checking out the PCBWAY site.  Thank you!


SCHEMATICS AND FOOTPRINTS/TRACES IN ONE BLOCK--New to Kicad 10.

Super useful--capture the schematic and layout of a subcircuit in a single block. However--work slowly and carefully. This feature is one of those "miss any step and the whole damn thing won't work" situation.  

The steps:

Creating the combo block--start with the schematic:
  • Create a schematic subcircuit with all the symbols, wires and values you want in your block.
  • Tool > create associations  
  • Make sure everything is OK, that all symbols have associated footprints and so on.
  • Create a block--for this let's call it europower w traces




Next, create the associated traces.
  • Go to PCB and update the PCB from footprint
  • The footprint appears
  • Draw in all traces you want to include in the combo block
  • Save the selected footprint and traces (you must select both!) as a block  (right click on block > save selection as block)
  • For the block name, type in the exact same name you used for the schematic block--this is case sensitive: in this case, "europower w traces"
  • Kicad 10 will ask "overwrite block"?  Say YES

To use it:
  • In your schematic, pick the block europower w traces and put it on the schematic
  • In your PCB, pick the same block europower w traces and put it on the pcb
  • Hit F8.  
  • If all goes well you will see a footprint with traces appear--the PCB and the schematic are "synced"--it's all wired up.
  • If you messed up, a new footprint will appear with no traces.  Damn!  Try again, make sure to follow each step.
  • You can now grouping > ungroup your Schematic or PCB block and change things.  





Tidbit: I noticed when upgrading Kicad 9 > 10 I had to set the global blocks path manually.  Preferences > Manage Design Block libraries > global libraries:


For Kicad 10.0.1, I had to set the Nickname, the "Library Path" (where the global block libraries are stored--the local location might vary if you are using a cloud repo on different hosts), and the Library Format (pulldown to "Kicad") by hand for this to work. Not sure why this didn't come over with the rest of my preferences.  

OUTTRO

Think "She's so Heavy": another brilliant John Lennon time signature change, with rapid master tape cut.  

Sequential Pro-One VCF: Smells like 80's Spirit

Readers: If you'd like to build the VCF featured in this post, please go to PCBWAY's Community pages--gerber file; KiCAD 9 project/pcb/schematic/library files, B.O.M., and more, are here.  

You can also help out this blog immensely by checking out PCBWAY using the link here. Thanks!

==============

I grew up on 70's rock and roll, by 1980 I was in college and Reagan was president. The latter was bad news, but the good news: cool synths everywhere. One of my favorites: Sequential Pro-One and yes, it had a hyphen. 

Back then I was the cool synth kid, playing in a remarkably lucrative band, I had a 5 and a 600, which both sounded great, and damn, the ProOne had that Sequential Spirit.

I see Pro-One's go for $1500-2000USD on the used market; I'm not going to buy one, I have too much vintage gear already, instead I cloned its VCF, a big part of its sound:



This is revision 3 of the initial design (here) and is almost 100% where I want it; still some minor adjustments needed for the resonance, but is otherwise good to go, and it sounds, well I think anyway, great.


Double happiness is 2 bubblewraps from this blog's faithful and patient sponsor, PCBWAY.  You can help out the blog immensely by checking the out--here.









 

For the front panel, to nail some of the 80's design look n' feel, I used a graphics technique shown to me by one of the most talented fabricators I know: Elton at Otter Mods. Read about the SVG to Kicad graphics process here.

I will skip the rest of the usual boring fab photos, instead jumping right to the test phase:

worked first time (WFT), but at rev 3, it should, right?



Altering the power rails changed the overall sound of the filter, especially bringing the V- rail to say -9 or -10VDC.  Raising the rails to +/-15V didn't make a big change which surprised me a bit. I might create a starvation add-on for the negative rail for further expermentation? Stay tuned.

The one remaining issue with the filter is that the resonance, when cranked to 11, doesn't create that nice whistle-like sine wave I remember on the beloved Pro-One; instead, it creates a crunchy distortion, a bit like an MS20 filter with it's "peak" cranked way up.  

that's not right, I probably missed a value somewhere?

I didn't need another crunchy VCF so I changed its current limiting resonance resistor from 200K to 330K, which topped out the resonance sound to more like a 12db/octave filter. Regardless, this filter has the nice 24db/octave Sequential fatness.  

In the future I will try to chase this rez issue down, but for now I have another good sounding filter without paying a kings ransom for a vintage synth I definitely don't need. 

Update 4-20-26 think I figured the resonance issue out (it's simple, and stupid): The Pro-One filter seems to expect around 10V P/P audio at input, maybe a bit less, while the Doepfer bench ramp VCO I used to test was about 17V P/P. 

So--fixing this was a simple matter of attenuating the VCO output signal on my bench. 

As far as using the filter as a sine wave oscillator, it was best to remove the input signal entirely when the filter was used as a VCO. I ended up using 220K for R1. With all that the filter resonates all the way to a decent sine wave and sounds great.

OK--That's it for this one. 

Until next time: Filter well and live. 



-10 to 10V 3x CV Generator--Part III

Readers: If you'd like to build the CV Generator featured in this post, please go to PCBWAY's Community pages--gerber file; KiCAD 9 project/pcb/schematic/library files, STL for the OLED standoff, Arduino .INO file, B.O.M., and more, are here.  

You can also help out this blog immensely by checking out PCBWAY using the link here. Thanks!

==============

Howdy--this post is part III of the posts here and here

From last time--I created a simple control voltage generator, sourcing about 30mA with 3 independent pots, each output is -10 to +10V DC controlled by a dedicated pot.

For revision 3 I added a MCP4728 DAC and tweaked the 16-bit ADC analogReadEnhanced algo, using 3 of the 4728's 4 channels, to make the CV generator's output better match the values shown in the OLED.



This simple revision had a big problem....unlike REV 1 and 2 I couldn't get the I2C bus to work--no I2C signal, anywhere.  

I figured it was a hardware issue and spent a lot of time troubleshooting based on that assumption--nope.

Then I had to move my shop--pack up every tool, every part, every drawer, move it across town, then set it all back up again--fun stuff.

Once unpacked I revisited the build, and right away Claude.ai caught the problem; the sketch used the "SSD1306AsciiWire.h" library to drive the OLED and my code was written like this:

  Wire.begin(); //set I2C 

  oled.begin(&Adafruit128x64, I2C_ADDRESS); 

  Wire.setClock(400000L);  //set I2C speed. 


meaning the I2C speed was set after constructing the oled object.

Claude told me I had to add the Wire.setClock statement before calling oled.begin. I knew that?

So--should be this.

   Wire.begin(); //set I2C 

  Wire.setClock(400000L);  //set I2C speed. 

  oled.begin(&Adafruit128x64, I2C_ADDRESS); 


(The errant code worked in revision 1 and 2 but not this one, making this one hard to track down....)

Fixed!  

Otherwise a simple build:

As usual I used SMD SOIC and 1206 parts and a cheap hotplate.



Uploading firmware....




The OLED needed a standoff and I was surprised I couldn't find anything close to what I needed online so I designed and 3D printed one myself:


That sat between the front panel/Oled and the PCB:

 
 

I then packaged all of this up (gerber, Kicad files, STL file for the standoff, Arduino code, and all the rest)--and put it on PCBWAY's community site , go here. Speaking of Serene and the good folks at PCBWAY, here's a word from this blog's humble sponsor:


      

 For all your prototype and production needs, PCBWAY is the place to go.

they can fabricate PCBs using full color! Details here

In addition to top shelf PCB fabrication they also do fantastic work with assembly3D printinginjection molding, and much more. 

Their staff is extremely helpful and PCBWAY always turns work around quickly. 

As always--you can help this blog by checking out the PCBWAY site. Thanks!

Back to it.....


Boring AI background. 

Wait, is that it?  Yep that's it for now. 

Gotta keep moving.

See ya next time.

Arduino HID Pushbuttons in a Harmonica Case; New Workshop (and) Moving Sucks

Over the past several weeks I had to pack up my entire bench, all parts, all tools, and everything else I own, and move them to a rental place across town while my psychiatrist wife's house gets a new foundation. 

Moving, especially when you are older and fully set in your ways, is stressful and generally not recommended.

We've moved in. Sort of.

To shake out my temporary workshop I built a simple USB-HID keyboard using perf, Arduino IDE, Claude Code, a DS3231 RTC (realtime clock) breakout board and an RP2040 MCU--specifically the Seeed XIAO-RP2040.  


Press a button, the current date and time are displayed on whatever PC you have the widget plugged into.  Press the other 2 and 2 pre-programmed strings appear.

Worked first time, here's what the finished thingy looks like--I may put labels and dumb decals on it, but good enough for now.

Hohner harp cases -- great for small projects.


PCBLESS

I hadn't built anything with perf in a long time, it was--fun?

Parts are mostly from the junk box....


The jury is still out.

The DS3231 I2C RTC breakout board is a no-name-o from Amazon. Without it, the RP2040 loses track of internal time during a power outage.

If you want this BoB check the link here, but the link may break after a few months....whatever; this is a common BoB and is probably available from your favorite tariff-ingesting retailer; match the photo:










Wiring: the upper IC is the SEEED MCU, bottom 4 pins (SCL, SDA, Vcc, GND) are the wirepads of the RTC breakout board.  Two views--from the top and bottom--are in one drawing. I have found with perf projects, if I don't create a guide like this, very likely I will make wiring mistakes....



THE CODE

....centers on the incredible C/C++ RP2040 SDK to Arduino port from Earle Philhower III, check out the extensive documentation here, Swiss accent guy's video here

Wow, Earle worked super hard so we don't have to--we owe Earle our gratitude!

Being an employable up-to-date tech (also intellectually disinterested?) I used Claude Code to generate sketches for the project.

Claude code is amazing and terrifying....the damn thing got most of what is below right in one pass, making a few stupid (but major) mistakes--whatever, easily fixed.....quicker to get things close with Claude and fix bugs by hand vs. code by hand and fix bugs by hand.

This first sketch sets the RTC to current time. Modify the rtc.adjust line, compile, and upload.



#include 
#include 

RTC_DS3231 rtc;

void setup() {
  Serial.begin(115200);
  Wire.begin();

  if (!rtc.begin()) {
    Serial.println("DS3231 not found!");
    while (true);
  }

  // >>> SET YOUR CURRENT TIME HERE <<<
  // Format: DateTime(YYYY, MM, DD, HH, MM, SS)  — 24-hour time
  rtc.adjust(DateTime(2026, 3, 15, 18, 50, 0));

  Serial.println("RTC time has been set!");

  // Verify by reading it back
  DateTime now = rtc.now();
  Serial.print("Time is now: ");
  Serial.print(now.month());   Serial.print("/");
  Serial.print(now.day());     Serial.print("/");
  Serial.print(now.year());    Serial.print(" ");
  Serial.print(now.hour());    Serial.print(":");
  if (now.minute() < 10) Serial.print("0");
  Serial.print(now.minute());  Serial.print(":");
  if (now.second() < 10) Serial.print("0");
  Serial.println(now.second());
}

void loop() {
  // Nothing — time is set, job done.
}


The second sketch makes pushing the buttons display current date/time as well as a couple of strings--replace string1 and string2 values with your own:




#include 
#include 
#include 

/* Board manager:
   https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
   Board: Seeed XIAO RP2040
   USB Stack: PICO SDK

   Library required: RTClib by Adafruit (Library Manager)

   DS3231 Wiring:
     VCC -> 3.3V
     GND -> GND
     SDA -> D4 (GPIO 6)
     SCL -> D5 (GPIO 7)

   NOTE: Button 3 (Email 2) moved from D4 to D6 to free up I2C SDA.
*/

RTC_DS3231 rtc;

// Button pins
const int buttonD1 = D1; // Date/Time
const int buttonD3 = D3; // Email 1
const int buttonD6 = D6; // Email 2 — moved from D4 to avoid I2C conflict

// Button states
bool lastStateD1 = HIGH;
bool lastStateD3 = HIGH;
bool lastStateD6 = HIGH;

void setup() {
  pinMode(buttonD1, INPUT_PULLUP);
  pinMode(buttonD3, INPUT_PULLUP);
  pinMode(buttonD6, INPUT_PULLUP);

  Keyboard.begin();
  Wire.begin();

  if (!rtc.begin()) {
    // RTC not found — flash onboard LED as error indicator
    pinMode(LED_BUILTIN, OUTPUT);
    while (true) {
      digitalWrite(LED_BUILTIN, HIGH); delay(200);
      digitalWrite(LED_BUILTIN, LOW);  delay(200);
    }
  }

  // If the RTC lost power (dead/missing battery), set it to compile time.
  // Once the coin cell is installed this will not overwrite a valid time.
 // if (rtc.lostPower()) {
  //  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
 // }
}

void loop() {
  bool currentStateD1 = digitalRead(buttonD1);
  bool currentStateD3 = digitalRead(buttonD3);
  bool currentStateD6 = digitalRead(buttonD6);

  if (currentStateD1 == LOW && lastStateD1 == HIGH) {
    delay(50);
    printRTCTime();
    delay(300);
  }

  if (currentStateD3 == LOW && lastStateD3 == HIGH) {
    delay(50);
    Keyboard.print("string1");
    delay(300);
  }

  if (currentStateD6 == LOW && lastStateD6 == HIGH) {
    delay(50);
    Keyboard.print("string2");
    delay(300);
  }

  lastStateD1 = currentStateD1;
  lastStateD3 = currentStateD3;
  lastStateD6 = currentStateD6;
}

void printRTCTime() {
  DateTime now = rtc.now();

  Keyboard.print(now.month());
  Keyboard.print("/");
  Keyboard.print(now.day());
  Keyboard.print("/");
  Keyboard.print(now.year());
  Keyboard.print(" ");

  if (now.hour() < 10) Keyboard.print("0");
  Keyboard.print(now.hour());
  Keyboard.print(":");
  if (now.minute() < 10) Keyboard.print("0");
  Keyboard.print(now.minute());
  Keyboard.print(":");
  if (now.second() < 10) Keyboard.print("0");
  Keyboard.print(now.second());
}

THE PLUG 


I will need a PCB for the next one of these I build, and maybe a more durable case.  For this, this blog's sponsor, PCBWAY, can fabricate the PCB's, the case, and everything else.
In addition to top shelf PCB fabrication they also do fantastic work with assembly, 3D printing, injection molding, and much more.  
As always--you can help this blog by checking out the PCBWAY site.  Thank you!

BENCHED MACH II

Here's the new bench setup. 

We are getting moved in and simple things like getting cold water from the kitchen sink is driving us nuts.  

I am told the foundation work, including lifting the house, redoing the French drains, fixing the roof line, bringing electrical up to code, and everything else needed in Earthquake Country, will take a year to a year and a half.

So we are here. For now.

What you see below works--sorta.



Good enough to perf....

See you next time.