Started following some tutorial on att85 usi. Downloaded example code from make avr book.
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Project-specific Details ##########
|
||||
########## Check these every time you start a new project ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
MCU = atmega168p
|
||||
F_CPU = 8000000UL
|
||||
BAUD = 9600UL
|
||||
## Also try BAUD = 19200 or 38400 if you're feeling lucky.
|
||||
|
||||
## A directory for common include files and the simple USART library.
|
||||
## If you move either the current folder or the Library folder, you'll
|
||||
## need to change this path to match.
|
||||
LIBDIR = ../../AVR-Programming-Library
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Programmer Defaults ##########
|
||||
########## Set up once, then forget about it ##########
|
||||
########## (Can override. See bottom of file.) ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
PROGRAMMER_TYPE = usbtiny
|
||||
# extra arguments to avrdude: baud rate, chip type, -F flag, etc.
|
||||
PROGRAMMER_ARGS =
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Program Locations ##########
|
||||
########## Won't need to change if they're in your PATH ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
CC = avr-gcc
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
AVRSIZE = avr-size
|
||||
AVRDUDE = avrdude
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Makefile Magic! ##########
|
||||
########## Summary: ##########
|
||||
########## We want a .hex file ##########
|
||||
########## Compile source files into .elf ##########
|
||||
########## Convert .elf file into .hex ##########
|
||||
########## You shouldn't need to edit below. ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
## The name of your project (without the .c)
|
||||
# TARGET = blinkLED
|
||||
## Or name it automatically after the enclosing directory
|
||||
TARGET = $(lastword $(subst /, ,$(CURDIR)))
|
||||
|
||||
# Object files: will find all .c/.h files in current directory
|
||||
# and in LIBDIR. If you have any other (sub-)directories with code,
|
||||
# you can add them in to SOURCES below in the wildcard statement.
|
||||
SOURCES=$(wildcard *.c $(LIBDIR)/*.c)
|
||||
OBJECTS=$(SOURCES:.c=.o)
|
||||
HEADERS=$(SOURCES:.c=.h)
|
||||
|
||||
## Compilation options, type man avr-gcc if you're curious.
|
||||
CPPFLAGS = -DF_CPU=$(F_CPU) -DBAUD=$(BAUD) -I. -I$(LIBDIR)
|
||||
CFLAGS = -Os -g -std=gnu99 -Wall
|
||||
## Use short (8-bit) data types
|
||||
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
|
||||
## Splits up object files per function
|
||||
CFLAGS += -ffunction-sections -fdata-sections
|
||||
LDFLAGS = -Wl,-Map,$(TARGET).map
|
||||
## Optional, but often ends up with smaller code
|
||||
LDFLAGS += -Wl,--gc-sections
|
||||
## Relax shrinks code even more, but makes disassembly messy
|
||||
## LDFLAGS += -Wl,--relax
|
||||
## LDFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf
|
||||
## LDFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf
|
||||
TARGET_ARCH = -mmcu=$(MCU)
|
||||
|
||||
## Explicit pattern rules:
|
||||
## To make .o files from .c files
|
||||
%.o: %.c $(HEADERS) Makefile
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $@ $<;
|
||||
|
||||
$(TARGET).elf: $(OBJECTS)
|
||||
$(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LDLIBS) -o $@
|
||||
|
||||
%.hex: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -O ihex $< $@
|
||||
|
||||
%.eeprom: %.elf
|
||||
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
|
||||
|
||||
%.lst: %.elf
|
||||
$(OBJDUMP) -S $< > $@
|
||||
|
||||
## These targets don't have files named after them
|
||||
.PHONY: all disassemble disasm eeprom size clean squeaky_clean flash fuses
|
||||
|
||||
all: $(TARGET).hex
|
||||
|
||||
debug:
|
||||
@echo
|
||||
@echo "Source files:" $(SOURCES)
|
||||
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
|
||||
@echo
|
||||
|
||||
# Optionally create listing file from .elf
|
||||
# This creates approximate assembly-language equivalent of your code.
|
||||
# Useful for debugging time-sensitive bits,
|
||||
# or making sure the compiler does what you want.
|
||||
disassemble: $(TARGET).lst
|
||||
|
||||
disasm: disassemble
|
||||
|
||||
# Optionally show how big the resulting program is
|
||||
size: $(TARGET).elf
|
||||
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
|
||||
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
|
||||
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
|
||||
$(TARGET).eeprom
|
||||
|
||||
squeaky_clean:
|
||||
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ *.eeprom
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Programmer-specific details ##########
|
||||
########## Flashing code to AVR using avrdude ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
flash: $(TARGET).hex
|
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
|
||||
|
||||
## An alias
|
||||
program: flash
|
||||
|
||||
flash_eeprom: $(TARGET).eeprom
|
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
|
||||
|
||||
avrdude_terminal:
|
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
|
||||
|
||||
## If you've got multiple programmers that you use,
|
||||
## you can define them here so that it's easy to switch.
|
||||
## To invoke, use something like `make flash_arduinoISP`
|
||||
flash_usbtiny: PROGRAMMER_TYPE = usbtiny
|
||||
flash_usbtiny: PROGRAMMER_ARGS = # USBTiny works with no further arguments
|
||||
flash_usbtiny: flash
|
||||
|
||||
flash_usbasp: PROGRAMMER_TYPE = usbasp
|
||||
flash_usbasp: PROGRAMMER_ARGS = # USBasp works with no further arguments
|
||||
flash_usbasp: flash
|
||||
|
||||
flash_arduinoISP: PROGRAMMER_TYPE = avrisp
|
||||
flash_arduinoISP: PROGRAMMER_ARGS = -b 19200 -P /dev/ttyACM0
|
||||
## (for windows) flash_arduinoISP: PROGRAMMER_ARGS = -b 19200 -P com5
|
||||
flash_arduinoISP: flash
|
||||
|
||||
flash_109: PROGRAMMER_TYPE = avr109
|
||||
flash_109: PROGRAMMER_ARGS = -b 9600 -P /dev/ttyUSB0
|
||||
flash_109: flash
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Fuse settings and suitable defaults ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
## Mega 48, 88, 168, 328 default values
|
||||
LFUSE = 0x62
|
||||
HFUSE = 0xdf
|
||||
EFUSE = 0x00
|
||||
|
||||
## Generic
|
||||
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
|
||||
|
||||
fuses:
|
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
|
||||
$(PROGRAMMER_ARGS) $(FUSE_STRING)
|
||||
show_fuses:
|
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
|
||||
|
||||
## Called with no extra definitions, sets to defaults
|
||||
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
|
||||
set_default_fuses: fuses
|
||||
|
||||
## Set the fuse byte for full-speed mode
|
||||
## Note: can also be set in firmware for modern chips
|
||||
set_fast_fuse: LFUSE = 0xE2
|
||||
set_fast_fuse: FUSE_STRING = -U lfuse:w:$(LFUSE):m
|
||||
set_fast_fuse: fuses
|
||||
|
||||
## Set the EESAVE fuse byte to preserve EEPROM across flashes
|
||||
set_eeprom_save_fuse: HFUSE = 0xD7
|
||||
set_eeprom_save_fuse: FUSE_STRING = -U hfuse:w:$(HFUSE):m
|
||||
set_eeprom_save_fuse: fuses
|
||||
|
||||
## Clear the EESAVE fuse byte
|
||||
clear_eeprom_save_fuse: FUSE_STRING = -U hfuse:w:$(HFUSE):m
|
||||
clear_eeprom_save_fuse: fuses
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,186 @@
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Project-specific Details ##########
|
||||
########## Check these every time you start a new project ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
MCU = atmega168
|
||||
F_CPU = 8000000
|
||||
BAUD = 9600
|
||||
## Also try BAUD = 19200 or 38400 if you're feeling lucky.
|
||||
|
||||
## This is where your main() routine lives (without .c extension)
|
||||
TARGET = speech_1_bit_diff
|
||||
## If you've split your program into multiple .c / .h files,
|
||||
## include the additional source here (without the .c or .h extension)
|
||||
LOCAL_SOURCE =
|
||||
|
||||
EXTRA_SOURCE_DIR = ../../../learningAVR/
|
||||
EXTRA_SOURCE_FILES = USART
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Programmer Defaults ##########
|
||||
########## Set up once, then forget about it ##########
|
||||
########## (Can override. See bottom of file.) ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
PROGRAMMER_TYPE = usbtiny
|
||||
# extra arguments to avrdude: baud rate, chip type, -F flag, etc.
|
||||
PROGRAMMER_ARGS =
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Makefile Magic! ##########
|
||||
########## Summary: ##########
|
||||
########## We want a .hex file ##########
|
||||
########## Compile source files into .elf ##########
|
||||
########## Convert .elf file into .hex ##########
|
||||
########## You shouldn't need to edit below. ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
## Defined programs / locations
|
||||
CC = avr-gcc
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
AVRSIZE = avr-size
|
||||
AVRDUDE = avrdude
|
||||
|
||||
## Compilation options, type man avr-gcc if you're curious.
|
||||
CFLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -DBAUD=$(BAUD) -Os -I. -I$(EXTRA_SOURCE_DIR)
|
||||
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
|
||||
CFLAGS += -Wall -Wstrict-prototypes
|
||||
CFLAGS += -g -ggdb
|
||||
CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax
|
||||
CFLAGS += -std=gnu99
|
||||
## CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf
|
||||
## CFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf
|
||||
|
||||
## Lump target and extra source files together
|
||||
TARGET = $(strip $(basename $(MAIN)))
|
||||
SRC = $(TARGET).c
|
||||
EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES))
|
||||
SRC += $(EXTRA_SOURCE)
|
||||
SRC += $(LOCAL_SOURCE)
|
||||
|
||||
## List of all header files
|
||||
HEADERS = $(SRC:.c=.h)
|
||||
|
||||
## For every .c file, compile an .o object file
|
||||
OBJ = $(SRC:.c=.o)
|
||||
|
||||
## Generic Makefile targets. (Only .hex file is necessary)
|
||||
all: $(TARGET).hex
|
||||
|
||||
%.hex: %.elf
|
||||
$(OBJCOPY) -R .eeprom -O ihex $< $@
|
||||
|
||||
%.elf: $(SRC)
|
||||
$(CC) $(CFLAGS) $(SRC) --output $@
|
||||
|
||||
%.eeprom: %.elf
|
||||
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
|
||||
|
||||
debug:
|
||||
@echo
|
||||
@echo "Source files:" $(SRC)
|
||||
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
|
||||
@echo
|
||||
|
||||
# Optionally create listing file from .elf
|
||||
# This creates approximate assembly-language equivalent of your code.
|
||||
# Useful for debugging time-sensitive bits,
|
||||
# or making sure the compiler does what you want.
|
||||
disassemble: $(TARGET).lst
|
||||
|
||||
disasm: disassemble
|
||||
|
||||
eeprom: $(TARGET).eeprom
|
||||
|
||||
%.lst: %.elf
|
||||
$(OBJDUMP) -S $< > $@
|
||||
|
||||
# Optionally show how big the resulting program is
|
||||
size: $(TARGET).elf
|
||||
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
|
||||
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
|
||||
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
|
||||
$(TARGET).eeprom
|
||||
|
||||
squeaky_clean:
|
||||
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Programmer-specific details ##########
|
||||
########## Flashing code to AVR using avrdude ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
flash: $(TARGET).hex
|
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
|
||||
|
||||
## An alias
|
||||
program: flash
|
||||
|
||||
flash_eeprom: $(TARGET).eeprom
|
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
|
||||
|
||||
avrdude_terminal:
|
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
|
||||
|
||||
## If you've got multiple programmers that you use,
|
||||
## you can define them here so that it's easy to switch.
|
||||
## To invoke, use something like `make flash_arduinoISP`
|
||||
flash_usbtiny: PROGRAMMER_TYPE = usbtiny
|
||||
flash_usbtiny: PROGRAMMER_ARGS = # USBTiny works with no further arguments
|
||||
flash_usbtiny: flash
|
||||
|
||||
flash_usbasp: PROGRAMMER_TYPE = usbasp
|
||||
flash_usbasp: PROGRAMMER_ARGS = # USBasp works with no further arguments
|
||||
flash_usbasp: flash
|
||||
|
||||
flash_arduinoISP: PROGRAMMER_TYPE = avrisp
|
||||
flash_arduinoISP: PROGRAMMER_ARGS = -b 19200 -P /dev/ttyACM0
|
||||
## (for windows) flash_arduinoISP: PROGRAMMER_ARGS = -b 19200 -P com5
|
||||
flash_arduinoISP: flash
|
||||
|
||||
flash_109: PROGRAMMER_TYPE = avr109
|
||||
flash_109: PROGRAMMER_ARGS = -b 9600 -P /dev/ttyUSB0
|
||||
flash_109: flash
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Fuse settings and suitable defaults ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
## Mega 48, 88, 168, 328 default values
|
||||
LFUSE = 0x62
|
||||
HFUSE = 0xdf
|
||||
EFUSE = 0x00
|
||||
|
||||
## Generic
|
||||
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
|
||||
|
||||
fuses:
|
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
|
||||
$(PROGRAMMER_ARGS) $(FUSE_STRING)
|
||||
show_fuses:
|
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
|
||||
|
||||
## Called with no extra definitions, sets to defaults
|
||||
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
|
||||
set_default_fuses: fuses
|
||||
|
||||
## Set the fuse byte for full-speed mode
|
||||
## Note: can also be set in firmware for modern chips
|
||||
set_fast_fuse: LFUSE = 0xE2
|
||||
set_fast_fuse: FUSE_STRING = -U lfuse:w:$(LFUSE):m
|
||||
set_fast_fuse: fuses
|
||||
|
||||
## Set the EESAVE fuse byte to preserve EEPROM across flashes
|
||||
set_eeprom_save_fuse: HFUSE = 0xD7
|
||||
set_eeprom_save_fuse: FUSE_STRING = -U hfuse:w:$(HFUSE):m
|
||||
set_eeprom_save_fuse: fuses
|
||||
|
||||
## Clear the EESAVE fuse byte
|
||||
clear_eeprom_save_fuse: FUSE_STRING = -U hfuse:w:$(HFUSE):m
|
||||
clear_eeprom_save_fuse: fuses
|
||||
@@ -0,0 +1,84 @@
|
||||
|
||||
% Speech encoder for Mega644/GCC decoder
|
||||
clear all
|
||||
|
||||
%===================================%the Encoder
|
||||
[d,r] = wavread('mega644small.wav'); %4
|
||||
%scale to about unity
|
||||
res = 1/(max(max(d),abs(min(d)) ));
|
||||
dd = diff(d * res);
|
||||
%init the code vector
|
||||
ddcode = zeros(1,length(dd));
|
||||
|
||||
brkpt1= 0 ;
|
||||
%quantize the first derivative
|
||||
ddcode(find(dd<brkpt1)) = 0;
|
||||
ddcode(find(dd>=brkpt1)) = 1;
|
||||
|
||||
%make the length of ddcode a multiple of 8
|
||||
ddcode = [ddcode,zeros(1,8-mod(length(ddcode),8))];
|
||||
length(ddcode)
|
||||
index=1;
|
||||
for i=1:8:length(ddcode)
|
||||
packed(index)= ...
|
||||
ddcode(i)*128 + ddcode(i+1)*64 + ...
|
||||
ddcode(i+2)*32 + ddcode(i+3)*16 + ...
|
||||
ddcode(i+4)*8 + ddcode(i+5)*4 + ...
|
||||
ddcode(i+6)*2 + ddcode(i+7) ;
|
||||
index=index+1;
|
||||
end
|
||||
%make a textfile with GCC source code in it.
|
||||
fname='mega644_1_bit.h';
|
||||
fid = fopen(fname,'w');
|
||||
fprintf(fid,'const prog_uint8_t mega644[%d]={\r',length(packed));
|
||||
for i=1:length(packed)-1
|
||||
fprintf(fid,' %5d,\r',packed(i));
|
||||
end
|
||||
fprintf(fid,' %5d};\r',packed(end));
|
||||
fclose(fid);
|
||||
|
||||
%===================================%the Decoder
|
||||
%value based on quantizer
|
||||
value = [-.16, .16];
|
||||
dl(1)=0;
|
||||
j=2;
|
||||
highpassfactor = 1/8;
|
||||
for i=1:length(packed)
|
||||
p1 = round(bitand(packed(i),128)/128);
|
||||
p2 = round(bitand(packed(i),64)/64);
|
||||
p3 = round(bitand(packed(i),32)/32);
|
||||
p4 = round(bitand(packed(i),16)/16);
|
||||
p5 = round(bitand(packed(i),8)/8);
|
||||
p6 = round(bitand(packed(i),4)/4);
|
||||
p7 = round(bitand(packed(i),2)/2);
|
||||
p8 = round(bitand(packed(i),1)/1);
|
||||
|
||||
%note that a bit of highpass has been added to reduce drift
|
||||
dl(j) = dl(j-1)+ value(p1+1) - highpassfactor * dl(j-1);
|
||||
j=j+1;
|
||||
dl(j) = dl(j-1)+ value(p2+1) - highpassfactor * dl(j-1);
|
||||
j=j+1;
|
||||
dl(j) = dl(j-1)+ value(p3+1) - highpassfactor * dl(j-1);
|
||||
j=j+1;
|
||||
dl(j) = dl(j-1)+ value(p4+1) - highpassfactor * dl(j-1);
|
||||
j=j+1;
|
||||
dl(j) = dl(j-1)+ value(p5+1) - highpassfactor * dl(j-1);
|
||||
j=j+1;
|
||||
dl(j) = dl(j-1)+ value(p6+1) - highpassfactor * dl(j-1);
|
||||
j=j+1;
|
||||
dl(j) = dl(j-1)+ value(p7+1) - highpassfactor * dl(j-1);
|
||||
j=j+1;
|
||||
dl(j) = dl(j-1)+ value(p8+1) - highpassfactor * dl(j-1);
|
||||
j=j+1;
|
||||
end
|
||||
% dl(1)=0;
|
||||
% for i=1:length(ddcode)
|
||||
% dl(i) = dl(i-1)+ value(ddcode(i)+1) - .125*dl(i-1); % .* w';
|
||||
% end
|
||||
|
||||
%return
|
||||
%====================================%playback and graphing
|
||||
% sound(dl,r);
|
||||
dl = dl/(max(abs(dl))+.001);
|
||||
wavwrite(dl', 'mega644_1_bit.wav');
|
||||
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -0,0 +1,113 @@
|
||||
//Voice decompressor example
|
||||
#include <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <util/delay.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "USART.h"
|
||||
|
||||
#define TableSize 3280 //refers to the following incl file
|
||||
//Contains the packed 1-bit codes for syntehsis
|
||||
#include "mega644_1_bit.h"
|
||||
|
||||
//reconstruction differentials
|
||||
//volatile signed char PCMvalue[4] = {-78, -16, 16, 78};
|
||||
volatile signed char PCMvalue[2] = {-10, 10};
|
||||
|
||||
volatile unsigned int outI, tableI; //indexes
|
||||
volatile unsigned char cycle ; //decode phase counter
|
||||
volatile signed char out, lastout, newvalue; //output values
|
||||
volatile unsigned char p1,p2,p3,p4,p5,p6,p7,p8; //hold 8 differentials
|
||||
volatile unsigned char packed ; //byte containing 4 2-bit values
|
||||
volatile uint8_t speaking; /* flag for whether currently speaking or not */
|
||||
|
||||
//generate waveform at 7812 scamples/sec
|
||||
ISR (TIMER2_COMPA_vect){
|
||||
//compute next sample
|
||||
cycle = outI & 7; // outI modulo 8
|
||||
if (cycle==0) //do we need to unpack more data?
|
||||
{
|
||||
if (tableI<TableSize) //} of stored wave?
|
||||
{
|
||||
//unpack a table entry into 2-bit indexs
|
||||
// pgm_read_byte (address_short)
|
||||
packed = pgm_read_byte(&mega644[tableI]) ;
|
||||
//packed = DPCMAllDigits[tableI];
|
||||
p1 = (packed & 128) == 128 ;
|
||||
p2 = (packed & 64) == 64 ;
|
||||
p3 = (packed & 32) == 32 ;
|
||||
p4 = (packed & 16) == 16 ;
|
||||
p5 = (packed & 8) == 8 ;
|
||||
p6 = (packed & 4) == 4 ;
|
||||
p7 = (packed & 2) == 2 ;
|
||||
p8 = (packed & 1) == 1 ;
|
||||
tableI++ ;
|
||||
} //end unpack table entry
|
||||
//compute the output and send to PWM
|
||||
newvalue = PCMvalue[p1] ;
|
||||
}
|
||||
else if (cycle==1) //don't need to unpack yet--just ouput
|
||||
newvalue = PCMvalue[p2] ;
|
||||
else if (cycle==2)
|
||||
newvalue = PCMvalue[p3] ;
|
||||
else if (cycle==3)
|
||||
newvalue = PCMvalue[p4] ;
|
||||
else if (cycle==4)
|
||||
newvalue = PCMvalue[p5] ;
|
||||
else if (cycle==5)
|
||||
newvalue = PCMvalue[p6] ;
|
||||
else if (cycle==6)
|
||||
newvalue = PCMvalue[p7] ;
|
||||
else if (cycle==7)
|
||||
newvalue = PCMvalue[p8] ;
|
||||
|
||||
out = lastout + newvalue - (lastout>>3);
|
||||
//update outputs
|
||||
OCR0A = out + 128;
|
||||
lastout = out;
|
||||
outI++;
|
||||
//at end, turn off TCCRO
|
||||
if (tableI==TableSize) TCCR2B = 0;
|
||||
} //ISR
|
||||
|
||||
int main(void){
|
||||
DDRD |= (1<<PD6);
|
||||
DDRB |= (1<<PB0);
|
||||
// turn on pwm with period= 256 cycles
|
||||
// (62,500 samples/sec) in fast PWM mode.
|
||||
// BUT OCR0A update is done using timer2 at 7800/sec
|
||||
// timer 0 runs at full rate set in MAIN loop; TCCR0B = 1 ;
|
||||
// turn on fast PWM and OC0A output
|
||||
// 16 microsec per PWM cycle sample time
|
||||
TCCR0A = (1<<COM0A0) | (1<<COM0A1) | (1<<WGM00) | (1<<WGM01) ;
|
||||
OCR0A = 128 ; // initialize PWM to half full scale
|
||||
TCCR0B = (1<<CS00); /* full speed */
|
||||
// turn on timer2 set to overflow at 7812 Hz
|
||||
// (prescaler set to divide by 8)
|
||||
TCCR2A = (1<<WGM21); /* CTC, count to OCR2A */
|
||||
OCR2A = 128; /* control sample playback frequency */
|
||||
TCCR2B = (1<<CS21); /* clock source / 8 = 1MHz */
|
||||
TIMSK2 = (1<<OCIE2A); // turn on compare interrupt
|
||||
|
||||
sei();
|
||||
|
||||
while(1) {
|
||||
|
||||
//init the output indexes
|
||||
outI = 0;
|
||||
tableI = 0;
|
||||
//init the ouptut value
|
||||
lastout = 0;
|
||||
// turn on PWM
|
||||
TCCR2B = (1<<CS21);
|
||||
//wait until the speech is done then
|
||||
//time delay the next utterance.
|
||||
while (TCCR2B>0){};
|
||||
OCR0A = 128 ;
|
||||
_delay_ms(500);
|
||||
PORTB ^= (1<<PB0);
|
||||
|
||||
} // end while
|
||||
} //end main
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
*.wav
|
||||
DPCM*.h
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
clear all
|
||||
%use an optimizer to find the best parameters
|
||||
%for an utterance
|
||||
%The encoder/decoder go into an iterative scheme to find the
|
||||
%best 3 break points and 4 reconstruction values
|
||||
%===================================%the Encoder
|
||||
[d,r] = wavread('C:\Documents and Settings\bruce land\My Documents\Matlab\Speech\SineSynth\test4small.WAV'); %4
|
||||
%scale to about unity
|
||||
res = 1/(max(max(d),abs(min(d)) ));
|
||||
dd = diff(d * res);
|
||||
|
||||
%parameters
|
||||
value = [-.16, -.026 .026 .16];
|
||||
brkpt1=-0.05; brkpt2=0 ; brkpt3=0.05;
|
||||
%initial parameter guess
|
||||
p0 = [brkpt1, brkpt2, brkpt3, ...
|
||||
value(1),value(2),value(3),value(4) ];
|
||||
|
||||
p = fminsearch(@FindOpt,p0,[],d,dd);
|
||||
%ChiMin = fmins ('chisq', density0, options, [], smat, observed,
|
||||
%fixdensity);
|
||||
|
||||
%=================================%print parameters
|
||||
p
|
||||
@@ -0,0 +1,16 @@
|
||||
function fit = FindOpt(p,d,dd)
|
||||
p
|
||||
%init the code vector
|
||||
ddcode = zeros(1,length(dd));
|
||||
%quantize the first derivative
|
||||
ddcode(find(dd<p(1)))=0;
|
||||
ddcode(find(dd>=p(1) & dd<p(2)))=1;
|
||||
ddcode(find(dd>=p(2) & dd<p(3)))=2;
|
||||
ddcode(find(dd>=p(3)))=3;
|
||||
|
||||
dl = zeros(1,length(ddcode));
|
||||
for i=2:length(ddcode)
|
||||
dl(i) = dl(i-1)+ p(ddcode(i)+4) - .125*dl(i-1); % .* w';
|
||||
end
|
||||
|
||||
fit = mean((d(2:end)-dl').^2);
|
||||
@@ -0,0 +1,186 @@
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Project-specific Details ##########
|
||||
########## Check these every time you start a new project ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
MCU = atmega168
|
||||
F_CPU = 8000000
|
||||
BAUD = 9600
|
||||
## Also try BAUD = 19200 or 38400 if you're feeling lucky.
|
||||
|
||||
## This is where your main() routine lives (without .c extension)
|
||||
TARGET = speech_644_GCC
|
||||
## If you've split your program into multiple .c / .h files,
|
||||
## include the additional source here (without the .c or .h extension)
|
||||
LOCAL_SOURCE =
|
||||
|
||||
EXTRA_SOURCE_DIR = ../../../learningAVR/
|
||||
EXTRA_SOURCE_FILES = USART
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Programmer Defaults ##########
|
||||
########## Set up once, then forget about it ##########
|
||||
########## (Can override. See bottom of file.) ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
PROGRAMMER_TYPE = usbtiny
|
||||
# extra arguments to avrdude: baud rate, chip type, -F flag, etc.
|
||||
PROGRAMMER_ARGS =
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Makefile Magic! ##########
|
||||
########## Summary: ##########
|
||||
########## We want a .hex file ##########
|
||||
########## Compile source files into .elf ##########
|
||||
########## Convert .elf file into .hex ##########
|
||||
########## You shouldn't need to edit below. ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
## Defined programs / locations
|
||||
CC = avr-gcc
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
AVRSIZE = avr-size
|
||||
AVRDUDE = avrdude
|
||||
|
||||
## Compilation options, type man avr-gcc if you're curious.
|
||||
CFLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -DBAUD=$(BAUD) -Os -I. -I$(EXTRA_SOURCE_DIR)
|
||||
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
|
||||
CFLAGS += -Wall -Wstrict-prototypes
|
||||
CFLAGS += -g -ggdb
|
||||
CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax
|
||||
CFLAGS += -std=gnu99
|
||||
## CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf
|
||||
## CFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf
|
||||
|
||||
## Lump target and extra source files together
|
||||
TARGET = $(strip $(basename $(MAIN)))
|
||||
SRC = $(TARGET).c
|
||||
EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES))
|
||||
SRC += $(EXTRA_SOURCE)
|
||||
SRC += $(LOCAL_SOURCE)
|
||||
|
||||
## List of all header files
|
||||
HEADERS = $(SRC:.c=.h)
|
||||
|
||||
## For every .c file, compile an .o object file
|
||||
OBJ = $(SRC:.c=.o)
|
||||
|
||||
## Generic Makefile targets. (Only .hex file is necessary)
|
||||
all: $(TARGET).hex
|
||||
|
||||
%.hex: %.elf
|
||||
$(OBJCOPY) -R .eeprom -O ihex $< $@
|
||||
|
||||
%.elf: $(SRC)
|
||||
$(CC) $(CFLAGS) $(SRC) --output $@
|
||||
|
||||
%.eeprom: %.elf
|
||||
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
|
||||
|
||||
debug:
|
||||
@echo
|
||||
@echo "Source files:" $(SRC)
|
||||
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
|
||||
@echo
|
||||
|
||||
# Optionally create listing file from .elf
|
||||
# This creates approximate assembly-language equivalent of your code.
|
||||
# Useful for debugging time-sensitive bits,
|
||||
# or making sure the compiler does what you want.
|
||||
disassemble: $(TARGET).lst
|
||||
|
||||
disasm: disassemble
|
||||
|
||||
eeprom: $(TARGET).eeprom
|
||||
|
||||
%.lst: %.elf
|
||||
$(OBJDUMP) -S $< > $@
|
||||
|
||||
# Optionally show how big the resulting program is
|
||||
size: $(TARGET).elf
|
||||
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
|
||||
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
|
||||
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
|
||||
$(TARGET).eeprom
|
||||
|
||||
squeaky_clean:
|
||||
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Programmer-specific details ##########
|
||||
########## Flashing code to AVR using avrdude ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
flash: $(TARGET).hex
|
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
|
||||
|
||||
## An alias
|
||||
program: flash
|
||||
|
||||
flash_eeprom: $(TARGET).eeprom
|
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
|
||||
|
||||
avrdude_terminal:
|
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
|
||||
|
||||
## If you've got multiple programmers that you use,
|
||||
## you can define them here so that it's easy to switch.
|
||||
## To invoke, use something like `make flash_arduinoISP`
|
||||
flash_usbtiny: PROGRAMMER_TYPE = usbtiny
|
||||
flash_usbtiny: PROGRAMMER_ARGS = # USBTiny works with no further arguments
|
||||
flash_usbtiny: flash
|
||||
|
||||
flash_usbasp: PROGRAMMER_TYPE = usbasp
|
||||
flash_usbasp: PROGRAMMER_ARGS = # USBasp works with no further arguments
|
||||
flash_usbasp: flash
|
||||
|
||||
flash_arduinoISP: PROGRAMMER_TYPE = avrisp
|
||||
flash_arduinoISP: PROGRAMMER_ARGS = -b 19200 -P /dev/ttyACM0
|
||||
## (for windows) flash_arduinoISP: PROGRAMMER_ARGS = -b 19200 -P com5
|
||||
flash_arduinoISP: flash
|
||||
|
||||
flash_109: PROGRAMMER_TYPE = avr109
|
||||
flash_109: PROGRAMMER_ARGS = -b 9600 -P /dev/ttyUSB0
|
||||
flash_109: flash
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Fuse settings and suitable defaults ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
## Mega 48, 88, 168, 328 default values
|
||||
LFUSE = 0x62
|
||||
HFUSE = 0xdf
|
||||
EFUSE = 0x00
|
||||
|
||||
## Generic
|
||||
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
|
||||
|
||||
fuses:
|
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
|
||||
$(PROGRAMMER_ARGS) $(FUSE_STRING)
|
||||
show_fuses:
|
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
|
||||
|
||||
## Called with no extra definitions, sets to defaults
|
||||
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
|
||||
set_default_fuses: fuses
|
||||
|
||||
## Set the fuse byte for full-speed mode
|
||||
## Note: can also be set in firmware for modern chips
|
||||
set_fast_fuse: LFUSE = 0xE2
|
||||
set_fast_fuse: FUSE_STRING = -U lfuse:w:$(LFUSE):m
|
||||
set_fast_fuse: fuses
|
||||
|
||||
## Set the EESAVE fuse byte to preserve EEPROM across flashes
|
||||
set_eeprom_save_fuse: HFUSE = 0xD7
|
||||
set_eeprom_save_fuse: FUSE_STRING = -U hfuse:w:$(HFUSE):m
|
||||
set_eeprom_save_fuse: fuses
|
||||
|
||||
## Clear the EESAVE fuse byte
|
||||
clear_eeprom_save_fuse: FUSE_STRING = -U hfuse:w:$(HFUSE):m
|
||||
clear_eeprom_save_fuse: fuses
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
% Speech encoder for Mega644/GCC decoder
|
||||
clear all
|
||||
|
||||
%===================================%the Encoder
|
||||
[d,r] = wavread('Z:\EEdocs\4760\ece4760labstuff\GCCmega644\Speech\AllDigits8khz.WAV'); %4
|
||||
%scale to about unity
|
||||
res = 1/(max(max(d),abs(min(d)) ));
|
||||
dd = diff(d * res);
|
||||
%init the code vector
|
||||
ddcode = zeros(1,length(dd));
|
||||
|
||||
% brkpt1=-0.5; brkpt2=0 ; brkpt3=0.5;
|
||||
% value = [-.75, -.25 .25 .75];
|
||||
%breakpoints are changeable
|
||||
brkpt1=-0.05; brkpt2=0 ; brkpt3=0.05;
|
||||
%quantize the first derivative
|
||||
ddcode(find(dd<brkpt1))=0;
|
||||
ddcode(find(dd>=brkpt1 & dd<brkpt2))=1;
|
||||
ddcode(find(dd>=brkpt2 & dd<brkpt3))=2;
|
||||
ddcode(find(dd>=brkpt3))=3;
|
||||
|
||||
%make the length of ddcode a multiple of 4
|
||||
ddcode = [ddcode,zeros(1,4-mod(length(ddcode),4))];
|
||||
length(ddcode)
|
||||
index=1;
|
||||
for i=1:4:length(ddcode)
|
||||
packed(index)=ddcode(i)*64 + ddcode(i+1)*16 + ...
|
||||
ddcode(i+2)*4 + ddcode(i+3) ;
|
||||
index=index+1;
|
||||
end
|
||||
%make a textfile with GCC source code in it.
|
||||
fname='DPCMAllDigits.h';
|
||||
fid = fopen(fname,'w');
|
||||
fprintf(fid,'const prog_uint8_t DPCMAllDigits[%d]={\r',length(packed));
|
||||
for i=1:length(packed)-1
|
||||
fprintf(fid,' %5d,\r',packed(i));
|
||||
end
|
||||
fprintf(fid,' %5d};\r',packed(end));
|
||||
fclose(fid);
|
||||
|
||||
%===================================%the Decoder
|
||||
%value based on quantizer
|
||||
value = [-.16, -.026 .026 .16];
|
||||
dl(1)=0;
|
||||
j=2;
|
||||
for i=1:length(packed)
|
||||
p1 = fix(bitand(packed(i),192)/64);
|
||||
p2 = fix(bitand(packed(i),48)/16);
|
||||
p3 = fix(bitand(packed(i), 12)/4);
|
||||
p4 = fix(bitand(packed(i),3));
|
||||
%note that a bit of highpass has been added to reduce drift
|
||||
dl(j) = dl(j-1)+ value(p1+1) - .125*dl(j-1);
|
||||
j=j+1;
|
||||
dl(j) = dl(j-1)+ value(p2+1) - .125*dl(j-1);
|
||||
j=j+1;
|
||||
dl(j) = dl(j-1)+ value(p3+1) - .125*dl(j-1);
|
||||
j=j+1;
|
||||
dl(j) = dl(j-1)+ value(p4+1) - .125*dl(j-1);
|
||||
j=j+1;
|
||||
end
|
||||
% dl(1)=0;
|
||||
% for i=1:length(ddcode)
|
||||
% dl(i) = dl(i-1)+ value(ddcode(i)+1) - .125*dl(i-1); % .* w';
|
||||
% end
|
||||
|
||||
%====================================%playback and graphing
|
||||
soundsc(dl,r);
|
||||
% Compare the spectrograms
|
||||
figure(1);clf
|
||||
|
||||
subplot(211)
|
||||
spectrogram(d,256,r);
|
||||
colormap gray
|
||||
title('Original');
|
||||
|
||||
subplot(212)
|
||||
spectrogram(dl,256,r);
|
||||
colormap gray
|
||||
title('synth');
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
clear all
|
||||
%reads a file at 16kHz and outputs it a 8kHz, 8 bits
|
||||
[d,r] = wavread('test6.WAV');
|
||||
y = resample(d,1,2);
|
||||
wavwrite(y,8000,8,'test6small.wav')
|
||||
@@ -0,0 +1,38 @@
|
||||
## Demo python program to create sine wave
|
||||
|
||||
from struct import pack, unpack
|
||||
from math import sin, pi
|
||||
import wave
|
||||
import os
|
||||
import random
|
||||
|
||||
|
||||
RATE = 44100
|
||||
|
||||
## GENERATE MONO FILE ##
|
||||
wv = wave.open('test_mono.wav', 'w')
|
||||
wv.setparams((1, 2, RATE, 0, 'NONE', 'not compressed'))
|
||||
maxVol=2**15-1.0 #maximum amplitude
|
||||
wvData=""
|
||||
for i in range(0, RATE*3):
|
||||
wvData+=pack('h', maxVol*sin(2*pi*i*440.0/RATE))
|
||||
|
||||
wv.writeframes(wvData)
|
||||
wv.close()
|
||||
os.system("mplayer test_mono.wav")
|
||||
|
||||
## GENERATE STEREO FILE ##
|
||||
wv = wave.open('test_stereo.wav', 'w')
|
||||
wv.setparams((2, 2, RATE, 0, 'NONE', 'not compressed'))
|
||||
maxVol=2**15-1.0 #maximum amplitude
|
||||
waveData = ""
|
||||
for i in range(0, RATE*3):
|
||||
t = 2*pi*i/RATE # time-step in radians*sec
|
||||
waveData+=pack('h', maxVol*sin(t*440.0)) #440Hz left
|
||||
waveData+=pack('h', maxVol*sin(t*220.0)) #220Hz right
|
||||
|
||||
|
||||
wv.writeframes(waveData)
|
||||
wv.close()
|
||||
os.system("mplayer test_stereo.wav")
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
// Talking Voltmeter Example
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <util/delay.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "pinDefines.h"
|
||||
|
||||
#include "DPCM_rich_hello_world_8000.h"
|
||||
#define TABLE_NAME DPCM_rich_hello_world_8000
|
||||
|
||||
volatile uint16_t sampleNumber; // sample index
|
||||
volatile int8_t out, lastout; // output values
|
||||
volatile uint8_t p1, p2, p3, p4; // hold 4 differentials
|
||||
const int8_t PCMvalue[4] = {-20, -4, 4, 20};
|
||||
|
||||
ISR (TIMER2_COMPA_vect){
|
||||
/* Timer 2 controls sampling speed --
|
||||
ISR reads new data, loads PWM output, OCR0A */
|
||||
/* Since we can decode 4 2-bit values at once, need to know where
|
||||
we are in the 4-step mini-cycle. */
|
||||
uint8_t cycle = sampleNumber & 0b00000011; /* our 4 steps */
|
||||
uint16_t tableEntry = sampleNumber >> 2; /* 4 steps per table byte */
|
||||
uint8_t packedData; /* the new byte */
|
||||
switch(cycle){
|
||||
case 0: // Start of the cycle, unpack next byte of samples
|
||||
if (tableEntry < sizeof(TABLE_NAME)){
|
||||
packedData = pgm_read_byte(&TABLE_NAME[tableEntry]) ;
|
||||
p1 = (packedData>>6) & 3 ;
|
||||
p2 = (packedData>>4) & 3 ;
|
||||
p3 = (packedData>>2) & 3 ;
|
||||
p4 = (packedData & 3);
|
||||
}
|
||||
/* Add in the next PCM differential value */
|
||||
out = lastout + PCMvalue[p1] - (lastout>>3) ;
|
||||
break;
|
||||
case 1:
|
||||
out = lastout + PCMvalue[p2] - (lastout>>3) ;
|
||||
break;
|
||||
case 2:
|
||||
out = lastout + PCMvalue[p3] - (lastout>>3) ;
|
||||
break;
|
||||
case 3:
|
||||
out = lastout + PCMvalue[p4] - (lastout>>3) ;
|
||||
break;
|
||||
}
|
||||
/* Update PWM audio output */
|
||||
OCR0A = out + 128; /* re-center for 0-255 PWM */
|
||||
lastout = out; /* update last value */
|
||||
sampleNumber++; /* on to next sample */
|
||||
|
||||
/* When done, turn off PWM, Timer0 */
|
||||
if (sampleNumber == 4*sizeof(TABLE_NAME)-1) {
|
||||
TCCR2B = 0; /* disable sample-playback clock */
|
||||
OCR0A = 128; /* idle at mid-voltage */
|
||||
lastout = 0; /* start at 0 next time */
|
||||
}
|
||||
} // end ISR
|
||||
|
||||
void initTimer0(void){
|
||||
// Timer 0 Configured for free-running PWM Audio Output
|
||||
TCCR0A |= (1<<WGM00) | (1<<WGM01); /* fast PWM mode */
|
||||
TCCR0A |= (1<<COM0A0) | (1<<COM0A1); /* output on PD6/OC0A */
|
||||
TCCR0B = (1<<CS00); /* fastest clock */
|
||||
OCR0A = 128 ; /* initialize mid-value */
|
||||
SPEAKER_DDR |= (1<<SPEAKER); /* output PD6 / OC0A */
|
||||
}
|
||||
|
||||
void initTimer2(void){
|
||||
// Timer 2 loads OCR0A, defines sampling frequency
|
||||
// Aiming for around 8kHz
|
||||
TCCR2A = (1<<WGM21); /* CTC, count to OCR2A */
|
||||
OCR2A = 128; /* controls sample playback frequency */
|
||||
TCCR2B = (1<<CS21); /* clock source / 8 = 1MHz */
|
||||
TIMSK2 = (1<<OCIE2A); /* turn on compare interrupt */
|
||||
sei();
|
||||
}
|
||||
|
||||
void initADC(void){
|
||||
// ADC for Voltmeter function
|
||||
ADMUX |= (0b00001111 & PC5); /* set mux to ADC5 */
|
||||
DIDR0 |= _BV(ADC5D); /* turn off digital circuitry on PC5 */
|
||||
ADMUX |= (1 << REFS0); /* reference voltage is AVCC, 5V */
|
||||
ADCSRA |= (1 << ADPS1) | (1 << ADPS2); /* ADC clock prescaler /64 */
|
||||
ADCSRA |= (1 << ADEN); /* enable ADC */
|
||||
}
|
||||
|
||||
int main(void){
|
||||
uint8_t adcValue;
|
||||
|
||||
initTimer0();
|
||||
initTimer2();
|
||||
initADC();
|
||||
|
||||
while(1) {
|
||||
sampleNumber = 0; /* back to start of sample table */
|
||||
TCCR2B = (1<<CS21); /* start loading samples */
|
||||
|
||||
/* Wait until done speaking, then delay some more. */
|
||||
loop_until_bit_is_clear(TCCR2B, CS21);
|
||||
_delay_ms(1000);
|
||||
|
||||
} /* end while */
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
## Given a .wav audio file, downsamples it to 8000 Hz and writes it out
|
||||
## as a ADPCM file suitable for use with AVRs.
|
||||
|
||||
from struct import unpack
|
||||
import wave
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def unpackMono(waveFile):
|
||||
w = wave.Wave_read(waveFile)
|
||||
data = []
|
||||
for i in range(w.getnframes()):
|
||||
data.append(unpack("h", w.readframes(1))[0])
|
||||
return(data)
|
||||
|
||||
def scaleData(data):
|
||||
scale = max(max(data), abs(min(data))) * 1.0
|
||||
return([x/scale for x in data])
|
||||
|
||||
def getDifferences(data):
|
||||
differences = []
|
||||
for i in range(len(data)-1):
|
||||
differences.append(data[i+1]-data[i])
|
||||
return(differences)
|
||||
|
||||
def quantize(data, thresholds):
|
||||
quantized = []
|
||||
n = len(thresholds)
|
||||
thresholdRange = range(n)
|
||||
for d in data:
|
||||
categorized = False
|
||||
for i in thresholdRange:
|
||||
if d <= thresholds[i]:
|
||||
quantized.append(i)
|
||||
categorized = True
|
||||
break
|
||||
if not categorized:
|
||||
quantized.append(n)
|
||||
return(quantized)
|
||||
|
||||
def pack4(data): # for 2-bit data
|
||||
packedData = []
|
||||
for i in range(len(data) / 4):
|
||||
thisByte = 0
|
||||
thisByte += 2**6 * data[4*i]
|
||||
thisByte += 2**4 * data[4*i+1]
|
||||
thisByte += 2**2 * data[4*i+2]
|
||||
thisByte += data[4*i+3]
|
||||
packedData.append(thisByte)
|
||||
return(packedData)
|
||||
|
||||
def pack2(data): # for 1-bit data
|
||||
packedData = []
|
||||
for i in range(len(data) / 8):
|
||||
thisByte = 0
|
||||
thisByte += 2**7 * data[8*i]
|
||||
thisByte += 2**6 * data[8*i+1]
|
||||
thisByte += 2**5 * data[8*i+2]
|
||||
thisByte += 2**4 * data[8*i+3]
|
||||
thisByte += 2**3 * data[8*i+4]
|
||||
thisByte += 2**2 * data[8*i+5]
|
||||
thisByte += 2**1 * data[8*i+6]
|
||||
thisByte += data[8*i+7]
|
||||
packedData.append(thisByte)
|
||||
return(packedData)
|
||||
|
||||
|
||||
def packOneBitDPCM(filename):
|
||||
data = unpackMono(filename)
|
||||
data = scaleData(data)
|
||||
differences = getDifferences(data)
|
||||
quantized = quantize(differences, [0])
|
||||
packed = pack2(quantized)
|
||||
return(packed)
|
||||
|
||||
def packTwoBitDPCM(filename):
|
||||
data = unpackMono(filename)
|
||||
data = scaleData(data)
|
||||
differences = getDifferences(data)
|
||||
quantized = quantize(differences, TWO_BIT_THRESHOLDS)
|
||||
packed = pack4(quantized)
|
||||
return(packed)
|
||||
|
||||
def createHeader(filename, packedData):
|
||||
baseFilename = filename[:-4]
|
||||
outfile = open("DPCM_" + baseFilename + ".h", "w")
|
||||
outfile.write('const uint8_t DPCM_{}[] PROGMEM = {{\n'.format(baseFilename))
|
||||
for byte in packedData:
|
||||
outfile.write(' {:d},\n'.format(byte))
|
||||
outfile.write('};\n')
|
||||
outfile.close()
|
||||
|
||||
def testWaveFile(filename):
|
||||
w = wave.Wave_read(filename)
|
||||
bitrate = w.getframerate()
|
||||
channels = w.getnchannels()
|
||||
bits = w.getsampwidth()*8
|
||||
if not bitrate==8000 or not channels==1 or not bits==16:
|
||||
newFilename = filename[:-4] + "_8000.wav"
|
||||
returnValue = os.system(SOXCOMMAND.format(filename, newFilename))
|
||||
if returnValue:
|
||||
raise(SOX_Exception("Something went wrong calling sox: SOXCOMMAND.format(filename, newFilename"))
|
||||
filename = newFilename
|
||||
return(filename)
|
||||
|
||||
|
||||
class SOX_Exception(Exception):
|
||||
pass
|
||||
class UsageException(Exception):
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
TWO_BIT_THRESHOLDS = [-0.05, 0, 0.05]
|
||||
try:
|
||||
filename = sys.argv[1]
|
||||
except IndexError:
|
||||
raise(UsageException("usage: python wave2DPCM.py wavefilename.wav"))
|
||||
|
||||
SOXCOMMAND = "sox {} -r 8000 -c 1 -b 16 {}" # for converting wave file
|
||||
## install sox, or use itunes or audacity to convert
|
||||
## wavefile to 8kHz, 16-bit, one-channel
|
||||
|
||||
filename = testWaveFile(filename)
|
||||
packedData = packTwoBitDPCM(filename)
|
||||
createHeader(filename, packedData)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
*8000.wav
|
||||
DPCM*.h
|
||||
muah.wav
|
||||
outtakes.wav
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,136 @@
|
||||
## Given a .wav audio file, downsamples it to 8000 Hz and writes it out
|
||||
## as a ADPCM file suitable for use with AVRs.
|
||||
|
||||
from struct import unpack
|
||||
import wave
|
||||
import os
|
||||
import sys
|
||||
|
||||
def unpackMono(waveFile):
|
||||
w = wave.Wave_read(waveFile)
|
||||
data = []
|
||||
for i in range(w.getnframes()):
|
||||
data.append(unpack("h", w.readframes(1))[0])
|
||||
return(data)
|
||||
|
||||
def scaleData(data):
|
||||
scale = max(max(data), abs(min(data))) * 1.0
|
||||
return([x/scale for x in data])
|
||||
|
||||
def getDifferences(data):
|
||||
differences = []
|
||||
for i in range(len(data)-1):
|
||||
differences.append(data[i+1]-data[i])
|
||||
return(differences)
|
||||
|
||||
def quantize(data, thresholds):
|
||||
quantized = []
|
||||
n = len(thresholds)
|
||||
thresholdRange = range(n)
|
||||
for d in data:
|
||||
categorized = False
|
||||
for i in thresholdRange:
|
||||
if d <= thresholds[i]:
|
||||
quantized.append(i)
|
||||
categorized = True
|
||||
break
|
||||
if not categorized:
|
||||
quantized.append(n)
|
||||
return(quantized)
|
||||
|
||||
def pack4(data): # for 2-bit data
|
||||
packedData = []
|
||||
for i in range(len(data) / 4):
|
||||
thisByte = 0
|
||||
thisByte += 2**6 * data[4*i]
|
||||
thisByte += 2**4 * data[4*i+1]
|
||||
thisByte += 2**2 * data[4*i+2]
|
||||
thisByte += data[4*i+3]
|
||||
packedData.append(thisByte)
|
||||
return(packedData)
|
||||
|
||||
def pack2(data): # for 1-bit data
|
||||
packedData = []
|
||||
for i in range(len(data) / 8):
|
||||
thisByte = 0
|
||||
thisByte += 2**7 * data[8*i]
|
||||
thisByte += 2**6 * data[8*i+1]
|
||||
thisByte += 2**5 * data[8*i+2]
|
||||
thisByte += 2**4 * data[8*i+3]
|
||||
thisByte += 2**3 * data[8*i+4]
|
||||
thisByte += 2**2 * data[8*i+5]
|
||||
thisByte += 2**1 * data[8*i+6]
|
||||
thisByte += data[8*i+7]
|
||||
packedData.append(thisByte)
|
||||
return(packedData)
|
||||
|
||||
|
||||
def packOneBitDPCM(filename):
|
||||
data = unpackMono(filename)
|
||||
data = scaleData(data)
|
||||
differences = getDifferences(data)
|
||||
quantized = quantize(differences, [0])
|
||||
packed = pack2(quantized)
|
||||
return(packed)
|
||||
|
||||
def packTwoBitDPCM(filename):
|
||||
data = unpackMono(filename)
|
||||
data = scaleData(data)
|
||||
differences = getDifferences(data)
|
||||
quantized = quantize(differences, TWO_BIT_THRESHOLDS)
|
||||
packed = pack4(quantized)
|
||||
return(packed)
|
||||
|
||||
def createHeader(filename, packedData):
|
||||
baseFilename = filename[:-4]
|
||||
outfile = open("DPCM_" + baseFilename + ".h", "w")
|
||||
outfile.write('uint8_t DPCM_{}[] PROGMEM = {{\n'.format(baseFilename))
|
||||
for byte in packedData:
|
||||
outfile.write(' {:d},\n'.format(byte))
|
||||
outfile.write('};\n')
|
||||
outfile.close()
|
||||
|
||||
def testWaveFile(filename):
|
||||
w = wave.Wave_read(filename)
|
||||
bitrate = w.getframerate()
|
||||
channels = w.getnchannels()
|
||||
bits = w.getsampwidth()*8
|
||||
if not bitrate==8000 or not channels==1 or not bits==16:
|
||||
newFilename = filename[:-4] + "_8000.wav"
|
||||
returnValue = os.system(SOXCOMMAND.format(filename, newFilename))
|
||||
if returnValue:
|
||||
raise(SOX_Exception("Something went wrong calling sox: SOXCOMMAND.format(filename, newFilename"))
|
||||
filename = newFilename
|
||||
return(filename)
|
||||
|
||||
|
||||
class SOX_Exception(Exception):
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
## Default is to convert all wav files in the current directory.
|
||||
|
||||
TWO_BIT_THRESHOLDS = [-0.05, 0, 0.05]
|
||||
|
||||
SOXCOMMAND = "sox {} -r 8000 -c 1 -b 16 {}" # for converting wave file
|
||||
## install sox, or use itunes or audacity to convert
|
||||
## wavefile to 8kHz, 16-bit, one-channel
|
||||
|
||||
wavefiles = [x for x in os.walk(".").next()[2] if x.endswith(".wav")]
|
||||
for filename in wavefiles:
|
||||
|
||||
filename = testWaveFile(filename)
|
||||
packedData = packTwoBitDPCM(filename)
|
||||
createHeader(filename, packedData)
|
||||
|
||||
## And create a digits set:
|
||||
digits = ["one", "two", "three", "four", "five", "six",
|
||||
"seven", "eight", "nine", "zero", "point", "volts"]
|
||||
allDigits = open("allDigits.h", "w")
|
||||
for digit in digits:
|
||||
filename = "DPCM_" + digit + "_8000.h"
|
||||
print filename
|
||||
allDigits.write(open(filename).read())
|
||||
allDigits.close()
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
*8000.wav
|
||||
DPCM*.h
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,125 @@
|
||||
// Talking Voltmeter Example
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <util/delay.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/power.h>
|
||||
#include "pinDefines.h"
|
||||
#include "USART.h"
|
||||
|
||||
#include "talkingVoltmeter.h"
|
||||
|
||||
void startSampleTimer(void) {
|
||||
sampleNumber = 0; /* back to start of sample table */
|
||||
TCCR2B = (1 << CS21); /* turn on timer clock */
|
||||
/* Two clock options above end up ~8kHz on 8MHz system */
|
||||
}
|
||||
void stopSampleTimer(void) {
|
||||
TCCR2B = 0; /* disable sample-playback clock */
|
||||
OCR0A = 128; /* idle PWM at mid-voltage */
|
||||
lastout = 0; /* start at 0 next time */
|
||||
}
|
||||
void speak(void) {
|
||||
startSampleTimer();
|
||||
loop_until_bit_is_clear(TCCR2B, CS21); /* Wait until done */
|
||||
}
|
||||
|
||||
void updatePWMAudio(void) {
|
||||
OCR0A = out + 128; /* re-center for 0-255 PWM */
|
||||
lastout = out; /* update last value */
|
||||
sampleNumber++; /* on to next sample */
|
||||
}
|
||||
void unpackByte(uint8_t dataByte) {
|
||||
/* Select pairs of bits from byte, save out */
|
||||
differentials[0] = (dataByte >> 6) & 0b00000011;
|
||||
differentials[1] = (dataByte >> 4) & 0b00000011;
|
||||
differentials[2] = (dataByte >> 2) & 0b00000011;
|
||||
differentials[3] = (dataByte & 0b00000011);
|
||||
}
|
||||
|
||||
/* Timer 2 controls sampling speed.
|
||||
ISR reads new data, loads PWM values into OCR0A */
|
||||
ISR(TIMER2_COMPA_vect) {
|
||||
/* Since we can decode 4 2-bit values at once, need to know where
|
||||
we are in the 4-step mini-cycle. */
|
||||
uint8_t cycle = sampleNumber & 0b00000011; /* keep last 2 bits */
|
||||
uint16_t tableEntry;
|
||||
uint8_t packedData;
|
||||
|
||||
if (cycle == 0) { /* at first sample, re-load */
|
||||
tableEntry = sampleNumber >> 2; /* where we are in table */
|
||||
if (tableEntry < thisTableLength) {
|
||||
/* read the next byte from the selected table */
|
||||
packedData = pgm_read_byte(&thisTableP[tableEntry]);
|
||||
unpackByte(packedData); /* split up byte into differentials[] */
|
||||
}
|
||||
else { /* at end of table, done. */
|
||||
stopSampleTimer();
|
||||
}
|
||||
}
|
||||
/* Decode the differences: current value = last + difference */
|
||||
out = lastout + dpcmWeights[differentials[cycle]] - (lastout >> 4);
|
||||
updatePWMAudio();
|
||||
} // end ISR (TIMER2_COMPA_vect)
|
||||
|
||||
void printString_Progmem(const char *stringP) {
|
||||
char oneLetter;
|
||||
while ((oneLetter = pgm_read_byte(stringP))) {
|
||||
transmitByte(oneLetter);
|
||||
stringP++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(void) {
|
||||
uint16_t voltage;
|
||||
uint8_t volts;
|
||||
uint8_t tenths;
|
||||
uint8_t vcc = 51; /* 10x VCC, in volts */
|
||||
|
||||
clock_prescale_set(clock_div_1); /* 8 MHz */
|
||||
initTimer0();
|
||||
initTimer2();
|
||||
sei(); /* for timer2 ISR */
|
||||
initADC();
|
||||
initUSART();
|
||||
|
||||
printString_Progmem(PSTR("\r\n--=( Talking Voltmeter )=--\r\n"));
|
||||
|
||||
selectTable(INTRO);
|
||||
speak();
|
||||
|
||||
while (1) {
|
||||
|
||||
ADCSRA |= (1 << ADSC); /* start ADC */
|
||||
loop_until_bit_is_clear(ADCSRA, ADSC);
|
||||
|
||||
voltage = ADC * vcc + vcc / 2; /* vcc/2 to make rounding work */
|
||||
voltage = voltage >> 10; /* divide by 10-bits for ADC */
|
||||
/* "voltage" is now actually 10x real-world voltage */
|
||||
volts = voltage / 10;
|
||||
tenths = voltage % 10;
|
||||
|
||||
transmitByte('0' + volts); /* serial output as well */
|
||||
selectTable(volts); /* 0 points to ZERO_TABLE, etc */
|
||||
speak();
|
||||
|
||||
transmitByte('.');
|
||||
selectTable(POINT);
|
||||
speak();
|
||||
|
||||
transmitByte('0' + tenths);
|
||||
selectTable(tenths);
|
||||
speak();
|
||||
|
||||
printString_Progmem(PSTR(" volts\r\n"));
|
||||
selectTable(VOLTS);
|
||||
speak();
|
||||
|
||||
_delay_ms(SPEECH_DELAY);
|
||||
|
||||
} /* end while */
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/* Include file with DPCM data in it */
|
||||
#include "allDigits.h"
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
// Now define sample-table names used in digits file
|
||||
// From here on, no matter what you call the samples,
|
||||
// you can refer to them as "ONE_TABLE", etc.
|
||||
#define ONE_TABLE DPCM_one_8000
|
||||
#define TWO_TABLE DPCM_two_8000
|
||||
#define THREE_TABLE DPCM_three_8000
|
||||
#define FOUR_TABLE DPCM_four_8000
|
||||
#define FIVE_TABLE DPCM_five_8000
|
||||
#define SIX_TABLE DPCM_six_8000
|
||||
#define SEVEN_TABLE DPCM_seven_8000
|
||||
#define EIGHT_TABLE DPCM_eight_8000
|
||||
#define NINE_TABLE DPCM_nine_8000
|
||||
#define ZERO_TABLE DPCM_zero_8000
|
||||
#define POINT_TABLE DPCM_point_8000
|
||||
#define VOLTS_TABLE DPCM_volts_8000
|
||||
#define INTRO_TABLE DPCM_talkingvoltmeter_8000
|
||||
|
||||
#define SPEECH_DELAY 2000 /* milliseconds */
|
||||
|
||||
/* --------------- Globals used by the ISR -------------- */
|
||||
volatile uint8_t* thisTableP; /* points at the current speech table */
|
||||
volatile uint16_t thisTableLength; /* length of current speech table */
|
||||
|
||||
volatile uint16_t sampleNumber; // sample index
|
||||
volatile int8_t out, lastout; // output values
|
||||
volatile uint8_t differentials[4] = {0,0,0,0};
|
||||
const int8_t dpcmWeights[4] = {-12, -3, 3, 12};
|
||||
|
||||
|
||||
/* These arrays let us choose a table (and its length) numerically */
|
||||
const uint16_t tableLengths[] = { /* all sample tables are 8-bit */
|
||||
sizeof(ZERO_TABLE), sizeof(ONE_TABLE), sizeof(TWO_TABLE),
|
||||
sizeof(THREE_TABLE), sizeof(FOUR_TABLE), sizeof(FIVE_TABLE),
|
||||
sizeof(SIX_TABLE), sizeof(SEVEN_TABLE), sizeof(EIGHT_TABLE),
|
||||
sizeof(NINE_TABLE), sizeof(POINT_TABLE), sizeof(VOLTS_TABLE),
|
||||
sizeof(INTRO_TABLE)
|
||||
};
|
||||
|
||||
// Create an indexing table of all of the start addresses for
|
||||
// each spoken digit. And then store this index in PROGMEM.
|
||||
const uint8_t* const tablePointers[] PROGMEM = {
|
||||
ZERO_TABLE, ONE_TABLE, TWO_TABLE, THREE_TABLE, FOUR_TABLE,
|
||||
FIVE_TABLE, SIX_TABLE, SEVEN_TABLE, EIGHT_TABLE, NINE_TABLE,
|
||||
POINT_TABLE, VOLTS_TABLE, INTRO_TABLE
|
||||
};
|
||||
|
||||
void selectTable(uint8_t whichTable){
|
||||
/* Set up global table pointer, lengths */
|
||||
uint16_t pointerAddress;
|
||||
thisTableLength = tableLengths[whichTable];
|
||||
pointerAddress = (uint16_t) &tablePointers[whichTable];
|
||||
thisTableP = (uint8_t*) pgm_read_word(pointerAddress);
|
||||
}
|
||||
|
||||
/* Extra defines for the non-numeric values */
|
||||
#define POINT 10
|
||||
#define VOLTS 11
|
||||
#define INTRO 12
|
||||
|
||||
|
||||
///----------------- Init functions -------------------///
|
||||
|
||||
void initTimer0(void){
|
||||
// Timer 0 Configured for free-running PWM Audio Output
|
||||
TCCR0A |= (1<<WGM00) | (1<<WGM01); /* fast PWM mode */
|
||||
TCCR0A |= (1<<COM0A0) | (1<<COM0A1); /* output on PD6/OC0A */
|
||||
TCCR0B = (1<<CS00); /* fastest clock */
|
||||
OCR0A = 128 ; /* initialize mid-value */
|
||||
SPEAKER_DDR |= (1<<SPEAKER); /* output PD6 / OC0A */
|
||||
}
|
||||
|
||||
void initTimer2(void){
|
||||
// Timer 2 loads OCR0A, provides sampling frequency
|
||||
TCCR2A = (1<<WGM21); /* CTC, count to OCR2A */
|
||||
TIMSK2 = (1<<OCIE2A); /* turn on compare interrupt */
|
||||
OCR2A = 128; /* controls sample playback frequency */
|
||||
/* note: no clock source selected yet, so won't start up */
|
||||
}
|
||||
|
||||
void initADC(void){
|
||||
// ADC for Voltmeter function
|
||||
ADMUX |= (0b00001111 & PC5); /* set mux to ADC5 */
|
||||
DIDR0 |= _BV(ADC5D); /* turn off digital circuitry on PC5 */
|
||||
ADMUX |= (1 << REFS0); /* reference voltage is AVCC, 5V */
|
||||
ADCSRA |= (1 << ADPS1) | (1 << ADPS2); /* ADC clock prescaler /64 */
|
||||
ADCSRA |= (1 << ADEN); /* enable ADC */
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
## Functions to convert mono, 8kHz .wav files to differential PCM
|
||||
|
||||
## If you've got 'sox' installed on your computer, this code calls
|
||||
## 'sox' and re-codes the files for you. If not, you've got to do it.
|
||||
|
||||
## Finally, given a bunch of wav files with names like one.wav, two.wav
|
||||
## this writes the DPCM data out to a header file for including in AVR C
|
||||
|
||||
from struct import unpack
|
||||
import wave
|
||||
import os
|
||||
import sys
|
||||
|
||||
def unpackMono(waveFile):
|
||||
w = wave.Wave_read(waveFile)
|
||||
data = []
|
||||
for i in range(w.getnframes()):
|
||||
data.append(unpack("h", w.readframes(1))[0])
|
||||
return(data)
|
||||
|
||||
def scaleData(data):
|
||||
scale = max(max(data), abs(min(data))) * 1.0
|
||||
return([x/scale for x in data])
|
||||
|
||||
def getDifferences(data):
|
||||
differences = []
|
||||
for i in range(len(data)-1):
|
||||
differences.append(data[i+1]-data[i])
|
||||
return(differences)
|
||||
|
||||
def quantize(data, thresholds):
|
||||
quantized = []
|
||||
n = len(thresholds)
|
||||
thresholdRange = range(n)
|
||||
for d in data:
|
||||
categorized = False
|
||||
for i in thresholdRange:
|
||||
if d <= thresholds[i]:
|
||||
quantized.append(i)
|
||||
categorized = True
|
||||
break
|
||||
if not categorized:
|
||||
quantized.append(n)
|
||||
return(quantized)
|
||||
|
||||
def pack4(data): # for 2-bit data
|
||||
packedData = []
|
||||
for i in range(len(data) / 4):
|
||||
thisByte = 0
|
||||
thisByte += 2**6 * data[4*i]
|
||||
thisByte += 2**4 * data[4*i+1]
|
||||
thisByte += 2**2 * data[4*i+2]
|
||||
thisByte += data[4*i+3]
|
||||
packedData.append(thisByte)
|
||||
return(packedData)
|
||||
|
||||
def packTwoBitDPCM(filename):
|
||||
data = unpackMono(filename)
|
||||
data = scaleData(data)
|
||||
differences = getDifferences(data)
|
||||
quantized = quantize(differences, TWO_BIT_THRESHOLDS)
|
||||
packed = pack4(quantized)
|
||||
return(packed)
|
||||
|
||||
def createHeader(filename, packedData):
|
||||
baseFilename = filename[:-4]
|
||||
outfile = open("DPCM_" + baseFilename + ".h", "w")
|
||||
outfile.write('const uint8_t DPCM_{}[] PROGMEM = {{\n'.format(baseFilename))
|
||||
for byte in packedData:
|
||||
outfile.write(' {:d},\n'.format(byte))
|
||||
outfile.write('};\n')
|
||||
outfile.close()
|
||||
|
||||
def fixWaveFile(filename):
|
||||
w = wave.Wave_read(filename)
|
||||
bitrate = w.getframerate()
|
||||
channels = w.getnchannels()
|
||||
bits = w.getsampwidth()*8
|
||||
if not bitrate==8000 or not channels==1 or not bits==16:
|
||||
newFilename = filename[:-4] + "_8000.wav"
|
||||
returnValue = os.system(SOXCOMMAND.format(filename, newFilename))
|
||||
if returnValue:
|
||||
raise(SOX_Exception("""Something went wrong calling sox:
|
||||
SOXCOMMAND.format(filename, newFilename
|
||||
Is sox installed? If not, just make sure that you've saved 8kHz mono wav files."""))
|
||||
filename = newFilename
|
||||
return(filename)
|
||||
|
||||
|
||||
class SOX_Exception(Exception):
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
## Default is to convert all wav files in the current directory.
|
||||
|
||||
TWO_BIT_THRESHOLDS = [-0.05, 0, 0.05]
|
||||
|
||||
SOXCOMMAND = "sox {} -r 8000 -c 1 -b 16 {}" # for converting wave file
|
||||
## install sox, or use itunes or audacity to convert
|
||||
## wavefile to 8kHz, 16-bit, one-channel
|
||||
|
||||
wavefiles = [x for x in os.walk(".").next()[2] if x.endswith(".wav")]
|
||||
for filename in wavefiles:
|
||||
filename = fixWaveFile(filename) # converts if needed, returns new filename
|
||||
packedData = packTwoBitDPCM(filename)
|
||||
createHeader(filename, packedData)
|
||||
|
||||
## And create a digits sample set for talkingVoltmeter.h:
|
||||
digits = ["one", "two", "three", "four", "five", "six",
|
||||
"seven", "eight", "nine", "zero",
|
||||
"point", "volts", "talkingvoltmeter"]
|
||||
allDigits = open("allDigits.h", "w")
|
||||
for digit in digits:
|
||||
filename = "DPCM_" + digit + "_8000.h"
|
||||
print filename
|
||||
allDigits.write(open(filename).read())
|
||||
allDigits.close()
|
||||
|
||||
Reference in New Issue
Block a user