Monday, May 31, 2021

ProMicro HID Keyboard Emulator

Quick one this time. The Arduino ProMicro (examples here and here) is based on an Atmel 16u4 MCU and has HID keyboard emulation ready to go--use the keyboard.h functions in your sketch and go. It also has a USB port. That makes creating PC keyboard emulators, which work in parallel to your normal PC keyboard, a breeze. 

A good tutorial for this is here.


Arduino Pro Micro


 I will be using something like this for the continuing PNG sequencer project (part I post for that ongoing project is here) so this time I got a couple of HID emulators working using junk box parts and plastic cases I had lying around.


I used a couple of Hohner harmonica cases to hold the proMicro, switches, and DS3231 timer IC.

The "dtime" button selects the current time off a DS3231 I2C real time clock and fakes the PC into thinking someone typed this date-time in--I'll test it right now!  5/31/2021 16:17:22  Ah!  Works!!

The other 2 buttons can be set to produce a text string, anything you want.


The ProMicro is held in place with a 3D printed case; download the SVG file here. It took about 20 minutes to print. The plastics throughout are easily/sloppily augered out with a dremel grinder.

I used the cheapest parts possible. The ProMicro and DS3231 breakout boards are a $2-$3USD  AliExpress clones. The I2C based RTC holds time OK as long as it has USB power--after that it goes out of time pretty quickly, although doesn't reset itself to zilch. So it kinda works, but not great. 

I guess you get what you pay for right? After a power outage I upload the code into the ProMicro again which gets the clock working accurately; the code sends the time of the last compile to the DS3231 by default.  

Good enough for now, but for the sequencer this has to be fixed.  I assume (?) that if I use a better quality DS3231 timer, better battery etc., this will work; we will see.


You can get the ino Arduino sketch for this emulator below. 

There are many different RTC DS3231 Arduino libraries out there; I used Adafruit's which you can get here. Instructions about how to install this library into Arduino IDE is here.

I assume readers can figure out the ProMicro's wiring--the switches are momentary NO's connected from D pins to ground--from the code. the DS3231 is connected to Power, ground, and ProMicro pins 2 (SDA) and 3 (SCL).   

To get the real time clock programmed: for the first time run the code below.  Make sure to read the comments and comment out statements accordingly--there are different time setting algorithms in this sketch depending on your use case.

Until next time, don't breathe the fumes.


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


#include "RTClib.h"

#include <Keyboard.h>


String getdt();


RTC_DS3231 rtc;


char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};


int pin = 10;  // 

int mspin = 9;

int datepin = 7;




void setup()

{

  

 /*

///////////////////RTC CLOCK BS//////////////////////////////

arduinos don't have RTC


we are using RTC3231 from Maxim.

for pro micro here are I2C pins

2 > SDA, 3 > SCL


Library used is this one:

https://learn.adafruit.com/adafruit-ds3231-precision-rtc-breakout/arduino-usage

be careful, there are lots of other 3231 Arduino libraries.  Others probably won't

work with this sketch


*/


    //RTC setup:

    Serial.begin(9600);

    if (! rtc.begin()) 

    {

        Serial.println("Couldn't find RTC");

        Serial.flush();

        abort();

    }


  if (rtc.lostPower()) 

    {

    Serial.println("RTC lost power, let's set the time!");

    /* When time needs to be set on a new device, or after a power loss, the

     following line sets the RTC to the date & time this sketch was compiled

I have found you never need to comment this next line.

  */

    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

    }


  /* UNCOMMENT BELOW TO SET DATE TIME ON RTC TO TIME SKETCH WAS COMPILED FOR THE VERY FIRST TIME.

When time needs to be re-set on a previously configured device, the

following line sets the RTC to the date & time this sketch was compiled. 

HOWEVER!! COMMENT THE LINE BELOW AFTER YOUR DEVICE RTC HAS BEEN PROGRAMMED THE FIRST TIME.  

If you run this next statement on an already programmed RTC I have found the RTC may not work the way you want after a power loss.  

  */

  

  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));


  

  /* 

  UNCOMMENT AND CHANGE NEXT LINE TO SET THE TIME:  y m d h m s

otherwise compile time is blown into RTC at sketch upload.

NOTE! USING THE LINE BELOW MAY NOT ALLOW RTC TO CORRECTLY TRACK TIME AFTER A POWER LOSS.

  */

  

 // rtc.adjust(DateTime(2021, 3, 19, 8, 56, 0));

  

  

  pinMode(pin, INPUT_PULLUP);  // Set the button as an input

  pinMode(mspin, INPUT_PULLUP);  // Set the button as an input

  pinMode(datepin, INPUT_PULLUP);  // Set the button as an input

  

  digitalWrite(pin, HIGH);  // Pull the button high

  digitalWrite(mspin, HIGH);  // Pull the button high

  digitalWrite(datepin, HIGH);  // Pull the button high


  Keyboard.begin();


}




