Saturday, January 19, 2019

Front Panels: The Technique So Far

Not only am I learning about electronics but also working with metal?

Here's a quick post about how I do this, hope I don't forget this in a couple of years. This technique (?) is good for drilling holes, reasonably accurately lined up, in flat metal prototype panels.

First: I get my aluminum blanks from PCBWAY in China ("Alubase PCB").  Personally I use FrakRac format for my Audiodiwhy craziness but this should work for 5U, Euro, a one-off front panel for a preamp, a 19" 2U panel for a power amp, or whatever.

Today I am building an modular synthesizer ADSR and need extra drills for SPDT switches and the PCB bracket's 4/40 screws....


Using Eagle (but any illustration program should work) I create a 1:1 drawing of the existing blank with existing holes, and add any extra holes that are needed.

Next I see if it all lines up--this one is getting close.



More alignment, but still not there.



Once aligned (or before) I can add pencil marks for anything else I want to drill. I am basically being lazy--it makes more sense to put this on the CAD drawing, but, oh well. Here, it's for the brackets to hold the PCB. A straightedge and ruler are friends for this.


In the words of my personal hero, Frank Zappa: here is the "crux of the biscuit": The glue on the left will attach the paper print out to the front of the panel, with enough stick to not come loose or tear during drilling. The solvent on the right will completely remove the paper template and any glue that doesn't come up when it's time to ditch the paper. Warning: the solvent stinks to high heaven, so wear gloves or whatever, work outdoors, and as a last resort, try not to breathe the fumes.

All can be purchased at amazon, craft stores, hobby stores and the like.


I use a very small hand drill to create the pilot holes. These can be found on line or in hobby shops--the model airplane folks apparently use them quite a bit for instance. I have found that punches and the like can distort the metal panel's shape.


I invested in a small drill press and put it in my garage. Highly recommended. But!! Caution: Use sharp bits, and always wear gloves and eye protection with this tool--seriously, I have had some close calls here.



Here's a mock up of how things ended up this time. Pretty good, but not perfect! The left hole for the PCB got screwed up; the drill press skittered because I didn't have the bit tightened down enough.  Damn! Glad I was wearing gloves!  This time, I am going against every fiber of my mild OCD; I am going to try to leave it as-is. It's good for me!


Final mock up. Not bad for a prototype, in spite of the screwed up goof on the left. Damn! Oh well. I need to finish the ADSR, and it's a 3 day weekend here in the US so maybe I will do some Lazertranning.

Moving on....happy drilling!

Friday, January 11, 2019

Programming Arduino in "Pure C": Now We're Playing with Power! First steps!!

Let's jump right into the why. 

I have been corresponding a bit with an audio DIY master: Grumble, from the electro-music DIY audio forum. Just when I think I've done something cool, I see what Grumble comes up with and shake my head: this guy has extraordinary DIY skills!

A lot of Grumble's projects (but not all) are digital in nature, using Atmel  MCU's.

I was curious how some of his code works and Grumble was nice enough to send me some of his Atmel C code for study.

Hmm, not entirely what I expected. It seems his projects are too advanced to be easily crafted from Arduino's super friendly sketch programming language.  

Instead, Grumble uses what professional microprocessor programmers call "pure C" or "AVR-C" or "Embedded C".



Pure C: not a Citrus Product. I've also seen it called "raw C". Or maybe "Embedded Microprocessor C/C++".   For AVR/Atmel Processors, I also hear this called "AVR-C"

What's all this then? Arduino's sketch language is a library, written in C and C++, allowing us DIYers to do hard things quickly.

However, if you peruse the libraries that comes with the Arduino IDE you see code like Grumble's. That's because the Arduino sketch language itself is written in C and C++.

I read that this is what professionals often use when programming these chips. Why? Pure C unlocks every capability of the MPU (Atmel 328P for instance), not just the features and peripherals exposed by friendly open source coders at Arduino and elsewhere. 

