Author Topic: AVR Tiny for Chorus/Reverb  (Read 6319 times)


AVR Tiny for Chorus/Reverb
« on: April 20, 2015, 04:06:44 PM »
It was asked in my Tiny84 flanger thread if it was possible to make a Chorus.
Before working on the Flanger, I'd built a multi-fx delay using the 8pin DIL Tiny85. Mostly out of curiosity and experimental zeal, it has...

Analog mixing of wet/dry & regen. Normal or Inverse Mix & Regen.
2 delay ranges - Short for Flanger and Long for Chorus and Reverb.
Sine table LFO.
Normal or Inverse Envelope time sweep.

The digital circuit is this...

One of the 85's is used like a BBD delay chip but it only needs one clock input. Delay time is a function of the buffer length and the clock rate. IIRC, the clock rate can run between 7Khz and 60Khz. 7Khz? Yes, it's too low to avoid aliasing, but it has a trick. The pwm is always running at 65KHz and is updated twice in the delay clock cycle. The first update is an interpolated sample between the previous and next value and the second update is the true next value. Although it's only done at the output, there is no aliasing with normal instrument inputs and the effective minimum sample rate starts at 15Khz. This was the only way I could get a long enough delay for chorus/reverb and a wide enough sweep range for flanging. The Short delay option simply switches to a much shorter buffer size (12bytes!)

In the end, I think it served me as a sandbox, but from lessons learned, I wouldn't repeat it exactly like this.
For one thing, the audio is only 8bit. A small MCU like the 85 is likely to leave you wanting 2 functions on the same pin - so it can't have dual PWM for a longer sample word AND a separate/clean Aref for the on board ADC. I've not tried using an internal reference, but wouldn't expect it to be clean enough for audio - but maybe I'll try it...
8bit isn't necessarily bad. It is improved with pre-emphasis and some Companding. Chorus and Reverb have the advantage of having the clean signal present, which hides the lo-fi to some extent. Flanging though, to be as deep as possible, needs the wet & dry signals to have very similar spectra. In this case, they are not, which is why I made the tiny84 Flanger mixing 100% internal.

The other 85, the LFO/Clock took me a lot of work to get satisfactory control from the time/depth & speed pots. Although there was enough CPU time to run math code for scaling the values, the 8bit timers of the 85 cause the settings to bunch too tightly. I wouldn't bother next time, and instead use conventional circuits such as 4046 VCO and dual op-amp LFO to provide the delay clock.

Also, it is too complex. The various types of FX are, I think, best done with more dedicated boxes. I didn't bother trying to make it a stomp box, it's a "studio fx".  I can get some useful noises out of it, so I'll post some clips here soon.

Anyway, if anyone wants to play with it - here the code for the BBD-ish Tiny85...
Code: [Select]
; 312 or 12 stage Bucket Brigade type audio delay for Tiny85.
; Version 10.
; Created for improvements/additions
; Buffer size switching using pin 3. Defined in Equates.
; 312 stage better for "Chorus" range.
; 12 stage delay should give decent flanging effect.
; Doubled sample rate by linear interpolation on playback. Extra sample played on 2nd half cycle
; of delay clock input.
; ADC input, PWM output.
; Sample rate set by external delay clock.
; 1Mhz ADC clock.
; Clock bits - Set for Internal Fast PLL clock no Div8 = 16Mhz
; Pin use- 8pin DIL package
; 1=Reset
; 2=ADC3 audio in
; 3=Port B-4. Buffer size switch input. Set=Long, Clear=Short
; 4=GND
; 5=Aref
; 6=OC0B PWM out
; 7=PortB-2 Delay clock input
; 8=VCC
; *J W Yale, Ashdale Studio. 6th March 2015**************************************************

.INCLUDE "" ;Atmel AT Tiny85

.DEF Temp=R19 ;Temporary register
.DEF TopHi=R18 ;For 16bit compare. Contains Hi byte of max buffer=$01 or $00
.DEF TopLo=R17 ;For 16bit compare. contains Lo byte of max buffer=$98 or $6C
.DEF ADCstart=R16 ;Bit config for ADCSRA reg to start conversion and clear flag
.DEF ADCresultLo=R15 ;Read from ADCL register
.DEF Old=R14 ;Oldest sample to play from delay buffer.
.DEF New=R13 ;Newest sample to play from delay buffer
.DEF Fake=R12 ;Interpolated sample value between old and new
.EQU TopHiLong=$01 ;Change this for high byte of long delay buffer (max $02:60)
.EQU TopLoLong=$98 ;Change this for low byte of long delay buffer (min $00:60)
.EQU TopHiShort=$00 ;Change this for high byte of short delay selection
.EQU TopLoShort=$6C ;Change this for low byte of short delay selection
.cseg ;CODE segment
.org 0
rjmp INIT ;Reset vector

