dodanie plikow
This commit is contained in:
commit
8d3482ec6f
21
MCP4xxx.h
Normal file
21
MCP4xxx.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#include "spi.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define nWR 7 //bit aktywacja zapisu do rejestru przetwornika
|
||||||
|
#define DC 6 //bit nieużywany (Don't Care)
|
||||||
|
#define GA 5 //bit wyboru wzmocnienia
|
||||||
|
#define SHDN 4 //bit aktywacji wyjścia
|
||||||
|
|
||||||
|
#define GAIN_X1 1
|
||||||
|
#define GAIN_X2 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CONF1 0b00110000 //gain x1
|
||||||
|
#define CONF2 0b00010000 //gain x2
|
||||||
|
|
||||||
|
void analogWrite(uint8_t data){
|
||||||
|
SS_LOW;
|
||||||
|
spiTransfer(CONF1 | (data>>4));
|
||||||
|
spiTransfer(data<<4);
|
||||||
|
SS_HIGH;
|
||||||
|
}
|
109
effects.h
Normal file
109
effects.h
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
#include "MCP4xxx.h"
|
||||||
|
|
||||||
|
#define BUFFER_LENGTH 1851
|
||||||
|
//Przeliczenie przesunięcia w próbkach na czas dla fs = 10 kHz
|
||||||
|
#define _0MS 0
|
||||||
|
#define _1MS 10
|
||||||
|
#define _5MS 50
|
||||||
|
#define _10MS 100
|
||||||
|
#define _15MS 150
|
||||||
|
#define _16MS 160
|
||||||
|
#define _18MS 180
|
||||||
|
#define _20MS 200
|
||||||
|
#define _23MS 230
|
||||||
|
#define _25MS 250
|
||||||
|
#define _30MS 300
|
||||||
|
#define _35MS 350
|
||||||
|
#define _40MS 400
|
||||||
|
#define _41MS 410
|
||||||
|
#define _50MS 500
|
||||||
|
#define _60MS 600
|
||||||
|
#define _70MS 700
|
||||||
|
#define _80MS 800
|
||||||
|
#define _85MS 850
|
||||||
|
#define _90MS 900
|
||||||
|
#define _100MS 1000
|
||||||
|
#define _105MS 1050
|
||||||
|
#define _110MS 1100
|
||||||
|
#define _120MS 1200
|
||||||
|
#define _135MS 1350
|
||||||
|
#define _140MS 1400
|
||||||
|
#define _150MS 1500
|
||||||
|
#define _160MS 1600
|
||||||
|
#define _170MS 1700
|
||||||
|
#define _175MS 1750
|
||||||
|
#define _180MS 1800
|
||||||
|
#define _185MS 1850
|
||||||
|
|
||||||
|
|
||||||
|
int16_t reverb(uint8_t buffer [BUFFER_LENGTH], uint16_t bufferIndex, uint8_t roomSize){
|
||||||
|
int16_t echo1Index = bufferIndex - _35MS;
|
||||||
|
if(echo1Index < 0) echo1Index += BUFFER_LENGTH;
|
||||||
|
int16_t echo2Index = bufferIndex - _60MS;
|
||||||
|
if(echo2Index < 0) echo2Index += BUFFER_LENGTH;
|
||||||
|
int16_t echo3Index = bufferIndex - _85MS;
|
||||||
|
if(echo3Index < 0) echo3Index += BUFFER_LENGTH;
|
||||||
|
int16_t echo4Index = bufferIndex - _110MS;
|
||||||
|
if(echo4Index < 0) echo4Index += BUFFER_LENGTH;
|
||||||
|
int16_t echo5Index = bufferIndex - _135MS;
|
||||||
|
if(echo5Index < 0) echo5Index += BUFFER_LENGTH;
|
||||||
|
int16_t echo6Index = bufferIndex - _160MS;
|
||||||
|
if(echo6Index < 0) echo6Index += BUFFER_LENGTH;
|
||||||
|
int16_t echo7Index = bufferIndex - _185MS;
|
||||||
|
if(echo6Index < 0) echo7Index += BUFFER_LENGTH;
|
||||||
|
|
||||||
|
//wyznaczenie zmiennych tymczasowych (bez składowych stałych)
|
||||||
|
int16_t echo1Temp = -128 + buffer[echo1Index];
|
||||||
|
int16_t echo2Temp = -128 + buffer[echo2Index];
|
||||||
|
int16_t echo3Temp = -128 + buffer[echo3Index];
|
||||||
|
int16_t echo4Temp = -128 + buffer[echo4Index];
|
||||||
|
int16_t echo5Temp = -128 + buffer[echo5Index];
|
||||||
|
int16_t echo6Temp = -128 + buffer[echo6Index];
|
||||||
|
int16_t echo7Temp = -128 + buffer[echo6Index];
|
||||||
|
|
||||||
|
//obliczenie wartości próbki do przekazania DAC i przywrócenie składowej stałej
|
||||||
|
if(roomSize == 1){
|
||||||
|
return (1*echo1Temp + 3*echo2Temp + 2*echo3Temp)/30 +128;
|
||||||
|
} else if(roomSize == 2){
|
||||||
|
return (1*echo1Temp + 3*echo2Temp + 2*echo3Temp + 2*echo4Temp)/30 +128;
|
||||||
|
} else if(roomSize == 3){
|
||||||
|
return (1*echo1Temp + 3*echo2Temp + 3*echo3Temp + 2*echo4Temp + 1*echo5Temp)/30 +128;
|
||||||
|
} else if(roomSize == 4){
|
||||||
|
return (2*echo1Temp + 4*echo2Temp + 3*echo3Temp + 2*echo4Temp + 1*echo5Temp)/30 +128;
|
||||||
|
} else if(roomSize == 5){
|
||||||
|
return (2*echo1Temp + 4*echo2Temp + 3*echo3Temp + 3*echo4Temp + 2*echo5Temp + 1*echo6Temp)/30 +128;
|
||||||
|
} else if(roomSize == 6){
|
||||||
|
return (2*echo1Temp + 5*echo2Temp + 4*echo3Temp + 3*echo4Temp + 3*echo5Temp + 1*echo6Temp)/30 +128;
|
||||||
|
} else if(roomSize == 7){
|
||||||
|
return (2*echo1Temp + 5*echo2Temp + 5*echo3Temp + 4*echo4Temp + 3*echo5Temp + 2*echo6Temp + 1*echo7Temp)/30 +128;
|
||||||
|
} else if(roomSize == 8){
|
||||||
|
return (3*echo1Temp + 6*echo2Temp + 5*echo3Temp + 4*echo4Temp + 4*echo5Temp + 2*echo6Temp + 2*echo7Temp)/30 +128;
|
||||||
|
} else {
|
||||||
|
return (3*echo1Temp + 7*echo2Temp + 6*echo3Temp + 5*echo4Temp + 4*echo5Temp + 3*echo6Temp + 2*echo7Temp)/30 +128;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int16_t distortion(uint8_t cutoff, uint8_t adcVal){
|
||||||
|
//jeżeli wartość przekracza ustawiony próg, to jest ona do nigo zmniejszana (ucinanie górnej części przebiegu)
|
||||||
|
if (adcVal > cutoff){
|
||||||
|
return cutoff;
|
||||||
|
} else {
|
||||||
|
return adcVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int16_t chorusFlanger(uint8_t buffer [BUFFER_LENGTH], uint16_t bufferIndex, uint16_t delayVal, uint8_t attenuationLevel){
|
||||||
|
int16_t echoIndex = bufferIndex - delayVal;
|
||||||
|
if(echoIndex < 0) echoIndex += BUFFER_LENGTH;
|
||||||
|
int16_t echoTemp = -128 + buffer[echoIndex];
|
||||||
|
|
||||||
|
return echoTemp/(1+attenuationLevel) + 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t tremolo(uint8_t adcVal, uint8_t amplitudeLevel){
|
||||||
|
return ((adcVal - 128)*(amplitudeLevel+70))/271 + 128;
|
||||||
|
}
|
356
main.cpp
Normal file
356
main.cpp
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
#include "effects.h"
|
||||||
|
|
||||||
|
#define TESTING 0
|
||||||
|
#define REVERB 1
|
||||||
|
#define CHORUS 2
|
||||||
|
#define FLANGER 3
|
||||||
|
#define ECHO 4
|
||||||
|
#define DISTORTION 5
|
||||||
|
#define TREMOLO 6
|
||||||
|
|
||||||
|
volatile uint8_t sampleReady = 0; //zmienna kotrolująca możliwość podania nowej wartości do DAC
|
||||||
|
volatile uint8_t adcVal = 0;
|
||||||
|
volatile uint8_t effect = REVERB; //wybrany efekt
|
||||||
|
volatile uint32_t counter = 0;
|
||||||
|
const uint8_t sine [101] = {0,0,0,0,1,1,2,2,3,4,5,6,7,8,10,11,12,14,16,17,19,21,23,25,27,29,32,34,36,39,41,44,46,49,
|
||||||
|
52,55,57,60,63,66,69,72,75,78,81,84,87,91,94,97,100,103,106,109,113,116,119,122,125,128,131,134,137,140,143,145,148,
|
||||||
|
151,154,156,159,161,164,166,168,171,173,175,177,179,181,183,184,186,188,189,190,192,193,194,195,196,197,198,198,199,
|
||||||
|
199,200,200,200,200};
|
||||||
|
volatile uint8_t effectSetting = 5;
|
||||||
|
const uint8_t effectSettingVector [9] = {0, 5, 15, 30, 55, 90, 130, 180, 255};
|
||||||
|
volatile uint8_t encoderDir = 0; //0 - w lewo, 1 - w prawo
|
||||||
|
volatile uint8_t encoderServed = 1;
|
||||||
|
|
||||||
|
//timer0 służy tylko do aktywacji odczytu przez ADC (i do debouncingu)
|
||||||
|
ISR(TIMER0_COMPA_vect){
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(TIMER1_OVF_vect){
|
||||||
|
OCR1A = effectSettingVector[effectSetting -1];//20 * effectSetting - 15; //od 25 do 225
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(INT0_vect){
|
||||||
|
if(encoderServed){
|
||||||
|
if(!(PIND & 0x08)){
|
||||||
|
encoderDir = 0;
|
||||||
|
} else if(PIND & 0x08){
|
||||||
|
encoderDir = 1;
|
||||||
|
}
|
||||||
|
encoderServed = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(ADC_vect){
|
||||||
|
adcVal = ADCH;
|
||||||
|
sampleReady = 1; //dopiero po odczytaniu nowej wartości ADC uruchomiona jest możliwość podania nowej wartości do DAC
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void){
|
||||||
|
//wyprowadzenie do sterowania wejsciem sygnalu nieprzetworzonego
|
||||||
|
DDRC |= 1<<DDC5;
|
||||||
|
|
||||||
|
//enkoder do zmiany parametru efektu
|
||||||
|
DDRD &= ~(1<<DDD2 | 1<<DDD3);
|
||||||
|
|
||||||
|
//przycisk do zmiany efektu
|
||||||
|
DDRD &= (1<<DDD4);
|
||||||
|
PORTD |= (1<<DDD4);
|
||||||
|
|
||||||
|
//przycisk do aktywacji efektu
|
||||||
|
DDRD &= (1<<DDD1);
|
||||||
|
PORTD |= (1<<DDD1);
|
||||||
|
|
||||||
|
//diody sygnalizujące wybrany efekt
|
||||||
|
DDRD |= (1<<DDD5) | (1<<DDD6) | (1<<DDD7);
|
||||||
|
|
||||||
|
//dioda sygnalizująca aktywację efektu
|
||||||
|
DDRB |= (1<<DDB0);
|
||||||
|
|
||||||
|
//dioda, której intensywność świecenia wskazuje na parametr efektu
|
||||||
|
DDRB |= (1<<DDB1);
|
||||||
|
|
||||||
|
|
||||||
|
//TIMER0
|
||||||
|
//Prescaler = 64; pojemność bufora 1850;
|
||||||
|
//250 000 / 41,67 kHz = 6 ; 1850 / 41,67 kHz = 44,4 ms
|
||||||
|
//250 000 / 20,83 kHz = 12; 1850 / 20,83 kHz = 88,8 ms
|
||||||
|
//250 000 / 10 kHz = 25; 1850 / 10 kHz = 185 ms
|
||||||
|
//250 000 / 8,065 kHz = 31; 1850 / 8,065 kHz = 229,4 ms
|
||||||
|
//250 000 / 5 kHz = 50; 1850 / 5 kHz = 370 ms
|
||||||
|
TCCR0A = (1<<WGM01); //CTC
|
||||||
|
TCCR0B = (1<<CS01) | (1<<CS00); //prescaler = 64
|
||||||
|
OCR0A = 25;
|
||||||
|
TIMSK0 = (1<<OCIE0A);
|
||||||
|
|
||||||
|
//TIMER1
|
||||||
|
//Do sterowania diodą (PWM)
|
||||||
|
TCCR1A = (1<<COM1A1) | (1<<WGM10); //OC1A, Clear on compare match; Fast PWM 8-bit
|
||||||
|
TCCR1B = (1<<WGM12) | (1<<CS12) | (1<<CS10); //Fast PWM 8-bit; fosc/1024
|
||||||
|
OCR1A = 128;
|
||||||
|
TIMSK1 = (1<<TOIE1); //Przerwanie przy przepełnieniu do aktualizacji wartości wypełnienia.
|
||||||
|
|
||||||
|
//ADC
|
||||||
|
ADMUX = (1<<REFS0) | (1<<ADLAR); //Vref = AVcc, przesuniecie do lewej, ADC0
|
||||||
|
ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADATE) | (1<<ADIE) | (1<<ADPS2) /*(1<<ADPS1) | (1<<ADPS0)*/; //częstotliwość zegara ADC = 1 MHz
|
||||||
|
ADCSRB = (1<<ADTS1) | (1<<ADTS0); //triggerowanie ADC przerwaniem od przepełnienia timera 0
|
||||||
|
DIDR0 = (1<<ADC0D);
|
||||||
|
|
||||||
|
//INT0
|
||||||
|
EICRA = 1<<ISC01; //wyzwalanie zboczem opadającym
|
||||||
|
EIMSK = 1<<INT0; //aktywacja
|
||||||
|
|
||||||
|
sei();
|
||||||
|
spiInit();
|
||||||
|
|
||||||
|
int16_t valueToSend = 128; //wartość do przekazania do DAC; int16_t (16 bitowy, ze znakiem) w celu implementacji nasycenia
|
||||||
|
|
||||||
|
//bufor na dane i jego inicjalizacja wartościami 128
|
||||||
|
uint8_t buffer [BUFFER_LENGTH] = {0};
|
||||||
|
for(uint16_t i = 0; i < BUFFER_LENGTH; i++){
|
||||||
|
buffer[i] = 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t bufferIndex = 0; //indeks najnowszej próbki
|
||||||
|
|
||||||
|
//Przyciski
|
||||||
|
uint32_t counterButton = 0;
|
||||||
|
uint8_t buttonPressed = 0;
|
||||||
|
|
||||||
|
uint32_t counterButton2 = 0;
|
||||||
|
uint8_t buttonPressed2 = 0;
|
||||||
|
uint8_t effectOn = 0;
|
||||||
|
|
||||||
|
//Enkoder
|
||||||
|
uint32_t counterEncoder = 0;
|
||||||
|
|
||||||
|
//Chorus
|
||||||
|
uint8_t sineIndex = 0; //indeks wartości z wektora z sinusem
|
||||||
|
uint8_t chorusCounter = 0; //licznik służacy do spowolnienia zmian w opóźnieniu
|
||||||
|
//użyty zamiast licznika od timera, żeby operować na wartości 8-bitowej zamiast 32-bitowej
|
||||||
|
uint8_t chorusDirChange = 0; //0 - inkrementacja, 1 - dekrementacja
|
||||||
|
|
||||||
|
//Flanger
|
||||||
|
uint8_t flangerDelayTime = _0MS;
|
||||||
|
uint8_t flangerCounter = 0;
|
||||||
|
uint8_t flangerDirChange = 0;
|
||||||
|
|
||||||
|
//Echo
|
||||||
|
uint16_t echoIndex = 0;
|
||||||
|
|
||||||
|
//Tremolo
|
||||||
|
uint8_t tremoloCounter = 0;
|
||||||
|
uint8_t tremoloDirChange = 0;
|
||||||
|
|
||||||
|
while(1){
|
||||||
|
//Obsługa przycisku od przełączania efektu
|
||||||
|
if(counter - counterButton >= _50MS){
|
||||||
|
if(!(PIND & 0x10) && !buttonPressed){
|
||||||
|
//Jeżeli przed zmianą na echo znajduje się coś w buforze, to istnieje ryzyko wystąpienia zapętlenia próbki,
|
||||||
|
//stąd zerowanie buforu.
|
||||||
|
if(effect == ECHO - 1) {
|
||||||
|
for(uint16_t i = 0; i < BUFFER_LENGTH; i++){
|
||||||
|
buffer[i] = 128;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
effect++;
|
||||||
|
if(effect > TREMOLO) effect = REVERB;
|
||||||
|
buttonPressed = 1;
|
||||||
|
} else if(PIND & 0x10 && buttonPressed) buttonPressed = 0;
|
||||||
|
counterButton = counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
//obsługa przycisku od aktywacji efektu i diody sygnalizującej aktywację efektu
|
||||||
|
if(counter - counterButton2 >= _50MS){
|
||||||
|
if(!(PIND & 0x02) && !buttonPressed2){
|
||||||
|
if(effectOn){
|
||||||
|
effectOn = 0;
|
||||||
|
PORTB &= ~(1<<PORTB0);
|
||||||
|
} else {
|
||||||
|
effectOn = 1;
|
||||||
|
PORTB |= (1<<PORTB0);
|
||||||
|
}
|
||||||
|
buttonPressed2 = 1;
|
||||||
|
} else if(PIND & 0x02 && buttonPressed2) buttonPressed2 = 0;
|
||||||
|
counterButton2 = counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(counter - counterEncoder >= _20MS && !encoderServed){
|
||||||
|
if(encoderDir == 1){
|
||||||
|
if(effectSetting < 9) effectSetting++;
|
||||||
|
} else {
|
||||||
|
if(effectSetting > 1) effectSetting--;
|
||||||
|
}
|
||||||
|
counterEncoder = counter;
|
||||||
|
encoderServed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sampleReady){
|
||||||
|
if(effect < ECHO) buffer[bufferIndex] = adcVal; //zapisanie aktualnej próbki na najnowszą pozycję w buforze
|
||||||
|
//pod warunkiem że efekt to REVERB, CHORUS lub FLANGER
|
||||||
|
|
||||||
|
if(effect == TESTING){
|
||||||
|
valueToSend = adcVal;
|
||||||
|
PORTD &= ~((1<<PORTD7) | (1<<PORTD6) | (1<<PORTD5));
|
||||||
|
//PORTC &= ~(1<<PORTC5);
|
||||||
|
PORTC |= 1<<PORTC5;
|
||||||
|
|
||||||
|
} else if(effect == REVERB){
|
||||||
|
PORTC |= 1<<PORTC5;
|
||||||
|
|
||||||
|
valueToSend = reverb(buffer, bufferIndex, effectSetting);
|
||||||
|
PORTD |= (1<<PORTD5);
|
||||||
|
PORTD &= ~((1<<PORTD7) | (1<<PORTD6));
|
||||||
|
|
||||||
|
} else if(effect == CHORUS){
|
||||||
|
PORTC |= 1<<PORTC5;
|
||||||
|
|
||||||
|
valueToSend = chorusFlanger(buffer, bufferIndex, sine[sineIndex] + _40MS, 10 - effectSetting);
|
||||||
|
chorusCounter++;
|
||||||
|
if(chorusCounter >= 200){
|
||||||
|
if(chorusDirChange == 0){
|
||||||
|
sineIndex++;
|
||||||
|
if(sineIndex >= 100) chorusDirChange = 1;
|
||||||
|
} else {
|
||||||
|
sineIndex--;
|
||||||
|
if(sineIndex == 0) chorusDirChange = 0;
|
||||||
|
}
|
||||||
|
chorusCounter = 0;
|
||||||
|
}
|
||||||
|
PORTD |= (1<<PORTD6);
|
||||||
|
PORTD &= ~((1<<PORTD7) | (1<<PORTD5));
|
||||||
|
|
||||||
|
} else if(effect == FLANGER){
|
||||||
|
PORTC |= 1<<PORTC5;
|
||||||
|
|
||||||
|
valueToSend = chorusFlanger(buffer, bufferIndex, flangerDelayTime, 10 - effectSetting);
|
||||||
|
flangerCounter++;
|
||||||
|
if(flangerCounter >= 100){
|
||||||
|
if(flangerDirChange == 0){
|
||||||
|
flangerDelayTime++;
|
||||||
|
if(flangerDelayTime >= _10MS) flangerDirChange = 1;
|
||||||
|
} else {
|
||||||
|
flangerDelayTime--;
|
||||||
|
if(flangerDelayTime == _0MS) flangerDirChange = 0;
|
||||||
|
}
|
||||||
|
flangerCounter = 0;
|
||||||
|
}
|
||||||
|
PORTD |= (1<<PORTD5) | (1<<PORTD6);
|
||||||
|
PORTD &= ~(1<<PORTD7);
|
||||||
|
|
||||||
|
} else if(effect == ECHO){
|
||||||
|
PORTC |= 1<<PORTC5;
|
||||||
|
|
||||||
|
echoIndex = bufferIndex + (_16MS * effectSetting) + _41MS; //obliczenie miejsca zapisu próbki "na później"
|
||||||
|
if(echoIndex > BUFFER_LENGTH) echoIndex -= BUFFER_LENGTH;
|
||||||
|
buffer[echoIndex] = (adcVal - 128)/2 + 2*(buffer[bufferIndex] - 128)/3 + 128; // wpisanie z opóźnieniem i tłumieniem aktualnej wartości
|
||||||
|
valueToSend = buffer[bufferIndex];
|
||||||
|
|
||||||
|
PORTD |= (1<<PORTD7);
|
||||||
|
PORTD &= ~((1<<PORTD6) | (1<<PORTD5));
|
||||||
|
|
||||||
|
|
||||||
|
} else if (effect == DISTORTION){
|
||||||
|
if(effectOn){
|
||||||
|
PORTC &= ~(1<<PORTC5);
|
||||||
|
} else {
|
||||||
|
PORTC |= (1<<PORTC5);
|
||||||
|
}
|
||||||
|
|
||||||
|
valueToSend = distortion(164 - effectSetting*4, adcVal);
|
||||||
|
PORTD |= (1<<PORTD7) | (1<<PORTD5);
|
||||||
|
PORTD &= ~((1<<PORTD6));
|
||||||
|
|
||||||
|
} else if(effect == TREMOLO){
|
||||||
|
if(effectOn){
|
||||||
|
PORTC &= ~(1<<PORTC5);
|
||||||
|
} else {
|
||||||
|
PORTC |= (1<<PORTC5);
|
||||||
|
}
|
||||||
|
|
||||||
|
valueToSend = tremolo(adcVal, sine[sineIndex]);
|
||||||
|
tremoloCounter++;
|
||||||
|
if(tremoloCounter >= 1 + effectSetting){
|
||||||
|
if(tremoloDirChange == 0){
|
||||||
|
sineIndex++;
|
||||||
|
if(sineIndex >= 100) tremoloDirChange = 1;
|
||||||
|
} else {
|
||||||
|
sineIndex--;
|
||||||
|
if(sineIndex == 0) tremoloDirChange = 0;
|
||||||
|
}
|
||||||
|
tremoloCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PORTD |= (1<<PORTD7) | (1<<PORTD6);
|
||||||
|
PORTD &= ~((1<<PORTD5));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
effect = REVERB;
|
||||||
|
}
|
||||||
|
|
||||||
|
//implementacja przesterowania programowego
|
||||||
|
if(valueToSend > 255){
|
||||||
|
valueToSend = 255;
|
||||||
|
} else if(valueToSend < 0){
|
||||||
|
valueToSend = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (effectOn) {
|
||||||
|
analogWrite(valueToSend);
|
||||||
|
} else {
|
||||||
|
analogWrite(128);
|
||||||
|
}
|
||||||
|
|
||||||
|
sampleReady = 0;
|
||||||
|
|
||||||
|
//zmiana indeksu dla kolejnej próbki
|
||||||
|
bufferIndex++;
|
||||||
|
if(bufferIndex >= BUFFER_LENGTH) bufferIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Wykorzystana pamięć
|
||||||
|
|
||||||
|
//sampleReady = 1 B
|
||||||
|
//adcVal = 1 B
|
||||||
|
//effect = 1 B
|
||||||
|
//counter = 4 B
|
||||||
|
//sine = 101 B
|
||||||
|
//effectSetting = 1 B
|
||||||
|
//effectSettingVector = 9 B
|
||||||
|
//encoderLeft = 1 B
|
||||||
|
//encoderRight = 1 B
|
||||||
|
//encoderServed = 1 B
|
||||||
|
|
||||||
|
//valueToSend = 2 B
|
||||||
|
//bufor = 1851 B
|
||||||
|
//bufferIndex = 2 B
|
||||||
|
//counterButton1 = 4 B
|
||||||
|
//buttonPressed1 = 1 B
|
||||||
|
//counterButton2 = 4 B
|
||||||
|
//buttonPressed2 = 1 B
|
||||||
|
//effectOn = 1 B
|
||||||
|
|
||||||
|
//counterEncoder = 4 B
|
||||||
|
|
||||||
|
//chorusSineIndex = 1 B
|
||||||
|
//chorusCounter = 1 B
|
||||||
|
//chorusDirChange = 1 B
|
||||||
|
|
||||||
|
//flangerDelayTime = 1 B
|
||||||
|
//flangerCounter = 1 B
|
||||||
|
//flangerDirChange = 1 B
|
||||||
|
|
||||||
|
//echoIndex = 2 B
|
||||||
|
|
||||||
|
//14 zmiennych w reverbie
|
||||||
|
//echo#Index... = 14 B (7x2 B)
|
||||||
|
//echo#Temp... = 14 B (7x2 B)
|
||||||
|
|
||||||
|
//3 zmienne w chorusie/flangerze
|
||||||
|
//echoIndex = 2 B
|
||||||
|
//echoTemp = 2 B
|
||||||
|
|
||||||
|
//W najgorszym przypadku łącznie: 2031 B
|
||||||
|
//Pozostaje: (2048 - 2031) B = 17 B
|
63
spi.h
Normal file
63
spi.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
|
||||||
|
#define SS_LOW PORTB &= ~(1<<PORTB2)
|
||||||
|
#define SS_HIGH PORTB |= (1<<PORTB2)
|
||||||
|
|
||||||
|
//Jaki stan musi być na SS żeby DAC odbierał dane??
|
||||||
|
//musi być to stan niski (zarówno wg kursu jak i danycha katalogowych)
|
||||||
|
|
||||||
|
/*"CS is the Chip Select input pin, which requires an
|
||||||
|
active low to enable serial clock and data functions."*/
|
||||||
|
|
||||||
|
/*CPOL (polaryzacja) - mówi o tym jaki ma być stan zegara w bezczynności
|
||||||
|
W przypadku użytego DAC, w trybie 0,0 (Mode 0, 0), powinien być to stan niski, a więc CPOL = 0 */
|
||||||
|
|
||||||
|
/*CPHA (faza) - określa kiedy są odczytywane, a kiedy wystawiane bity na linii danych DAC.
|
||||||
|
Ponieważ bity są wystawiane na zboczu opadającym, to CPHA = CPOL = 0 (czyli DAC pracuje w trybie 0, 0)*/
|
||||||
|
|
||||||
|
/*W ogólności MCP4xxx wspierają tryb 0,0 i 1,1*/
|
||||||
|
|
||||||
|
/*Wg kursu inne piny odpowiadają za SPI niż w rzeczywistości (PB4, 5, 6, 7 zamiast PB2, 3, 4, 5)*/
|
||||||
|
|
||||||
|
//inicjalizacja
|
||||||
|
void spiInit(void) {
|
||||||
|
// /SS, MOSI, SCK jako wyjścia
|
||||||
|
DDRB |= (1<<PORTB2) | (1<<PORTB3) | (1<<PORTB5);
|
||||||
|
// /SS w stanie wysokim
|
||||||
|
SS_HIGH;
|
||||||
|
//SPI włączone, tryb master, podział przez 2 (najwyższa możliwa prędkość)
|
||||||
|
SPCR = (1<<SPE) | (1<<MSTR);
|
||||||
|
SPSR |= (1<<SPI2X);
|
||||||
|
}
|
||||||
|
|
||||||
|
//wysłanie jednego bajtu
|
||||||
|
/*uint8_t*/ void spiTransfer(uint8_t data) {
|
||||||
|
//rozpocznij transmisję
|
||||||
|
SPDR = data;
|
||||||
|
//poczekaj na koniec
|
||||||
|
while(!(SPSR & (1<<SPIF))); //wstrzymanie programu trwa do chwili zakończenia transmisji (flaga SPIF = 0 w rejestrze statusowym)
|
||||||
|
//możliwe jest też wywołanie przerwania w takim przypadku: można by zmieniać w nim własną flagę
|
||||||
|
//wysyłanie i tak następuje co 1600 cykli (f = 10 000 Hz), więc oczekiwanie raczej nie jest do niczego potrzebne
|
||||||
|
//BŁĄD!! Żeby wysłać jedna wartość do DAC wysyłane są dwa bajty jeden za drugim
|
||||||
|
//Czas jaki mija między zakończeniem wysyłki pierwszego i rozpoczęcia transmisji
|
||||||
|
//drugiego pakietu wynosi ok. 600 ns - ok. 10 cykli zegarowych (powinno wyjść dokładnie 10 * 62,5 ns = 625 ns).
|
||||||
|
//Można stworzyć dodatkową funkcję - wysyłającą drugi bajt bez czekania
|
||||||
|
//NIE DZIAŁA! Z jakiegoś powodu, wykorzystując taką funkcję wysyła się tylko pierwszy bajt
|
||||||
|
//Dzieje się tak, ponieważ natychmiast po przekazaniu danych do wysyłki następuje rozłaczenie (bit SS = 1)
|
||||||
|
//Aktywacja DAC SPI na stałe (SS = 0) nic nie daje. Nadal bez while'a, wysyłka drugiego bajtu nie następuje
|
||||||
|
//Obsługa przez przerwania prawdopodobnie byłaby nieopłacalna - więcej procesor musiałby się napracować niż marnuje czasu w while'u
|
||||||
|
//Zmiany stanu wyjscia SS są konieczne do poprawnej pracy przetwornika CA, stąd:
|
||||||
|
//- usunięcie while'a po pierwszym bajcie jest niemożliwe, bo natychmiast nastąpiłoby wprowadzanie
|
||||||
|
//kolejnych danych do rejestru SPDR,
|
||||||
|
//- usunięcie while'a po drugim bajcie jest niemożliwe, bo zanim nastąpiłaby wysyłka, doszłoby do
|
||||||
|
//podniesienia linii SS
|
||||||
|
|
||||||
|
//Cała wysyłka jednego bajtu trwa (1940 ns / 62,5 ns) ok. 31 cykli (czas kiedy SS = 0)
|
||||||
|
//Zanim zostanie wysłany pierwszy bit, mijają (1490 ns / 62,5 ns) ok. 24 cykle
|
||||||
|
//While kończy się zanim na MOSI kończy się wysyłka
|
||||||
|
//Przy wysyłaniu dwóch bajtów całość trwa dłużej (4640 ns / 62,5 ns): ok. 74 cykle
|
||||||
|
//W tym przypadku while kończy się po przekazaniu drugiego bajtu (470 ns / 62,5 ns): ok. 7,5 cykli
|
||||||
|
//zwróć odebraną wartość
|
||||||
|
//return SPDR;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user