For example, for 328P 10 bit ADC conversion, using Pure C you can increase the gain of an incoming analog signals before being presented to the MPU for processing. See how to set that up here. As far as I know, Arduino sketch language can't do this.
 
You also potentially gain better control of a program's size since you only use code space for features you need. 

So--enough introduction!.....let's look at some of the common code fragments you see in Pure C MPU programming.

Here's an example of Pure C--what the hell does this mean?

DDRD |= ( 1 < DDD4);  // answer: same in Sketch as pinMode(4,OUTPUT);

Initially I had no idea.  I need to do some reading!

Why read when there is YouTube? A really good (albeit lengthy) video about "why to use pure C, what is pure C, how do I get Pure C, how do I make Pure C work", is here

For anyone with previous Arduino Sketch programming experience, I think the the video is clear and easy to follow. It's worth a look.



I watched the video a couple of times and began to experiment with Pure C. Here's what I've found so far:
  • You can code using Arduino Sketch in the Arduino IDE, but throw in dashes of Pure C as needed. It all works; the two can mix. UPDATE: not quite. I noticed to mix analogRead() statments into your pure C plus arduino library masterpiece, you need to use void setup() for initialization, not int main() as shown in the code example below. I figure there are other exceptions as well.
  • Does the usual SIM suspect, Tinkercad, work for Pure C development? Sort of. A video showing Pure C on Tinkercad to get the immortal blinking LED to blink is here. But I could not get Tinkercad to work reliably beyond simple blink tests--for instance, using pure C to set up one of the simulated Atmel CPU's built in timers--all programmed in Pure C--caused the simulation to bog down in terms of performance, to the point where I felt it wasn't useful.
  • Virtual Breadboard, as described in this post, works. Oddly, using VBBs IDE to talk to an Amtel ATmega328P directly didn't, but using a Nano SIM, it did.  The developer told me a patch will be needed to have the Atmel SIM work but it's not available yet. Update: in version 6.08 of VBB I have verified that this is fixed.  Update 2-1-21: VBB appears to be End Of Life. Gone!  Oh well

Blink LED written entirely in C.  Doesn't work.  My fault.


If you want to play along at home: here's a rundown of some essentials I needed to get started with Pure C:

I needed the datasheet for the Atmel chip that describes the Atmel 328P MPU, which is the founmd in the  Arduino Uno R3. Get the ATMEGA328P data sheet hereYes, this datasheet has over 300 pages.  

Why all the reading? This will seem rudimentary to a professional embedded-C programmer, but maybe less so for Arduino programmers: Embedded C is all about finding bits in an MPU's registers and manipulating them. These registers hold essential information like "is this pin an input or output?" "Do you want this pin go to binary high or low?" "How should this timer work?" and so on. 

You flip bits in these registers--akin perhaps to turning on and off physical switches--to make things work the way you want. That means, to master pure C, I needed to understand at a very basic level not just a new programming language but also what many of the AVR MCU's registers really do.  There is no way around that. It's a pretty steep uphill climb.

However, to make it easier, Atmel supplies many #define designations behind the scenes to allow you to use names of registers and bits directly in your Pure C code; these macros match the data sheet, making things a bit easier to keep straight.

1 << TWDS ; // set this bit to zero, see the datasheet for that does....

And--there are a whole lot of registers and #defined bits in these Atmel MCUs. There are also a wealth of  Internet videos and web pages going over MCU specifics, like timers, peripherals, serial protocols, and so on. You can learn more about this from those--so--get reading.

I needed to understand how my Arduino board is wired--really.  If an Arduino board has a different pin designation your Pure C code may not work unless you keep which MPU pin goes to which external GPIO pin straight.

For instance, for the Nano I found its schematic here, which clearly shows which pin on the ATMEGA chip goes to which pin on the Arduino Nano board. You will need that information to interface things like LEDs, switches, etc. to your MCU as you write your code. That's because Pure-C doesn't care what pins are called on a development board, rather, it cares about the pins on the MCU IC itself.