;Port assignment.
ldi Temp,$02
out DDRB,Temp ;All inputs except B1 (PWM OC0B)
ldi Temp,$10
out PORTB,Temp ;Pull ups disabled except input B4
ldi Temp,$08
out DIDR0,Temp ;Disable digital input on ADC3 input
;Setup register constants
ldi ZH,$00
ldi ZL,$60 ;Set pointer to start of RAM.
;For 312 stage delay, RAM is from $0060 to $0198, 12 stage $0060 to $006C
ldi ADCstart,$D4 ;R16=Control byte to start ADC & clear complete flag in main loop
ldi TopHi,TopHiLong ;R18=Top of buffer hi byte
ldi TopLo,TopLoLong ;R17=Top of buffer lo byte
;Setup ADC
ldi Temp,$63
out ADMUX,Temp ;Channel 3, left justified. ADCH contains 8 MSB's of 10 bits
;Enable ADC with prescale 1/16 for 16Mhz CPU clock
ldi Temp,$94
out ADCSRA,Temp
;Setup Timer/counter 0 as fast PWM. No prescaler.
ldi Temp,$23
out TCCR0A,Temp ;Fast PWM out on OC0B
ldi Temp,$01
out TCCR0B,Temp ;No prescaler
;Initialise Buffer RAM and PWM to 127 (mean audio level) for largest buffer size
ldi Temp,$7F
mov  Old,Temp
out OCR0B,Temp
st Z+,Temp
cp ZL,TopLo
cpc ZH,TopHi
;Reset buffer pointer register Z to base $0060
ldi ZH,$00
ldi ZL,$60
sbis PINB,4
ldi TopHi,TopHiShort ;Change buffer top if Switch set for 12 stage delay
sbis PINB,4
ldi TopLo,TopLoShort

;Start ADC
out ADCSRA,ADCstart ;Start new conversion, clear flag

sbic PINB,2 ;Wait for clock input going low
rjmp WAIT0
;Main program loop
sbis PINB,2 ;Wait for clock input going high
rjmp MAIN
out OCR0B,Old ;Play Old
ld New,Z ;Put next play sample in New
;Interpolate a fake (average) sample between Old & New values
mov Temp,Old
add Temp,New ;Fake=(Old+New)/2
ror Temp
brcc SaveFake
ori Temp,$01 ;Round up LSB if clear and carry was set after division
mov Fake,Temp
mov Old,New ;Update Old sample for next cycle
sbis ADCSRA,4 ;Wait until ADC complete
rjmp WAIT1
in ADCresultLo,ADCL
in Temp,ADCH ;Get new sample from ADC
sbrc ADCresultLo,7
ori Temp,$01 ;Ensure sample LSB bit 0 is set if low byte >01xxxxxx
out ADCSRA,ADCstart ;Start new conversion, clear flag
st Z+,Temp ;Store newest sample to buffer and step to next
sbic PINB,2 ;Wait for clock input going low
rjmp WAIT2
out OCR0B,Fake ;Play interpolated sample
;Check for end of delay buffer
cp ZL,TopLo ;Compare 16 bit check for end of buffer 312=$0198, 12=$006C
cpc ZH,TopHi
brne MAIN ;Not end, start next sample.
ldi ZH,$00 ;End of buffer reached, reset pointer to start
ldi ZL,$60
sbis PINB,4
rjmp SHORT
ldi TopHi,TopHiLong ;Change buffer top if Switch set for long delay
ldi TopLo,TopLoLong
rjmp MAIN ;Back to buffer start with long delay.
SHORT: ldi TopHi,TopHiShort
ldi TopLo,TopLoShort
rjmp MAIN ;Back to buffer start with short delay



Re: AVR Tiny for Chorus/Reverb
« Reply #1 on: April 20, 2015, 05:32:48 PM »
That's awesome, you are doing some fanfastic stuff with these chips! Thank you for putting so many comments in the code, too. Makes it helpful for learning.


Re: AVR Tiny for Chorus/Reverb
« Reply #2 on: April 21, 2015, 10:38:41 AM »
Thanks Matt.
Here's a bunch of clips from it on Soundcloud...


Re: AVR Tiny for Chorus/Reverb
« Reply #3 on: April 23, 2015, 02:56:34 AM »
Loving the work. Just wondering what dev kit if any you are using for the AVR Tiny?


Re: AVR Tiny for Chorus/Reverb
« Reply #4 on: April 23, 2015, 05:42:34 AM »
AVR Studio 4 (I have more recent, but 4 runs faster). AVR Dragon for ISP programming, but I've been programming them in a ZIF socket on the Dragon.
No dev board used. I have one, but I find it's little help outside of pure digital stuff. In fact, I haven't used mine since the initial learning "buttons & leds" phase ;) A proto/breadboard works better for me since I only need a 5v reg for the AVR.


Re: AVR Tiny for Chorus/Reverb
« Reply #5 on: April 23, 2015, 06:05:26 AM »
ah OK. Played around with PICs a bit recently and  want to play about with other platforms. Might look into the AVR route. Looks fun!


Re: AVR Tiny for Chorus/Reverb
« Reply #6 on: April 23, 2015, 09:02:18 AM »
OK newbie...
I started with this...
But the essential development bit is the Dragon board...
There are cheaper programmers. You need to add your own ZIF socket & pin headers to the Dragon and have some jumper leads. Atmel scramble pinouts with every chip, so there's no standard programming pin order. The Dragon requires you to fit the jumpers on the board to suit whatever chip you're programming.
This page shows what's needed...
I fitted a 28pin ZIF on mine as I don't expect to use many 40pin AVR's.

If you have an Arduino, it can be used as a programmer.

I've never used the debug feature -  where you can watch the MCU internals on the PC while the things running in circuit. AVR Studio has a software emulator so you can run your code before committing it to a chip. You can assemble the code and play with it in the emulator without spending anything but time.

The current AVR Studio 6 is VERY bloated, needs .NET installed and adds features that don't apply for Mega and Tiny devices. Fortunately you can still get version 4 -  it's all free.



Re: AVR Tiny for Chorus/Reverb
« Reply #7 on: April 23, 2015, 03:52:37 PM »
anotherjim, thanks for the info. Going to read this and do some purchasing!



Re: AVR Tiny for Chorus/Reverb
« Reply #8 on: April 10, 2018, 01:08:05 PM »
Re-up scheme by request.