void loop()

{


 

  if (digitalRead(pin) == 0)  // if the button goes low

  {

    

    Keyboard.print("yer-text-0-here");  // 

    delay(1000);  // delay so we have poor mans debounce

  }


    if (digitalRead(mspin) == 0)  // if the button goes low

  {

    

    Keyboard.print("yer-text-1-here");   

    delay(1000);

  }

  


   if (digitalRead(datepin) == 0)  // if the button goes low

  {

    

    String gg = getdt();  


    {

    Keyboard.print(gg);  

    }

       

   delay(1000);

  }

   


}  


String getdt()

{


 DateTime now = rtc.now();


    int hour = now.hour();

    String hourStr = String(hour);

    if (hourStr.length() == 1)

       {

        hourStr = "0" + hourStr;

       }

    

    int minute = now.minute();

    String minuteStr = String(minute);

    if (minuteStr.length() == 1)       

       {

        minuteStr = "0" + minuteStr;

       }


    

    int second = now.second();

    String secondStr = String(second);

    if (secondStr.length()== 1)

       {

        secondStr= "0" + secondStr;

       }

       


    String TimeStr;

    TimeStr = hourStr + ":" + minuteStr + ":" + secondStr;


    int day = now.day();

    String dayStr=String(day);


    int month = now.month();

    String monthStr=String(month);


    int year = now.year();

    String yearStr=String(year);


    String DateStr;

    DateStr = monthStr + "/" + dayStr + "/" + yearStr;


    String FinalString;

    FinalString = DateStr + " " + TimeStr;

    return FinalString;

Thursday, May 20, 2021

AVR based Dirty Digital LFO--Written in Embedded C--Welcome to the Land of the Missing Blog Readers

Finally! after weeks coding, building and debugging a fully digital voltage controlled LFO module, it's done, it works, and ready to be racked.

Mod Synth LFO module based on an Atmel 328P, written entirely in embedded C.


The land of missing readers--what? This module was developed entirely in embedded C, read more about that in an earlier post; here. Many thanks to audio diy legend Grumble aka "BigDutchEd" for inspiring the switch to embedded C.

I figure most hobbyists won't want to build this LFO, or even read its underlying code, since it's not based on Arduino hardware and its Sketch programming language, Micropython, CircuitPython, mbed, or other high level languages, all aimed at makers who would rather "just build things".  

That's understandable and of course is A-OK, but it's not where I am coming from.  

For me this entire pursuit is about learning. How do these gizmos work, really? Otherwise, I'd build kits or even better, buy a lot of ready to rack audio gear from these guys.

So if you are curious about embedded C  and want to see how this works, or maybe even build C based audio modules (right?) check out my github page here.  It contains eagle files, wiring diagrams, PDFs, all the current C code, and all the rest, for this dirty LFO design to date.

ready to test....


About the Dirty Digital LFO: The "normal" way to code this would be to create an array of values and the walk the array to send the values to a DAC. Walk the array faster, by skipping memory cells, for higher frequencies. 

Something like this I figure is used on a lot of the commercial "ROMplers" and digital audio/CV generators out there now, and there are a whole lot of them available for purchase. 

Since this is diWHY--where it's OK to try something "different"--I tried to dream up an LFO that doesn't use a lookup table. 

The resulting output I figured would be gritty and distorted sounding, but at least it won't end up working and sounding the same as every other LFO out there. 

More info about the basics of how I made this work and software design choices are here. The simple 328P PCB--which cannot easily run Arduino sketches BTW, just C and C++ code--is discussed here.

OK let's make a simple synth module out of this.

This is still extremely experimental, so right away I know I want to use a more forgiving format than Euro--as usual, I used FRAC, which is cheap, super simple, butt ugly, and best of all, has no practical depth limitations for PCBs. 

I tried to make operation of this module simple as well--a 0-5V CV input to control output frequency, an output jack, a toggle switch to select course output frequency; a momentary switch (inspired by Mutable Instruments) that selects a waveform and lights corresponding LEDs, and pots to control frequency at input and offset voltage at output. 

 

The board in the center is a "mini AVR board", post is here.  Left is the PCB that lives behind the front panel.  Right are 2u Frac "blanks" for the front panel design.


Does the Dirty Digital LFO make balloon animals? 
No. The triangle wave still only goes to 22hz, but i can probably figure out a way to improve this (software based hardware builds--they are never done.)  As predicted, this LFO has an 8 or less bit grainy sound which is cool in its own way. Cleaned up with some lubrication when it needs to sound "more analog", but yes, it's definitely diff-rent.

I can also add other waveforms in the future--sawtooth? random? Stairstep? Sample/hold? In my addled mind I think this won't be hard to code--but finding the time may be. Overall, I tried to make the code as modular as I could, which is what I think C is designed for, and ads/changes should be relatively easy to add as I think them up.

The front panel used was built on a PCB; not metal, to save time and cost. How-to posts for that are here and here.  


For this prototype I printed out the PCB for the buffer circuit and taped it to a blank front panel.  Then drilled out the panel. Otherwise I end up with 4 leftover PCBs front panels from the fab house. instead I am left with 4 2u blanks I can use for other things

 
The new "pots board" used for this DLFO (again--github for schems etc. is here) is extremely simple; it's a few op amp buffers and home for switches, jacks, and LED's.  Also it has a socket for a 12 bit DAC (MCP4921--SPI--very useful and easy to use DIP IC) which is not a peripheral that comes built into a 328.  

If I was going to make a bunch of these I'd make make it +/- 12V "eurorack" and SMD; the circuits should work with +/- 12V without modification. I'd add a buffer/interter (post here--about halfway down) and the portamento subcircuit to the "pots" PCB but for this build they are daughterboards hanging off the front panel.  

The board could probably work with 3-4HP due to its simple hardware design if the SMD parts were laid out correctly. Not here/not now though...I don't have the time.



The MCU and pots board are at a right angle. Good for one-off prototyping of embedded C projects, but I wouldn't do this for something more serious.


Also on the bench it's easy to test....hook it to a scope:



OK enough C-thing for now.  I will use it in my rack for a bit before I add more waveforms and make more software and hardware modifications--but with so much time and so little to do that may never happen.  We will see....Oddly after developing in C for a bit, I don't see myself going back to a higher level language MCU programming with sense of urgency. I feel (oddly/unexpectedly?) that coding in Pure C is easier than Arduino Sketch once you get the hang of it. Embedded C can be straightforward, for AVR MCU's how to write code is extremely well documented, and of course, Embedded C is really frustratingly fun to debug....  

If I get around to that, I will do another post and update github. In the meantime, well, if you've made it this far, thanks for reading--and be warned: more embedded C posts are coming.

Update 10-31-21 The LFO that started on this post is done (finally!) go here.




JTAG to SWD Converter

Readers: If you'd like to build the project featured in today's post, please go to PCBWAY's Community pages--gerber file, KiCAD ...