I needed to understand a few strange statements you see over and over when reviewing pure C code. 

One we already saw:

DDRD |= ( 1 << DDD4);

This means, for register DDRD, put a 1 (high) into bit DDD4.  This specifically tells the Nano's CPU that pin D4 is going to be an Output.

Getting further into beginner's stuff:

You can OR these "bit shift" statements together:

DDRD =  ( 1 << DDD4) | ( 1 << DDD5) | ( 1 << DDD6) ;

Same idea, but we are putting a 1 in for bits 4, 5, and 6.  So D4, D5, D6 are now outputs.

You can use binary notation:

DDRD = 0b11111111;  // all 8 bits of port D all outputs.

So how to make DDD4 a zero?  Setting DDD4 is an input? Use a NOT, also known as an XOR:

DDRD &=~(1 << DDD4);

And another way to change DDD4 from 1 to a zero (so, flip things?)  This tests DDD4, if DDD4 already contains a 1, it makes DDD4 a zero. If it's a zero, make it a one.

DDRD ^=(1 << DDD4); 

You also set the entire register--for instance, make every pin in the Pin Group D inputs. Here 0x00 means use hex (base 16) to set all the bits to zero.

DDRD = 0x00;

And this sets them all to one:

DDRD = 0xFF;

Another common thing you see all the time with Pure C code: you can mask bits using "&".  This means to the compiler: pay attention to certain bits and ignore others.  

Best shown with an example:

#include <iostream>

using namespace std;

int main()
{
char x = 0;
char result = 0;
char b = 0b11001111;

result = b & 0b00000011;

printf("result is: %x",result);
// result is 3
}


The other thing I see all the time is bit shift: you use << or  >> .  This shifts bits left or right.  

Again best shown with an example:

#include <iostream>

using namespace std;

int main()
{
char x = 0;
char result = 0;
char b = 0x01;

result = b << 2;

printf("result is: %x",result);
// result is 4
}
 
I needed to understand some basics about the C language and how it's different than anything else I've ever seen before. For me, taking an online C++ programming class, combined with studying open source C code that's everywhere, was necessary. 

For example: in python, if you want to use a function, you can think it up, type it into your IDE, and start using it. Not so with C. C and C++ are statically typed languages,  meaning you have to declare what your function will return, as you well as declaring the data type for a variable. For me that was unfamiliar, having previously worked with PowerShell, Python, Perl, PHP, and other dynamically typed languages where the interpreter figured out the variable type for me. This is a quality of C: you have to tell it exactly what you are trying to do.  At first this was hard to get used to, but after programming in C for a bit, I started to appreciate the extra control this gave me over my program.

Enough for now? Just with these few discoveries, I can already read small chunks of Grumbles code and maybe see what he's after. 

To wrap up: Here is a Pure C program I wrote that compiles in Arduino IDE and flashes an LED.  Didn't work at first, now, works on my bench anyway. 

Remove comments, change 1's to 0's, etc., and have fun.

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////



#include<avr/io.h>
#define F_CPU16000000UL
#define myPin DDD2 //change 2 to whatever D group in you are using
#include<util/delay.h>

/*
my expanded pure C blink demo.  
Nano V3,0, with LED tied to pin D4; 
1K resistor between LED cathode and ground so to not fry the LED.
uncomment stuff to experiment.
*/

