Trying to get a part of Adafruits voice changer code to run on the ATTINY85 using an MCP4921 & MAX4466
I've swapped over the interrupts to Timer0 and subsequently changed the pre-scaling to 64:1 as there is no 32:1 on timer0
I can't seem to get the DAC to get any signal.
Pins are connected as such:
ATTINY:
P0 AREF connected to Vcc
P1 SDI on MCP4921 (pin4)
P2 SCK on MCP4921 (pin3)
P3 CS on MCP4921 (pin 2)
P4 Not connected (will be mode button)
P5 MAX4466 Out Pin
MCP4921
P1 connected to Vcc
P2>4 as above
P5/7 to ground
P6 to Vcc
P8 to Speaker
MAX4466
P1 Vcc
P2 GND
p3 At P5
// PINS CS(CHIP SELECT)Atpin3, SCK (Serial Clock Input)AtPin2, SDI (Serial Data Input) DO(Atpin1)
#include <tinySPI.h>
#define DAC_CS 3
#define BTN_PIN 4
#define PLAYBUFFLEN 512UL
#define MAXBTN 10
#define XFADE 16 //Samples for Cross-fade
#define MAX_SAMPLES (PLAYBUFFLEN - XFADE) // Remaining available audio samples
uint16_t in = 0, out = 0, xf = 0, nSamples = 128; // Audio sample counters, maybe able to vary nSamples
uint8_t adc_save; // Default ADC mode
uint8_t
buffer1[PLAYBUFFLEN], // Audio sample LSB
buffer2[PLAYBUFFLEN]; // Audio sample MSB
//////////////////////////////////// SETUP
void setup() {
//Initialise DAC outputs
SPI.begin();
//Initialise Button Input
//pinMode(BTN_PIN, INPUT);
pinMode(DAC_CS, OUTPUT);
analogReference(EXTERNAL); // AREF
//Set latch pin HIGH so DAC isn't selected
digitalWrite(DAC_CS, HIGH);
//Save ADC settings for restore later
adc_save = ADCSRA;
// Start PitchShift
startPitchShift();
}
//////////////////////////////////// LOOP
void loop() {
if(!(TIMSK & _BV(TOIE0))) startPitchShift(); //Timer Interrupt mask register & overflow interrupt
// add button presses stuff here: Hold Disable, Single tap go up,
}
//////////////////////////////////// PITCH-SHIFT CODE
void startPitchShift() {
int pitch = 5; // ------------------------------------------------------------------------SET PITCH
memset(buffer1, 0, nSamples + XFADE); // Clear sample buffers
memset(buffer2, 2, nSamples + XFADE); // (set all samples to 512)
// Use Timer0 for sample playing interrupt. It is a 16-bit timer with a pre-scaler of (64:1)
TCCR0A = _BV(WGM01) | _BV(WGM00); //Set timer0 to MOde 7, and Fast PWM
TCCR0B = _BV(WGM02) | _BV(CS01) | _BV(CS00); //Toggle OC2A on Compare Match & Set 64:1 pre-scale
OCR0A = map(pitch, 0, MAXBTN,
F_CPU / 64 / (9615 / 2), // Lowest pitch = -1 octave
F_CPU / 64 / (9615 * 2)); // Highest pitch = +1 octave
// Start up ADC in free-run mode for audio sampling:
DIDR0 |= _BV(ADC0D); // Disable digital input buffer on ADC0
ADMUX = 0x00; //ADMUX ADC Set AREF (PB0) as external, Right Adjusted, ADC0 (PB5) as input
ADCSRB = 0x00; // Free-run mode
ADCSRA =
_BV(ADEN) | // Enable ADC
_BV(ADSC) | // Start conversion
_BV(ADATE) | // Auto-trigger enable
_BV(ADIE) | // Interrupt enable
_BV(ADPS2) | // 128:1 pre-scale
_BV(ADPS1) | // yields 125 KHz ADC clock
_BV(ADPS0); // 13 cycles/conversion = ~9615 Hz
TIMSK |= _BV(TOIE0); // Enable Timer0 overflow interrupt
sei(); // Enable interrupts -------------------------------------------------------------------------------CHECK
}
void stopPitchShift() {
ADCSRA = adc_save; // Disable ADC interrupt and allow normal use
TIMSK = 0; // Disable Timer0 Interrupt
}
ISR(ADC_vect,ISR_BLOCK) { // ADC conversion complete
// Save old sample from 'in' position to Xfade buffer:
buffer1[nSamples + xf] = buffer1[in];
buffer2[nSamples + xf] = buffer2[in];
if(++xf >= XFADE) xf = 0;
// Store new value in sample buffers:
buffer1[in] = ADCL; // MUST read ADCL first!
buffer2[in] = ADCH;
if(++in >= nSamples) in = 0;
}
ISR(TIM0_OVF_vect) { // Playback interrupt
uint16_t s;
uint8_t w, inv, hi, lo, bit;
int o2, i2, pos;
// Cross fade around circular buffer 'seam'.
if((o2 = (int)out) == (i2 = (int)in)) {
// Sample positions coincide. Use cross-fade buffer data directly.
pos = nSamples + xf;
hi = (buffer2[pos] << 2) | (buffer1[pos] >> 6); // Expand 10-bit data
lo = (buffer1[pos] << 2) | buffer2[pos]; // to 12 bits
} if((o2 < i2) && (o2 > (i2 - XFADE))) {
// Output sample is close to end of input samples. Cross-fade to
//avoid click. The shift operations here assume that XFADE is 16;
// will need adjustment if that changes.
w = in - out; // Weight of sample (1-n)
inv = XFADE - w; // Weight of xfade
pos = nSamples + ((inv + xf) % XFADE);
s = ((buffer2[out] << 8) | buffer1[out]) * w +
((buffer2[pos] << 8) | buffer1[pos]) * inv;
hi = s >> 10; // Shift 14 bit result
lo = s >> 2; // down to 12 bits
} else if (o2 > (i2 + nSamples - XFADE)) {
// More cross-fade condition
w = in + nSamples - out;
inv = XFADE - w;
pos = nSamples + ((inv + xf) % XFADE);
s = ((buffer2[out] << 8) | buffer1[out]) * w +
((buffer2[pos] << 8) | buffer1[pos]) * inv;
hi = s >> 10; // Shift 14 bit result
lo = s >> 2; // down to 12 bits
} else {
// Input and output counters don't coincide -- just use sample directly.
hi = (buffer2[out] << 2) | (buffer1[out] >> 6); // Expand 10-bit data
lo = (buffer1[out] << 2) | buffer2[out]; // to 12 bits
}
digitalWrite(DAC_CS, LOW);
//Output 8 bits (4 config, 4 hi buffer) then next 8 bits of 8 lo buffer
// combine config bits with hi bits (30 = 0011 << 4) 0 (DAC A), 0 (unbuffered), 1 (Gain x1 enable), 1 (output buffer disabled)
hi = (0x1E & 0xF0) | hi;
SPI.transfer(hi);
SPI.transfer(lo);
digitalWrite(DAC_CS, HIGH);
if(++out >= nSamples) out = 0;
}