Pitchshifter ATTINY85 Potentiometer

Started by BIGBADBOIGUITAR, May 05, 2018, 03:11:22 PM

Previous topic - Next topic

BIGBADBOIGUITAR

Hey there

I stumbled across a cool project for a pitchshifter using an attiny85 chips, I'd like to modify the code to swap the push buttons for a potentiometer but my coding is a little shaky.

Any advice would be much appreciated, the code and project link are below.

http://www.technoblogy.com/show?1L02   //website

/* Audio Pitch Shifter

   David Johnson-Davies - www.technoblogy.com - 11th February 2017
   ATtiny85 @ 8MHz (internal oscillator; BOD disabled)
   
   CC BY 4.0
   Licensed under a Creative Commons Attribution 4.0 International license:
   http://creativecommons.org/licenses/by/4.0/
*/

volatile uint8_t Buffer[256];             // Circular buffer
volatile uint8_t ReadPtr, WritePtr, LastPtr, New;

// Everything done by interrupts **********************************

// ADC conversion complete - save sample in buffer
ISR (ADC_vect) {
  Buffer[LastPtr] = New;
  New = ADCH + 128;
  Buffer[WritePtr] = (Buffer[WritePtr] + New)>>1;
  LastPtr = WritePtr;
  WritePtr = (WritePtr + 1) & 0xFF;
}

// Timer interrupt - read from buffer and output to DAC
ISR (TIMER0_COMPA_vect) {
  OCR1A = Buffer[ReadPtr];
  ReadPtr = (ReadPtr + 1) & 0xFF;
}

// Pin change interrupt adjusts shift
ISR (PCINT0_vect) {
  int Buttons = PINB;
  if ((Buttons & 0x01) == 0) OCR0A++;
  else if ((Buttons & 0x04) == 0) OCR0A--;
}

// Setup **********************************************
 
void setup () {
  // Enable 64 MHz PLL and use as source for Timer1
  PLLCSR = 1<<PCKE | 1<<PLLE;     

  // Set up Timer/Counter1 for PWM output
  TIMSK = 0;                              // Timer interrupts OFF
  TCCR1 = 1<<PWM1A | 2<<COM1A0 | 1<<CS10; // PWM OCR1A, clear on match, 1:1 prescale
  OCR1A = 128;
  pinMode(1, OUTPUT);                     // Enable OC1A PWM output pin

  // Set up Timer/Counter0 to generate 20kHz interrupt
  TCCR0A = 2<<WGM00;                      // CTC mode
  TCCR0B = 2<<CS00;                       // /8 prescaler
  OCR0A = 55;                             // 17.9kHz interrupt
  TIMSK = TIMSK | 1<<OCIE0A;              // Enable interrupt
 
  // Set up ADC
  ADMUX = 2<<REFS0 | 1<<ADLAR | 7<<MUX0;  // Internal 1.1V ref, ADC2 vs ADC3, x20
  // Enable, auto trigger, interrupt, 250kHz ADC clock:
  ADCSRA = 1<<ADEN | 1<<ADSC | 1<<ADATE | 1<<ADIE | 5<<ADPS0; 
  ADCSRB = 1<<7 | 0<<ADTS0;               // Bipolar, free-running

  // Set up buttons on PB0 and PB2
  pinMode(0, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  PCMSK = 1<<PINB0 | 1<<PINB2;            // Pin change interrupts on PB0 and PB2
  GIMSK = GIMSK | 1<<PCIE;                // Enable pin change interrupt
}




potul

The code you posted uses a button interrupt to detect button pushes and adjust OCR0A.

ISR (PCINT0_vect) {
  int Buttons = PINB;
  if ((Buttons & 0x01) == 0) OCR0A++;
  else if ((Buttons & 0x04) == 0) OCR0A--;
}


you will need to remove this iterrupt, and add a routine somewhere that reads another ADC (fed by the pot) and does a similar thing. You can either have this check running continously in the main routine, or add it to another interrupt by timer.

I would probably just add a main function that takes care of the pot as it's not time-critical.

ElectricDruid

I don't know the ATTiny chip well, but it may not be possible if the pitch shifter algorithm is sampling the ADC as fast as it can.

I spent quite a while trying to find a way around a similar problem on a PIC - in the end, there wasn't enough time to sample one input at an audio rate, and also a couple of pots at a slower rate. Depends how fast the ADC can be set, and how fast the sample rate is (20KHz or 17.9KHz from the code?). How many ADC clocks are required on this chip to make an ADC reading?

HTH,
Tom

anotherjim

I'd have to refresh my memory on this chip.
I know the ADC if read continuously takes 13 clocks. While that is going on you can switch the input mux ready for reading a different pin. The ADC clock can be higher than recommended for accuracy (we aren't guiding rockets) but I still concluded the ADC can only realistically sample one audio input. For potentiometer controls, you must find another way.

Another way of reading a pot is to make it part of a variable RC timer using one of the timer/counters. The count value reached in a given fixed time frame is proportional to the resistance of the pot. The input pins have Schmitt trigger action and the slewed response of the external RC network make it a fairly jitter free method. All I would do to "debounce" is to average each new reading with the previous (add & shift right).

MR COFFEE

ATtiny ADC is only 10 bits IIRC. Pretty grainy, if you could even make it work.

mr coffee

Bart

ElectricDruid

#5
One-chip pitch shifters at this level do tend to be "pretty grainy", or worse. I mean, what other option have you got? - Aside from the FV-1 (not bad), there's that robot voice chip HTwhatever-it-is? That's not setting the bar for this type of thing too high. ATTiny might even do better, who knows. That'd make it the second-best option!

cracked_machine

Bit late to the party....

You would need to remove the pushbuttons from PB2 and PB0 and add the potentiometer to one of the pins that supports ADC use. PB2, PB3 or PB5(maybe not use the reset pin) are not being used.

Then you need to use ADC_vect ISR to process the pot input instead of PCINT0_vect. In the ISR, you can multiplex between different ADC channels. There are plenty of examples out there to demo this.

Bear in mind you will be sharing this ADC interrupt with the signal input so it will negatively affect your ADC conversion rates, although as people have already said it wasn't great to start with.  I guess if you want a bit shifter effect thrown in, then you're in luck  :icon_mrgreen:

You might be better served by using separate ADC and DAC ICs with higher conversion rates....or just use an Cortex M4.