int main()
  {   

/* all pins in D pin group are now input. For DDRD, 1 means output and 0 means input. */  
DDRD = B00000000;

/* we are putting a 1 into bit DD4 in the DDRD //register, making D4 on the nano an output. */  

DDRD |= (1<<myPin);  


/* make DDD4 (pin D4 on Nano) a zero, now it won't flash because it's an input.  So do the opposite of what I say. */
 // DDRD &=~(1 << myPin); 

/*test DDD4 to see if it's a one. If it's a zero, toggle the //bit to one.  If it's one, toggle to zero  */  
 // DDRD ^=(1 << myPin ); 


// BONUS COMMAND USING HEX vs. BIT TWIDDLING.

/* this will set all D pins but leave TX RX to output */
  //DDRD = DDRD | 0x00 ; 

/* this will set all D pins but TX RX to input */
  
  //DDRD = DDRD | 0xFF ; 

  /*Note: if you screw up TX and RX, 
   * which are part of the DDDx, DDRX, PINx" pin group mishpucha,
   * upload into your arduino a normal sketch with serial.begin().  this fixes it.
*/


/* WHILE(1) is the same as the main repeat forever loop you see on arduino  */
  
     while(1)
     {

 /*     PORTD=B11111111; 
//all port D pins (0-7) are now high.  
      _delay_ms(1000);  
      /* I put in 200 to make sure I'm not running the default "blink" sketch. */
/*
       PORTD=B00000000; //D2 is now low.  same exercise.
      _delay_ms(200);
*/

/* same way to do what we just did with 2 lines!  Go Pure C!
 */

PORTD ^=(1 << myPin ); 
     _delay_ms(1000); 
     }
  }

/* don't breathe the fumes */

UPDATE 4-6-21 I am using C a lot (vs. sketch) these days. Once you start you can't stop! Here is a cheat sheet I use for bit twiddling the I refer to a lot. Structs, not mentioned above, are explained here.

////C PROGRAMMING LOGIC CHEATSHEET

///x and y are uint8_t's:

x |= (1 << 2);  // set bit 2 in x to 1

x &= ~(1 << 2);  // Set bit 2 in x to 0

x ^= (1 << 2);   //flip existing value of bit 2, 
                 //so 1 becomes 0, 0 becomes 1. 

y = (x >> 2) & 1;  //check value of bit 2 in x 
                   //and put what you find into y.


//SAME IDEA USING STRUCT 

struct bits {
    uint8_t a0:1;
    uint8_t a1:1;
    uint8_t a2:1;
    uint8_t a3:1;
    uint8_t a4:1;
    uint8_t a5:1;
    uint8_t a4:1;
    uint8_t a5:1;
};

struct bits mybits;  //instantiate new struct

//set values
mybits.a0 = 1;
mybits.b0 = 0; (etc)

//To toggle bits, these 3 examples do the same thing.

mybits.a0 = !mybits.a0;  
mybits.a2 = ~mybits.a2;
mybits.a4 ^= 1;   

