The idea is to incorporate voice in MCU project. I’ve found a good example http://playground.arduino.cc/Code/PCMAudio, modified little to use with my ATmega8 and it’s working with data sample stored in MCU. But as I need more space (upto 5 sec. of msg.), I want to use external eprom (24c512 is handy to me & sufficient for my sample).
I’ve burn eprom with voice sample (8 Mhz, 8bit) & trying to run with the below code. Though I can’t get any result (No voice, No led blink in place of speaker, No serial output when using serial monitor) ! I only assume that the eprom can’t response in such a fast ISR/interrupt ?? Pl. tell me if any solution to this problem.
// ATMega8, 16Mhz., EPROM 24C512
/*
* based on speaker_pcm
* EPROM Library from : https://github.com/mikeneiderhauser/I2C-EEPROM-Arduino
*/
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <Wire.h>
#include <EEPROM24LC256_512.h>
#define SAMPLE_RATE 8000
unsigned int sounddata_length=65000;
int ledPin = 13;
int speakerPin = 11;
volatile uint16_t sample;
byte lastSample;
//define eeprom chip (1 per chip)
EEPROM256_512 mem_2;
// This is called at 8000 Hz to load the next sample.
ISR(TIMER1_COMPA_vect) {
if (sample >= sounddata_length) {
if (sample == sounddata_length + lastSample) {
stopPlayback(); }
else {
// Ramp down to zero to reduce the click at the end of playback.
OCR2 = sounddata_length + lastSample - sample; }
}
else {
//Serial.println(sample);
OCR2 = mem_2.readByte(sample);
}
++sample;
}
void startPlayback()
{
// THIS IS MODIFIED CODE FOR USE WITH ATMEGA8
pinMode(speakerPin, OUTPUT);
// Set up Timer 2 to do pulse width modulation on the speaker pin.
ASSR &= ~(_BV(AS2));
// Set fast PWM mode
TCCR2 = _BV(WGM21) | _BV(WGM20);
TCCR2 = (TCCR2 & ~(_BV(COM20))) | _BV(COM21) ;
TCCR2 = (TCCR2 & ~(_BV(CS22) | _BV(CS21))) | _BV(CS20);
//Serial.println("Starting, Please wait...");
// Set initial pulse width to the first sample.
OCR2 = mem_2.readByte(0);
// Set up Timer 1 to send a sample every interrupt.
cli();
// Set CTC mode (Clear Timer on Compare Match)
// Have to set OCR1A *after*, otherwise it gets reset to 0!
TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));
// No prescaler
TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Set the compare register (OCR1A).
// OCR1A is a 16-bit register, so we have to do this with
// interrupts disabled to be safe.
OCR1A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000
// Enable interrupt when TCNT1 == OCR1A (p.136)
TIMSK |= _BV(OCIE1A);
lastSample = mem_2.readByte(sounddata_length-1);
sample = 0;
sei();
}
void stopPlayback()
{
// Disable playback per-sample interrupt.
TIMSK &= ~_BV(OCIE1A);
// Disable the per-sample timer completely.
TCCR1B &= ~_BV(CS10);
// Disable the PWM timer.
TCCR2 &= ~_BV(CS20);
digitalWrite(speakerPin, LOW);
}
void setup()
{
pinMode(ledPin, OUTPUT);
//Serial.begin(115200);
Wire.begin();
mem_2.begin(0,1);
}
void loop()
{ while (true); }
Used external EPROM lib.https://github.com/mikeneiderhauser/I2C-EEPROM-Arduino, it’s tested & working fine.