Goooooood evening dear makers! (and, in this case, I hope also musicians! 😉 )
It’s toooooo much time that I work on my projects without new posts, and I apologize for this.
The fact is that I have -as you know- many activities in parallel to making open source *ware projects: my work (I work in the frame of space projects for artificial satellites, for example I uploaded a little part of me on JUNO, and especially on the Italian part of Juno: the JIRAM instrument), my music (I play in some bands, and I also produce a lot of solo music: check it out and download all at www.marcolastri.net ) … and obviously my family!!! 🙂
So, since time is short… and life is too short, let’s start.
We can start from this beautiful project: Meeblip Anode.
It is a great monophonic synthesizer based on ATMEGA32P, with a really great sound, very deep and powerful.
…Have a look to demos on Youtube for the proof of what I’m writing.
I loved the MeeBlip Anode sound from the first time I heard it. In Italy we call this feeling “Amore al primo ascolto”…. 😀
And to me, the greatest thing of MeeBlip Anode is that this incredible project is completely (hardware and software) open source!!! You can buy a pre-built one, but you can also self-produce it in order to play it with your band or to modify/hack it (or both the things, like me ! 😉 )
Well. I obviously self-produced one prototype of Anode and I started to play it in my music projects, but I wanted to add some (in my opinion) important functionality to this great project.
The idea has been of my father Gualtiero which, looking me playing with Anode and modifying the position of potentiometers, said to me: “It sounds very good… but… in which way you know the values for potentiometers?”
Woooow, thanks dad! It was the idea: add a numerical/visual indication of pots values using a display. An OLED display (because the OLEDs don’t have the backlight regulation…so less electronics to add! 😉 ).
And I decided to call this mod “Italian Way” because in Italy we always need visual information. For example think to our famous gestures when we (try to) talk in English to tourists to give them indication on the streets of our cities. 😀
So, I decided to proceed in the following way:
- Look in the electronic schematic if ATMEGA32P has some free GPIO to be used in order to command the display (at minimum 6 pins, which is the minimum for commanding the great part of displays)
- Since the Meeblip code is written in AVR assembler, download and study the datasheet (and instruction set) of the ATMEGA32P. I was a good assembler programmer once upon a time…but now I am a little older, so… 😉
- Find a good AVR driver or set of subroutines for commanding display, written in assembler
- Decide which synth values to display on the OLED!
- Modify these subroutines in order to display in quasi-realtime, and integrate them in the original code
- Modify the original Meeblip code in order to use the display subroutines.
Well…the work has been long (long, long, very long and again looooooooong) and hard (hard, very hard… etc.).
But I think it has been a great work! 🙂
I uploaded all the code on GitHub. I dont know if I well done all the process, but this is the first time with GitHub for me…. 😉
For the project I realized a new branch from the official one. So you can download all my code from: https://github.com/garretlabs/meeblip-anode/tree/meeblip_anode_italian_way
The GPIO pins to be used
I had been lucky: the MeeBlip Anode has some free (and not connected) GPIO on the microcontroller, so they can be freely used to command a display.
They are reported in the following photo:
I decided to use an OLED display by Newhaven ( Mouser code 763-NHD-0420DZW-AG5), which will use 4 pins for data (+ 2 pins for Enable and RS) chosen from PB0, PB1, PB2, PB3, PD2, PD5 and PD6 (plus 5V and GND).
The mapping used for the connection between the display and the ATMEGA32P has been the following:
- Display pin 1 (Vdd): VCC
- Display pin 2 (Gnd): GND
- Display pin 6 (data 0): PB0
- Display pin 7 (data 1): PB1
- Display pin 8 (data 2): PB2
- Display pin 9 (data 3): PB3
- Display pin 4 (RS): PD5
- Display pin 5 (E): PD6
So… I solded the pins of ATMEGA32P to display pins using a 9 pins male/female connection (such as a simple serial connection). The result has been the following:
The datasheet and code study
Simple step…but very tricky! 🙂
Well, during this step I downloaded the Atmel Studio 6 (freely available) and I wrote some example code, I used the debug function on the simulator and then I created a project based on the Meeblip Anode original code downloaded from Github (and obvioulsy I succesfully recompiled it).
The display driver written in AVR assembler and his
I found a really good set of subroutines written in AVR assembler for ATMEGA328 (but it is working also on ATMEGA32P) to command displays using 4 wires. This is the complete code from which I started.
I created the file LCD.inc, and I added it to the Atmel Studio project. Obviously I changed the GPIO assignments in order to match to GPIOs used in my situation. I also added some modification regarding the fact that I would like to display values taken from the RAM of the microcontroller and not from the program memory (as is in the driver). This is the fundamental modification, at line 786 of file LCD.inc:
;lpm temp_lcd, Z+ ; ///ML: removed since this instruction read from Program Memory ld temp_lcd, Z+ ; ////ML: get a character from RAM
And I also added some ad-hoc subroutine to be used in the frame of the modified MeeBlip code. They are the main ones:
- MYLCD_PREPARE_GUI is the subroutine which prepare the display inserting the fixed labels (they wont change during normal operation of synth).
- MYLCD_UPDATE is the main subroutine used to refresh the display (pots values and switches status). It refreshes tha display on every 100 milliseconds.
- MYLCD_CLEAR is used to clear all the display
Note also that in order to display numeric values in the display, a conversion between the values and his correspondent string should be done. For this I found online a very simple subroutine which is called in order to have the values to display in ascii format. This is the subroutine contained in the file SimpleASCIIConversion.inc:
HEX_2_ASCII: bcd: ldi r18, -1 + '0' _bcd1: inc r18 subi r16, 100 brcc _bcd1 ldi r17, 10 + '0' _bcd2: dec r17 subi r16, -10 brcs _bcd2 sbci r16, -'0' ret
Well… now we can include and use the file LCD.inc inside the original MeeBlip code.
Synth values to display on the OLED
I chose to display the values directly tied to the potentiomenters position and to switches positions. But it is only an idea: you can decide to display also other parameters. 😉
In this hand-made drawing you can see the Anode panel with the names of global variables tied to pots and to switches.
Under each switch you can see the switch number to refer in the code. Under each potentiomenter (in the  parentheses) you can see the name of the variables used to memorize the pot values.
Note that the pot on the bottom-left is used for two purposes (waveform and width), depending on the position of switch 3. The real variable names for this pot are the following (I know, the drawing is not updated to the last revision of my code…. but I loved to report it in my post 😉 ): WAVETABLE and PULSE_KNOB_LIMITED.
So in the code I managed this in order to display the right values depending on the siwtch position. You can see in file LCD.inc at the labels DISPLAY_WAVETABLE_VAL and DISPLAY_SWEEP_VAL. The choice of the path is done at lines 301 to 303, analyzing the current (and saved in a temporary variable) position of the switch 3.
The other variables names to display reported in the drawing should be OK…. I hope! In any case you can refer to the code, which ever says the truth! 🙂
Integration with Meeblip original code
I included the file LCD.inc after the inclusion of file “subroutines.inc”.
I defined some variable in variable_definition.inc:
///ML 20x4 lcd strings (4 rows of 20 chars+'\0') my_LCDstring4: .byte 21 my_LCDstring3: .byte 21 my_LCDstring2: .byte 21 my_LCDstring1: .byte 21 //ML temporary variable in RAM temp_in_RAM: .byte 1
After this, in the main program, the LCD is initialized using:
rcall LCD_START //---start delay routine push r18 push r19 push r20 ; Generated by delay loop calculator ; at http://www.bretmulvey.com/avrdelay.html ; ; Delay 8 000 000 cycles ; 500ms at 16.0 MHz ldi r18, 41 ldi r19, 150 ldi r20, 128 L1: dec r20 brne L1 dec r19 brne L1 dec r18 brne L1 pop r20 pop r19 pop r18 //----end wait routine--- rcall MYLCD_CLEAR //prepare LCD gui (not to be refreshed at each basic cycle!) rcall MYLCD_PREPARE_GUI
Then, the display refresh routine is called at each cpu cycle using:
Note that, since the memory occupation has been increased, I had modified some “rcall” instruction in “call”. You will find these changes searching for this comment:
//ML--->>changed rcall in call to avoid error " relative branch out of reach"
Well, that’s (mainly all)!
Recompiling the code and burning the binary on the ATMEGA32P you should obtain (after a screen reporting the name and the version of the synth) something like this:
I’m sorry for the bad picture…but I was so excited! 🙂
The tests using the synth have been all successful, that is:
- MIDI IN is OK (no MIDI note is lost during play)
- Audio is OK (the notes produced with the working display have the same waveforms of them produced by the original Meeblip Anode firmware, I tested it with oscilloscope)
- The interaction with the pots and switches are OK (the refresh of values on the display is very fast respect to the actions on the pots and switches).
So…it seems that a refresh rate of 100 milliseconds should be a good choice for ATMEGA32P computational load!
This is my MeeBlip Anode “Italian Way”, and now, after this great ordeal, I am ready for a (big) glass of Italian grappa. 🙂
I recall here the link to the code in GitHub: https://github.com/garretlabs/meeblip-anode/tree/meeblip_anode_italian_way
…Bonus Easter Egg (for die-hard geeks only): overclock it!
I am an old style geek… some years ago one of my hobbies was to overclock the CPUs of my computers.
I know that ATMEGA32P can be connected to a crystal with maximum frequency of 16Mhz (following the datasheet). But…I love the risk (hmmmm…. only on electronics things! 😉 ) so I wanted to connect him to a 20Mhz crystal.
With some basic code modification, you can have your overclocked Meeblip Anode “Italian Way”.
These are the modifications.
Firstly in the anode.asm file we change the cpu frequency:
.SET cpu_frequency = 20000000 //ML changed the CPU frequncy to 20Mhz
The other basic modification is the Timer 0 initilization (which is the hearth of the MeeBlip sound generation):
;initialize Timer0: //ldi r16, 49 ;\ ; Set sample rate to 40.00 kHz //ML---> commented, since we need a new prescaler value ldi r16, 62 ;\ ; Set sample rate to 40.00 kHz: ML---> we use 62 if the clock is 20Mhz since 16Mhz:49=20Mhz:x... in this case we have always the note in tune! out OCr0, r16 ;/ OCr0 = 49 (///ML---> 62 on overclocked version) gives 40000.00 Hz sample rate at 400 cycles per sample loop. ldi r16, 0x0A ;\ clear timer on compare, out TCCr0, r16 ;/ set prescaler = CK/8
Note that I used the value 62 for r16, instead of theoretically correct value 61, since I used a software tuner to have the best sound (Tunafish for MacOSX) and trying the values around 61.
Then I add a warning also in the initialization of Timer 2 PWM controlling cutoff…
ldi r16, 0b01100001 ; Phase correct PWM, no prescaler ///ML WARNING: verify if the soud is nice with 20Mhz clock, else adjust!!!
For me the sound is nice…. 😉
In the LCD.inc file you should finally set the new frequency:
.equ fclk = 20000000 ;///ML---->new system clock frequency (for delays)
This should be all for this easter egg… but I think you should do many other improvements of the code!
I had no problem and I played (and I’m playing) with great satisfaction the overclocked synth in my home studio for several projects…. but note that nothing is guaranteed with this mod. So handle with care! 😀
Phhhhhheeeeewww (I can rebreath now :-D)….Well geek boys & girls, that’s really all for this time.
It was a long time without a post on Garretlabs, but with this one I think I paid my debt with DIY community and to Garretlabs readers!
Bye bye folks… and keep always in touch with Garretlabs!