if (mybits.a0)
{
//do something if .a0==1

/*
POWERS OF 2:
bits: 7      6  5   4   3  2  1  0
vals: 128   64  32  16  8  4  2  1
*/


Saturday, January 5, 2019

ReneDSR: Fastest Envelope in the West: Zen and the Art of Tau

Hello again, just finished a new module based on a custom PCB.  The original design seems pretty well known in the DIY synth audio community: Rene Schmitz's "Fastest Envelope in the West".

Find his original page for this design here--scroll to the bottom of the page....

FADSRITW Prototype. No LazerTran front Panel Art yet, still testing it.

The Why in AudioDIWHY: I needed more ADSR's in my rig. What I have now works but doesn't always give me a super quick snappy decay.

I saw Rene's Fastest envelope schematic and thought--this will work" 

To me "fastest envelope" sounds postal; the acroymn is FEITW ("feeet-oo"?) is odorous, so I am calling it "fastest ADSR" or FADSRITW or even FDITW "Fastest Decay in the West". Whatever.

I will use acronyms going forward.

 Here it is:

Eagle BRD and SCM files, wiring diagrams, PDFs used for my take on FADSRITW are available on my website, click here.

About the module: Rene describes a couple of variations of his design--one with 2.2M A,D,R pots, another with 1M pots. Increase the the cap value if you decrease the pot value. To me, with analog envelope devices, the size of the cap creating the "TAU" (which, my EE brother explained to me, is simply the R*C value used as the heart of the ADSR) matters.

This is an RC curve--but what are RC curves, really?  Why does its output "curve"?

Warning: Math zone ahead. 

ReneADSR decay here's the formula to compute your decay control voltage:

V = S*(e^(-t/RC))

where:

V is the voltage at any given time--what we are after.
e is Eular's number (about 2.718), so, a constant
^ means "raised to a power of what follows", so, e raised to -t divided by R*C
-t is (time * -1).
RC is the resistance * capacitance.  That's TAU, baby!
S is the voltage at time = 0

If you plug this into a graphing program like this very cool one you get beautiful curves:


You take that voltage changing over time, and plug it into an appropriately designed VCA or VCF (such as this one, Matohiko Takeda's "Farm VCA") And: Aaaahhhh! The classic Moog/Roland analog synth sound.

A good sounding ADSR > VCF curve makes me very happy indeed.

Another aside: TAU is a Greek Letter and looks like the PI symbol that is missing a leg or pi cut in half:



It  means something different in mathematics, or biology, or astrophysics, or whatever; ditch the RC crapola if you're not a physicist because Tau means way different things to different scientists. This confused the hell out of me for a bit. You learn something every day eh?

OK back to it: from the equation above, it shouldn't matter if R gets big as long as C gets small. Right? Within reason perhaps. That's basic math. But again, how it sounds is way more important than however things look on paper. So what sounds best, really?

Guess we'll find out.

I built my first FDITW using 2.2M pots I found on Ebay (linear taper). 2.2M pots are not at all easy to find, but I found 'em, they arrived via eBay from China and 5 minutes later were soldered into the prototype. Yep! Worked first time! Update: I looked around for 2M or 2.2M audio taper--forget it, I am not sure they even exist?

Honking big 2M2 linear taper pot. The US dime to left, for nonUSAers playing along at home, is approx. 17.9mm in diameter. 

obligatory on the bench shot.

Can't find the pots? In an ElectroMusic forum post, DIY mensch donpachi lays down a cool trick for getting 2M out of a dual gang 1M audio taper pot:



I put this on the bench, and it works, but, if there is a +/- 20% error on each pot you might have -40% error overall, giving you a < 2M pot not 2M, so choose your pots accordingly.  You may have to try a few 1M AT dual gangs to get some with a rough value of 2MB overall. I dug some 1M dual gang audio tapers out of my junk box and pachi'd them in, replacing the linear taper honkers. To me, the FADSRITW sounds more musical with audio taper pots for A, D and R. I also jammed in a DPDT switch to select 2.2uF and 10uF for C3 to switch-a-tau. Yep that works, and you could use a DPTP switch here with 3 values for C3, a rotary with X values, a 4066 controlled by an MPU, or whatever else works for you. Overall another fun build. You can get the Eagle stuff, etc. here.

One more tid-bit: For some reason, I got the circuit to work w/ a standard 555 IC, but not a CMOS 7555. No idea why. I will build more of these and see if I can track that one down.

Going forward: I went online and bought some 1M audio taper pots from Small Bear. Waiting for those as I write this post.  I will build another FASDRITW with 1M, 100 ohm resistors vs. the 220's and maybe some other TAU-values (taulues?).  I'll also post some sound samples.  But no, no scope snaps. My eyes always confuse matters like these. The question: What sounds best, really? I figure the different RC combos will sound exactly the same but who knows.  Update: they do all sound pretty much the same, use 1MB single gang pots, since they are a lot easier to find online.

Part II of this post is here, where I go into variations on the RC parts of Rene's design.

Until then, DBTF.  See ya.


Anything to Clock Subcircuit

Readers:  If you want to build the project featured in today's post, please go to  PCBWAY's  Community pages --a gerber ready to dow...