AN written by Evert Dekker (This AN has also Part2, follow this link )
What is it?
It’s a
very simple, only 2 resistors and 1 condensator, sound playback. And it sounds
amazing good, check the TheFinalResult.mp3 file.
This is
based on an article by Mariano Barron in the Circuit Cellar #180 July 2005. Due
the copyright I can’t publish the article here. You can buy your copy at the
Circuit Cellar website.
The software we need to encode
the WAV files is free available from the Circuit cellar ftp server, in this
file there is also a short description how it works.
With the Rc
Sound Encoder software we compress the WAV to RC2 coding. This coding will be
stored in eeprom and played back with this simple “Soundcard”
Every sample requires only 1 bit, so for 1
second 44,1kHz sound we need 5512 Bytes storage space. It’s not much but for
most MCU too much to store in the flash or internal eeprom. Therefore we store
the sound samples in an external i2c eeprom.
Hardware

Schematic
is very simple. I’m using a Mega128 running on 16MHz. I2c eeprom (24c256) is connected
with the hardware i2c (scl/sda). Software i2c will not work, this is to slow,
maybe it will work with 22050hz samples but I didn’t try that.
In the
upper right corner we have the Rc2 decoder and optional an low pass filter and
a simple amplifier.
Timing
Even the
timer isr calculation is simple Crystal/prescaler/sample rate =
16000000/1/44100 = 362 = &H016A .
If you like
to use an other sample rate or crystal you need to recalculate the timer.
Diy
The
document RC2-Howto.pdf describes how to make your own Eeprom file with your
sound or speech, this document can be found in the Zip file. The zip contains
also the used WAV files, the ready to run demo Eeprom hex file and some ASM
files.
Limitation
In all the
routines are 16bits addressing used, therefore it’s not possible to use
Eeprom’s larger then 512KB. If you change the routines you can use more then
one 512KB i2c eeprom (you can hook up 4 to 1 i2c bus), but the RC-coder
software uses also 16bits addresses and that’s something that we cannot change.
Required tools
- Sound
edit software, Windows sound recorder will do, but there’s always better
- RC
Sound encoder ftp://ftp.circuitcellar.com/pub/Circuit_Cellar/2005/180/Barron180.zip
- Atmel Avr studio 4 www.atmel.com
- Bascom AVR www.mcselec.com
- I2C
Eeprom programmer including software
The code
Code is
written and tested in Bascom 1.11.9.0.001 license.
Note from MCS
To make the conversion of the ASM files simpler, i added some VB code to Everts VB programmer that allow to generate the BIN out of the ASM files. You do not need Studio in that case. Also, some files were added for the Mega88 running at 8 Mhz.
'------------------------------------------------------------------
' R2C Decoder voice playback
' Playback
sound and voice with very simple hardware 2xR 1xC
' By
Evert Dekker 2008 R2CDecoder@Evertdekker dotje com
' Created with Bascom-Avr: 1.11.9.0.100
'------------------------------------------------------------------
$regfile = "m128def.DAT"
$crystal = 16000000
$baud = 19200
$hwstack = 50
$swstack = 50
$framesize = 40
$lib "I2C_TWI.LBX" 'Setting up i2c hardware bus
Config
Twi = 400000 'Hardware i2c bus speed
Config
Scl = Portd.0 'TWI (i2c) ports on the Mega128
Config
Sda = Portd.1
Const
Addressw = &B10100000 'slave write address eeprom
Const
Addressr = &B10100001 'slave read address eeprom
Vp1 Alias Porta.1 'Voice pin 1
Vp2 Alias Porta.2 'Voice pin 2
Config Porta.1 = Output
Config Porta.2 = Output
Config Timer1 = Timer , Prescale =
1 , Compare A = Set , Clear Timer = 1 'Setting
up the timer
Compare1a = &H016A 'Timer1 comparator
Enable Interrupts
Enable Compare1a
On Compare1a
Timer1_int
Stop Timer1 'Stop the timer, not yet needed
'==== Declaration
Declare Sub
Read_eeprom_word(byval Adress As Word , Valueword As Word)
Declare Sub
Playsample(byval Sample As Byte)
Declare Sub
Read_eeprom_index
Dim
Samples As Word , Start_byte(10) As Word , Lenght(10) As Word 'If
you have more then 10 voices programmed, then incr this here.
Dim
Bytetodo As Word , Outbyte As Byte
Dim
Temp As Byte , Tempw As Word , Lus As Byte
Dim
Bitcount As Byte , Tempadress2 As Byte
'=== Main ===
Do
Read_eeprom_index 'Read the eeprom index because we need to know number of samples,
startadress and lenght
Print
Samples ; " Samples present in the eeprom"
For
Lus = 1 To Samples
Print Lus ; "e sample start at eeprom adress: &H" ; Hex(start_byte(lus)) ; " is &H" ; Hex(lenght(lus)) ; " bytes
long."
Next For
Wait
3
For
Lus = 1 To Samples
Playsample Lus
Wait
1
Next
Lus
Loop
End
'=== Sub routines ===
Sub
Playsample(byval Sample As Byte)
Bytetodo = Lenght(sample) 'Number of bytes to be processed
Tempw = Start_byte(sample) * 2 'Index
is in word, need now bytes so *2
I2cstart 'Generate start
I2cwbyte
Addressw
Tempadress2 = High(tempw) 'High(adress)
I2cwbyte
Tempadress2 'highbyte
adress of EEPROM
Tempadress2 = Low(tempw)
I2cwbyte
Tempadress2 'lowbyte adress of EEPROM
I2cstart 'repeated start
I2cwbyte
Addressr
Start Timer1 'Start the timer and therefore the
playback
Do
If
Bitcount = 7 Then '1 byte processed
I2crbyte Outbyte , Ack 'Read byte from eeprom
Decr Bytetodo '1 byte less todo
Bitcount = 0 'Reset bits processed
End If
Loop Until
Bytetodo = 0 'Do until all the bytes from the sample are processed
Stop Timer1 'Ready stop the timer
I2crbyte
Temp , Nack 'read extra byte with Nack to finish the i2c bus
I2cstop 'Stop i2c
Vp2 = 0 : Vp1 = 0 'Silence the voice pins
End Sub
Timer1_int:
Vp2 = Vp1 'Voice pin2 is the previous setting of
voice pin1
If
Bitcount >
0 Then Shift
Outbyte , Right , 1 'shift the bits out
Vp1 = Outbyte.0 'Set voice pin1
Incr
Bitcount 'Next bit
Return
Sub
Read_eeprom_index 'Find the start adresse of each Voice. Adress is stored as word
Read_eeprom_word 0 , Samples '1e Byte in the eeprom contens the number of programmed samples and is
the low byte of the first sample
Temp = Low(samples) : Temp = Temp -1 '
For Lus = 0 To Temp 'Loop the number of Samples found
Tempw = Lus * 2 'Reading words, so steps 2
Read_eeprom_word Tempw , Start_byte(lus + 1) 'Read the start adres of the samples
Tempw = Start_byte(lus
+ 1)
Tempw = Tempw * 2 'Reading words, so steps 2
Read_eeprom_word Tempw , Lenght(lus + 1) 'Read the lenght of the sample from the
eeprom
Rotate Lenght(lus + 1) , Left , 8 'Msb and Lsb are inverted so swap them
Next Lus
End Sub
Sub
Read_eeprom_word(byval Adress As Word , Valueword As Word)
Local Tempadress As Byte , Valueh As Byte , Valuel As Byte,
I2cstart 'generate start
I2cwbyte Addressw 'slave adsress
Tempadress = High(adress)
I2cwbyte Tempadress 'highbyte adress of EEPROM
Tempadress = Low(adress)
I2cwbyte Tempadress 'lowbyte adress of EEPROM
I2cstart 'repeated start
I2cwbyte Addressr 'slave address (read)
I2crbyte Valuel , Ack 'read byte
I2crbyte Valueh , Nack
I2cstop 'generate stop
Valueword = Makeint(valuel , Valueh)
End Sub
|