Octo-phonic syntet (6 / 11 steg)
Steg 6: kod
OCTOSynth-0,2
//
Joe Marshall 2011
Resonant filtrera baserat på Meeblip (meeblip.noisepages.com)
Avbryta installationen koden baserat på koden av Martin Nawrath (http://interface.khm.de/index.php/lab/experiments/arduino-dds-sinewave-generator/)
oscillatorer och inline assembler optimering av mig.
//
tangentinmatning är från 8 kapacitiv ingångar på digital ingång 6,7 och analoga ingångar 0-6
varje ingång är en enda tråd, kommer att något metall röra
(Jag använde en massa stora vagnsbultar)
//
avkänning av detta sker genom getNoteKeys, med den metod som beskrivs på:
http://www.Arduino.cc/Playground/Code/CapacitiveSensor
//
Jag använder assembler med en upprullad loop med 16 register för att upptäcka detta
Detta gör saker mycket mer exakt än C slingan beskrivs på länken ovan
som vi mäter relevanta förseningen i enda processorcykler.
Det verkar vara nöjd även med batteridrift, upptäcka upp till 8 samtidiga
berör.
Vågorna är alla definierade högst upp, eftersom vi tvingar dem att anpassa till 256 byte gränser
Detta gör oscillatorn koden snabbare (som beräkningen av en våg offset är bara
en fråga för att ersätta den låga byten av adressen).
Med detta sagt, andra arduino saker förmodligen får lastas här först
eftersom attributet arrangera i rak linje verkar att lägga till ett par hundra byte till koden
#define TEST_PATTERN_INTRO
#define FILTER_LPF_NONE
#define FILTER_LPF_HACK
tabell med 256 sine värden / en sinus period / lagras i flashminne
char sine256 [256] __attribute__ ((aligned(256))) = {
0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45,
48, 51, 54, 57, 59, 62, 65, 67, 70, 73, 75, 78, 80, 82, 85, 87,
89, 91, 94, 96, 98, 100, 102, 103, 105, 107, 108, 110, 112, 113, 114, 116,
117, 118, 119, 120, 121, 122, 123, 123, 124, 125, 125, 126, 126, 126, 126, 126,
127, 126, 126, 126, 126, 126, 125, 125, 124, 123, 123, 122, 121, 120, 119, 118,
117, 116, 114, 113, 112, 110, 108, 107, 105, 103, 102, 100, 98, 96, 94, 91,
89 87, 85, 82, 80, 78, 75, 73, 70, 67, 65, 62, 59, 57, 54, 51,
48, 45, 42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3,
0 -3, -6, -9, -12, -15, -18, -21, -24, -27, -30, -33,-36, -39,-42, -45,
-48,-51, -54,-57,-59,-62,-65,-67, -70,-73,-75, -78,-80,-82,-85,-87,
-89,-91, -94, -96, -98, -100,-102,-103,-105,-107,-108,-110,-112,-113,-114,-116,
-117,-118,-119, -120,-121,-122,-123,-123,-124,-125,-125,-126,-126,-126,-126,-126,
-127,-126,-126,-126,-126,-126,-125,-125,-124,-123,-123,-122,-121, -120,-119,-118,
-117,-116,-114,-113,-112,-110,-108,-107,-105,-103,-102, -100, -98, -96, -94,-91,
-89,-87,-85,-82,-80, -78,-75,-73, -70,-67,-65,-62,-59,-57, -54,-51,
-48, -45,-42, -39,-36, -33, -30, -27, -24, -21, -18, -15, -12, -9, -6, -3
};
char square256 [256] __attribute__ ((aligned(256))) = {
127 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,
-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,
-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,
-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,
-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,
-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,
-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,
-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127
};
char triangle256 [256] __attribute__ ((aligned(256))) = {
-127,-125,-123,-121,-119,-117,-115,-113,-111,-109,-107,-105,-103,-101, -99,-97,
-95,-93,-91, -89,-87,-85,-83,-81,-79,-77,-75,-73,-71,-69,-67,-65,
-63,-61,-59,-57, -55, -53,-51,-49,-47, -45,-43,-41, -39,-37,-35, -33,
-31 -29, -27, -25,-23, -21, -19, -17, -15, -13, -11, -9, -7, -5, -3, -1,
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31,
33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63,
65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95,
97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127,
129, 127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107, 105, 103, 101, 99,
97 95, 93, 91, 89, 87, 85, 83, 81, 79, 77, 75, 73, 71, 69, 67,
65 63, 61, 59, 57, 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, 35,
33, 31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3,
1 -1, -3, -5, -7, -9, -11, -13, -15, -17, -19, -21,-23, -25, -27, -29,
-31 -33,-35,-37, -39,-41,-43, -45,-47,-49,-51, -53, -55,-57,-59,-61,
-63,-65,-67,-69,-71,-73,-75,-77,-79,-81,-83,-85,-87, -89,-91,-93,
-95,-97, -99,-101,-103,-105,-107,-109,-111,-113,-115,-117,-119,-121,-123,-125
};
char sawtooth256 [256] __attribute__ ((aligned(256))) = {
-127,-127,-126,-125,-124,-123,-122,-121, -120,-119,-118,-117,-116,-115,-114,-113,
-112,-111,-110,-109,-108,-107,-106,-105,-104,-103,-102,-101, -100, -99, -98,-97,
-96, -95, -94,-93,-92,-91, -90, -89,-88,-87,-86,-85, -84,-83,-82,-81,
-80,-79, -78,-77,-76,-75, -74,-73, -72,-71, -70,-69, -68,-67,-66,-65,
-64,-63,-62,-61,-60,-59,-58,-57, -56, -55, -54, -53,-52,-51, -50,-49,
-48,-47,-46, -45,-44,-43,-42,-41, -40, -39, -38,-37,-36,-35,-34, -33,
-32,-31, -30, -29,-28, -27,-26, -25, -24,-23, -22, -21, -20, -19, -18, -17,
-16 -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127
};
#include "avr/pgmspace.h"
loggtabell för 128 filter cutoffs
unsigned char logCutoffs[128] = {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x03,0x04,0x04,0x04,0x04,0x04,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x08,0x08,0x08,0x09,0x09,0x0A,0x0A,0x0A,0x0A,0x0B ,0x0C,0x0C,0x0C,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1E,0x20,0x21,0x22,0x23,0x24,0x26,0x28,0x2A,0x2C,0x2E,0x30,0x32,0x34,0x36,0x38,0x3A,0x40,0x42,0x44,0x48,0x4C,0x4F,0x52,0x55,0x58,0x5D,0x61,0x65,0x68,0x6C,0x70,0x76,0x7E,0x85,0x8A,0x90,0x96,0x9D,0xA4 0xAB, 0xB0, 0xBA, 0xC4, 0xCE, 0xD8, 0xE0, 0xE8, 0xF4, 0xFF};
flyktiga unsigned int WAIT_curTime;
#define WAIT_UNTIL_INTERRUPT() WAIT_curTime = loopSteps; While(WAIT_curTime==loopSteps) {}
#define SERIAL_OUT 0
attack, decay är 1/64ths per 125th av en sekund - dvs. 1 = 0 - > 1 i en halv sekund
CONST int DECAY = 3;
CONST int ATTACK = 4;
flyktiga char * curWave = square256;
#define cbi (sfr, lite) (_SFR_BYTE(sfr) & = ~_BV(bit))
#define sbi (sfr, lite) (_SFR_BYTE(sfr) | = _BV(bit))
Detta är förmodligen den audio klockfrekvensen - som
Du kan se, uppmätta freq kan variera lite från förmodade klockfrekvens
Jag är inte helt säker på varför
CONST double refclk = 31372.549; = 16MHz / 510
CONST double refclk = 31376.6; uppmätt
variabler som används inuti avbryta tjänsten som voilatile
dessa variabler tillåt du till hålla spår tid - som fördröjning / millis etc. är
gjorde inaktiv på grund av avbrott att inaktiveras.
volatile unsigned char loopSteps = 0; en gång per prov
volatile unsigned int loopStepsHigh = 0; en gång per 256 prover
information om det aktuella läget för en enda oscillator
struct oscillatorPhase
{
unsigned int phaseStep;
char volym;
unsigned int phaseAccu;
};
oscillatorerna (8 av dem)
struct oscillatorPhase oscillatorer [8].
tword_m = pow (2,32) * dfreq/refclk; calulate DDS nya tuning word
för att få hz -> trim ord: (pow(2,16) * frekvens) / 31376.6
CONST unsigned int NOTE_FREQS [25] = {273,289,307,325,344,365,386,409,434,460,487,516,546,579,613,650,688,729,773,819,867,919,974,1032,1093}.
tröskelvärden för kapacitiv avkänning knapparna
int calibrationThresholds [8] = {0,0,0,0,0,0,0,0}.
inline int getNoteKeys (boolean kalibrera = false)
{
char PORTD_PINS = 0b11000000; (stift 6-7 - Undvik pins 0,1 eftersom de används för seriell port comms)
char PORTC_PINS = 0b111111; (analog stift 0-5)
CONST int MAX_LOOPS = 16.
char port_values [MAX_LOOPS * 2];
WAIT_UNTIL_INTERRUPT();
ASM flyktiga)
Port D behandlingen loop:
DDRD & = ~(PORTD_PINS = 0x3f); ställa in stift 8-12 till insatsen läge
"i % [temp], 0x0a" "\n\t"
"andi % [temp], 0x3f" "\n\t"
"ut 0x0a, % [temp]" "\n\t"
PORTD | = (PORTD_PINS); ställa in stift 8-12 pullup på
"i % [temp], 0x0b" "\n\t"
"ori % [temp], 0xC0" "\n\t"
"ut 0x0b, % [temp]" "\n\t"
"i %0, 0x09" "\n\t"
"i %1, 0x09" "\n\t"
"i %2, 0x09" "\n\t"
"i %3, 0x09" "\n\t"
"i %4, 0x09" "\n\t"
"i 5 %, 0x09" "\n\t"
"i 6 %, 0x09" "\n\t"
"i %7, 0x09" "\n\t"
"i 8 %, 0x09" "\n\t"
"i 9 %, 0x09" "\n\t"
"i % 10, 0x09" "\n\t"
"i % 11, 0x09" "\n\t"
"i % 12, 0x09" "\n\t"
"i % 13, 0x09" "\n\t"
"i % 14, 0x09" "\n\t"
"i % 15, 0x09" "\n\t"
:
utgångar
"= r" (port_values[0]),
"= r" (port_values[2]),
"= r" (port_values[4]),
"= r" (port_values[6]),
"= r" (port_values[8]),
"= r" (port_values[10]),
"= r" (port_values[12]),
"= r" (port_values[14]),
"= r" (port_values[16]),
"= r" (port_values[18]),
"= r" (port_values[20]),
"= r" (port_values[22]),
"= r" (port_values[24]),
"= r" (port_values[26]),
"= r" (port_values[28]),
"= r" (port_values[30])
: [temp] "d" (0));
WAIT_UNTIL_INTERRUPT();
ASM flyktiga)
Port C behandlingen loop:
DDRC & = ~(PORTC_PINS = 0xc0); ställa in stift 5-7 att mata in läge
"i % [temp], 0x07" "\n\t"
"andi % [temp], 0xc0" "\n\t"
"ut 0x07, % [temp]" "\n\t"
PORTC | = (PORTC_PINS); ställa in stift 5-7 pullup på
"i % [temp], 0x08" "\n\t"
"ori % [temp], 0x3F" "\n\t"
"ut 0x08, % [temp]" "\n\t"
"i %0, 0x06" "\n\t"
"i %1, 0x06"\n\t"
"i %2, 0x06"\n\t"
"i %3, 0x06" "\n\t"
"i %4, 0x06" "\n\t"
"i %5 0x06" "\n\t"
"i 6 %, 0x06" "\n\t"
"i %7, 0x06" "\n\t"
"i 8 %, 0x06" "\n\t"
"i 9 %, 0x06" "\n\t"
"i % 10, 0x06" "\n\t"
"i % 11, 0x06" "\n\t"
"i % 12, 0x06" "\n\t"
"i % 13, 0x06" "\n\t"
"i % 14, 0x06" "\n\t"
"i % 15, 0x06" "\n\t"
:
utgångar
"= r" (port_values[1]),
"= r" (port_values[3]),
"= r" (port_values[5]),
"= r" (port_values[7]),
"= r" (port_values[9]),
"= r" (port_values[11]),
"= r" (port_values[13]),
"= r" (port_values[15]),
"= r" (port_values[17]),
"= r" (port_values[19]),
"= r" (port_values[21]),
"= r" (port_values[23]),
"= r" (port_values[25]),
"= r" (port_values[27]),
"= r" (port_values[29]),
"= r" (port_values[31])
: [temp] "d" (0));
PORTC & = ~ (PORTC_PINS); pullup av stift 8-12
PORTD & = ~ (PORTD_PINS); pullup av stift 5-7
DDRC | = (PORTC_PINS); ansvarsfrihet
DDRD | = (PORTD_PINS); ansvarsfrihet
IF(Calibrate)
{
för (int c = 0; c < 8; c ++)
{
för (int d = 0; d < MAX_LOOPS; d ++)
{
int liveNotes=((int*)port_values) [d];
liveNotes & = 0x3fc0;
liveNotes >> = 6;
om (liveNotes & (1 << c))
{
om (calibrationThresholds [c] < = d)
{
calibrationThresholds [c] = d + 1;
}
bryta;
}
}
}
}
int liveNotes = 0;
för (int c = 0; c < 8; c ++)
{
int val = ((int*) port_values) [calibrationThresholds [c] + 1];
Val & = 0x3fc0;
Val >> = 6;
om ((val & (1 << c)) == 0)
{
liveNotes| = (1 << c);
}
}
återvända liveNotes;
}
få kapacitiv touch på ingång 4 och utgång 3
används för filter modulator
inline int getfiltermodulationtime()
{
statisk int running_average = 0;
statisk int running_min = 1024;
statisk int running_min_inc_count = 0;
statisk boolean initialise_running_min = sant;
unsigned int fördröjningstid = 0;
char PINNUM_OUT = 3;
char PINNUM_IN = 4;
char PIN_OUT = 1 << PINNUM_OUT;
char PIN_IN = 1 << PINNUM_IN;
göra säker ingångar / utgångar är sätta rätt
DDRD| = PIN_OUT;
DDRD & = ~ (PIN_IN);
WAIT_UNTIL_INTERRUPT();
PORTD| = PIN_OUT;
ASM flyktiga)
"loopstart % =:" "\n\t"
"sbic 0x09, % [PINNUM_IN]" "\n\t"
"rjmp outloop % =" "\n\t"
"adiw % [fördröjningstid], 0x01" "\n\t"
"cpi %B [fördröjningstid], 0x02" "\n\t"
"brne loopstart % =" "\n\t"
"outloop % =:" "\n\t"
: [fördröjningstid] "+ & w" (fördröjningstid)
: [PINNUM_IN] "I" (PINNUM_IN));
ställa in pin - kanske inte bryr sig timing, om det inte verkar lägga till
mycket noggrannhet?
WAIT_UNTIL_INTERRUPT();
PORTD & = ~ PIN_OUT;
ASM)
"loopstart % =:" "\n\t"
"sbis 0x09, % [PINNUM_IN]" "\n\t"
"rjmp outloop % =" "\n\t"
"adiw % [fördröjningstid], 0x01" "\n\t"
"cpi %B [fördröjningstid], 0x02" "\n\t"
"brne loopstart % =" "\n\t"
"outloop % =:" "\n\t"
: [fördröjningstid] "+ & w" (fördröjningstid)
: [PINNUM_IN] "I" (PINNUM_IN));
running_average = (running_average-(running_average >> 4)) + (fördröjningstid >> 4);
running_min_inc_count ++;
IF(running_min_inc_count==255)
{
IF(initialise_running_min)
{
running_min = running_average;
running_min_inc_count = 0;
initialise_running_min = false;
} annat {
running_min_inc_count = 0;
running_min ++;
}
}
IF(running_average<running_min)
{
running_min = running_average;
}
int touchVal = running_average-running_min;
IF(touchVal>15)
{
touchVal-= 15.
IF(touchVal>99)
{
touchVal = 99.
}
} annat {
touchVal = 0;
}
återvända touchVal;
}
få kapacitiv touch input 5 och utgång 3
används för pitch bend
inline int getpitchbendtime()
{
statisk int running_average = 0;
statisk int running_min = 1024;
statisk int running_min_inc_count = 0;
statisk boolean initialise_running_min = sant;
unsigned int fördröjningstid = 0;
char PINNUM_OUT = 3;
char PINNUM_IN = 5;
char PIN_OUT = 1 << PINNUM_OUT;
char PIN_IN = 1 << PINNUM_IN;
göra säker ingångar / utgångar är sätta rätt
DDRD| = PIN_OUT;
DDRD & = ~ (PIN_IN);
WAIT_UNTIL_INTERRUPT();
PORTD| = PIN_OUT;
ASM flyktiga)
"loopstart % =:" "\n\t"
"sbic 0x09, % [PINNUM_IN]" "\n\t"
"rjmp outloop % =" "\n\t"
"adiw % [fördröjningstid], 0x01" "\n\t"
"cpi %B [fördröjningstid], 0x02" "\n\t"
"brne loopstart % =" "\n\t"
"outloop % =:" "\n\t"
: [fördröjningstid] "+ & w" (fördröjningstid)
: [PINNUM_IN] "I" (PINNUM_IN));
ställa in pin - kanske inte bryr sig timing, om det inte verkar lägga till
mycket noggrannhet?
WAIT_UNTIL_INTERRUPT();
PORTD & = ~ PIN_OUT;
ASM)
"loopstart % =:" "\n\t"
"sbis 0x09, % [PINNUM_IN]" "\n\t"
"rjmp outloop % =" "\n\t"
"adiw % [fördröjningstid], 0x01" "\n\t"
"cpi %B [fördröjningstid], 0x02" "\n\t"
"brne loopstart % =" "\n\t"
"outloop % =:" "\n\t"
: [fördröjningstid] "+ & w" (fördröjningstid)
: [PINNUM_IN] "I" (PINNUM_IN));
running_average = (running_average-(running_average >> 4)) + (fördröjningstid >> 4);
running_min_inc_count ++;
IF(running_min_inc_count==255)
{
IF(initialise_running_min)
{
running_min = running_average;
running_min_inc_count = 0;
initialise_running_min = false;
} annat {
running_min_inc_count = 0;
running_min ++;
}
}
IF(running_average<running_min)
{
running_min = running_average;
}
int touchVal = running_average-running_min;
IF(touchVal>15)
{
touchVal-= 15.
IF(touchVal>99)
{
touchVal = 99.
}
} annat {
touchVal = 0;
}
återvända touchVal;
}
unsigned int pitchBendTable [201] = {241, 241, 241, 242, 242, 242, 242, 242, 242, 242, 243, 243, 243, 243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 245, 245, 245, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247, 247, 247, 247, 248, 248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 249 , 249, 249, 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 256,
256,256, 256, 256, 256, 256, 256, 256, 257, 257, 257, 257, 257, 257, 257, 258, 258, 258, 258, 258, 258, 259, 259, 259, 259, 259, 259, 259, 260, 260, 260, 260, 260, 260, 260, 261, 261, 261, 261, 261, 261, 262, 262, 262, 262, 262, 262, 262, 263, 263, 263, 263, 263, 263, 264, 264, 264, 264, 264, 264, 264, 265 265, 265, 265, 265, 265, 266, 266, 266, 266, 266, 266, 266, 267, 267, 267, 267, 267, 267, 268, 268, 268, 268, 268, 268, 269, 269, 269, 269, 269, 269, 269, 270, 270, 270, 270, 270, 270, 271, 271};
void setupNoteFrequencies (int baseNote, int pitchBendVal / * -100 -> 100 * /)
{
oscillatorer [0] .phaseStep = NOTE_FREQS [baseNote];
oscillatorer [1] .phaseStep = NOTE_FREQS [baseNote + 2];
oscillatorer [2] .phaseStep = NOTE_FREQS [baseNote + 4];
oscillatorer [3] .phaseStep = NOTE_FREQS [baseNote + 5];
oscillatorer [4] .phaseStep = NOTE_FREQS [baseNote + 7];
oscillatorer [5] .phaseStep = NOTE_FREQS [baseNote + 9];
oscillatorer [6] .phaseStep = NOTE_FREQS [baseNote + 11];
oscillatorer [7] .phaseStep = NOTE_FREQS [baseNote + 12];
om (pitchBendVal < -99)
{
pitchBendVal =-99;
} annat if(pitchBendVal>99)
{
pitchBendVal = 99.
}
Serial.Print("*");
Serial.Print(pitchBendVal);
unsigned int pitchBendMultiplier = pitchBendTable [pitchBendVal + 100];
Serial.Print(":");
Serial.Print(pitchBendMultiplier);
för (int c = 0; c < 8; c ++)
{
multiplicera 2 16-bitars nummer tillsammans och SKIFT 8 utan precision förlust
kräver assembler verkligen
volatile unsigned char zeroReg = 0;
volatile unsigned int multipliedCounter = oscillatorer [c] .phaseStep;
ASM flyktiga
(
hög byte mult tillsammans = övre byte
"ldi %A [outVal], 0" "\n\t"
"mul %B [phaseStep], %B [pitchBend]" "\n\t"
"mov %B [outVal], r0" "\n\t"
Ignorera overflow i r1 (bör aldrig overflow)
låga byte * övre byte -> båda byte
"mul %A [phaseStep], %B [pitchBend]" "\n\t"
"Lägg till %A [outVal], r0" "\n\t"
bära in övre byte
"adc %B [outVal], r1" "\n\t"
hög byte * låg byte -> båda byte
"mul %B [phaseStep], administrationskostnader [pitchBend]" "\n\t"
"Lägg till %A [outVal], r0" "\n\t"
bära in övre byte
"adc %B [outVal], r1" "\n\t"
låga byte * låg byte -> runda
"mul %A [phaseStep], administrationskostnader [pitchBend]" "\n\t"
adc nedan är att runda upp baserat på hög bithastighet för low * låg:
"adc %A [outVal], r1" "\n\t"
"adc %B [outVal] % [noll]" "\n\t"
"clr r1" "\n\t"
: [outVal] "= & d" (multipliedCounter)
: [phaseStep] "d" (oscillatorer [c] .phaseStep), [pitchBend] "d" (pitchBendMultiplier), [noll] "d" (zeroReg)
: "r1", "r0"
);
oscillatorer [c] .phaseStep = multipliedCounter;
}
Serial.Print(":");
Serial.Print(NOTE_FREQS[baseNote]);
Serial.Print(":");
Serial.println(oscillators[0].phaseStep);
}
void setup()
{
Serial.BEGIN(9600); ansluta till den seriella porten
#ifndef FILTER_LPF_NONE
setFilter (127, 0);
#endif
pinMode (11, OUTPUT); pin11 = PWM-utgång / frekvens output
setupNoteFrequencies(12,0);
för (int c = 0; c < 8; c ++)
{
oscillatorer [c] .volume = 0;
}
Setup_timer2();
Inaktivera avbrott för att undvika timing distorsion
CBI (TIMSK0, TOIE0); Inaktivera Timer0!!! Delay() finns nu inte
SBI (TIMSK2, TOIE2); Aktivera Timer2 avbryta
kalibrera de Kolfiberförstärkt nyckelvärdena
för (int x = 0; x < 1024; x ++)
{
getNoteKeys(true);
int steg = loopSteps;
WAIT_UNTIL_INTERRUPT();
int afterSteps = loopSteps;
Serial.println(afterSteps-Steps);
}
testmönster intro
#ifdef TEST_PATTERN_INTRO
int filtValue = 255;
byte notes[]={0x1,0x4,0x10,0x80,0x80,0x80,0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1,0x1,0x1,0x00,0x00,0x1,0x1,0x1,0x1,0x00,0x00,0x5,0x5,0x5,0x5,0x00,0x00,0x15,0x15,0x15,0x15,0x15,0x00,0x00,0x95,0x95,0x95,0x95,0x95,0x95,0x00};
för (int Obs = 0; Observera < sizeof(notes)/sizeof(byte);note++)
{
int noteCount = 0;
för (int c = 0; c < 8; c ++)
{
om (anteckningar [not] & (1 << c))
{
noteCount + = 1;
}
}
för (int c = 0; c < 8; c ++)
{
om (anteckningar [not] & (1 << c))
{
oscillatorer [c] .volume = 63/noteCount;
} annat
{
oscillatorer [c] .volume = 0;
}
}
för (int c = 0; c < 50, c ++)
{
kan också hålla kalibrera här
NB: varje kalibrering slinga = minst 1 avbrott
getNoteKeys(true);
#ifndef FILTER_LPF_NONE
setFilter (127-c, 64);
#endif
}
}
#else
bara ett pip om du vill visa kalibreringen sker
oscillatorer [0] .volume = 63.
för (int c = 0; c < 20; c ++)
{
WAIT_UNTIL_INTERRUPT();
}
oscillatorer [0] .volume = 63.
#endif
Serial.println("Calibrations:");
för (int c = 0; c < 8; c ++)
{
Serial.Print(c);
Serial.Print(":");
Serial.println(calibrationThresholds[c]);
}
}
void loop()
{
Vi håller en lista över "raw" volymer - och sänk volymen om ett ackord tar > 64 volym total
Detta är att låta chording utan att minska volymen av enstaka anteckningar
int rawVolumes [8] = {0,0,0,0,0,0,0,0}.
int curNote = 0;
unsigned int filterSweep = 64;
CONST int MIN_SWEEP = 64;
CONST int MAX_SWEEP = 127;
CONST int SWEEP_SPEED = 3;
int sweepDir = SWEEP_SPEED;
unsigned int lastStep = loopStepsHigh;
osignerade curStep = loopStepsHigh;
While(1)
{
lastStep = curStep;
curStep = loopStepsHigh;
Obs: timer fungerar inte i den här koden (avbryter inaktiverat / hastigheter förändrats), så inte ens tänka på kallelse: delay(), millis / micros etc.
varje loopstep är ungefär 31250 / sekund
denna huvudloop kommer få kallas en gång varje 3 eller 4 prover om den seriella produktionen är vände bort, kanske långsammare annars
int liveNotes=getNoteKeys();
Vi är rätt efter ett avbrott (som loopStep har bara ökats)
så vi bör ha tillräckligt med tid att göra de capacitative viktiga kontrollerna
IF(lastStep!=curStep)
{
int totalVolume = 0;
för (int c = 0; c < 8; c ++)
{
om ((liveNotes & (1 << c)) == 0)
{
rawVolumes [c]-= DECAY*(curStep-lastStep);
om (rawVolumes [c] < 0) rawVolumes [c] = 0;
IF(SERIAL_OUT)Serial.Print(".");
}
annat
{
rawVolumes [c] += ATTACK*(curStep-lastStep);
om (rawVolumes [c] > 63) rawVolumes [c] = 63.
IF(SERIAL_OUT)Serial.Print(c);
}
totalVolume += rawVolumes [c];
}
WAIT_UNTIL_INTERRUPT();
om (totalVolume < 64)
{
för (int c = 0; c < 8; c ++)
{
oscillatorer [c] .volume = rawVolumes [c];
}
} annat
{
totala volymen för mycket, förminska för att undvika klippning
för (int c = 0; c < 8; c ++)
{
oscillatorer [c] .volume =(rawVolumes[c]*63)/totalVolume;
}
}
}
IF(SERIAL_OUT)Serial.println("");
#ifndef FILTER_LPF_NONE
/ * if(liveNotes==0)
{
filterSweep = 64;
sweepDir = SWEEP_SPEED;
}
filterSweep += sweepDir;
om (filterSweep > = MAX_SWEEP)
{
filterSweep = MAX_SWEEP;
sweepDir =-sweepDir;
}
annars om (filterSweep < = MIN_SWEEP)
{
sweepDir =-sweepDir;
filterSweep = MIN_SWEEP;
}*/
Serial.println((int)filterValue);
filterSweep=127-(getpitchbendtime() >> 1);
WAIT_UNTIL_INTERRUPT();
setFilter(150-(getfiltermodulationtime()),220);
#endif
WAIT_UNTIL_INTERRUPT();
setupNoteFrequencies(12,-getpitchbendtime());
Vi är rätt efter ett avbrott igen (som loopStep har bara ökats)
så vi bör ha tillräckligt med tid att kolla pitch bend kapacitans utan att gå över ett annat prov, är timing ganska viktigt här
måste balansera med ett tillräckligt stort motstånd för att få anständigt fjärranalys avstånd med tar för lång tid att prova
Kolla pitch bend indata
}
}
//******************************************************************
timer2 inställningar
Ställ in prscaler på 1, PWM läge att gradvis rätt PWM, 16000000/510 = 31372.55 Hz klocka
void Setup_timer2() {
Timer2 klocka Prescaler till: 1
SBI (TCCR2B, CS20);
CBI (TCCR2B, CS21);
CBI (TCCR2B, CS22);
Timer2 inställt PWM på fas rätt PWM
CBI (TCCR2A, COM2A0); Rensa jämför Match
SBI (TCCR2A, COM2A1);
SBI (TCCR2A, WGM20); Läge 1 / fas rätt PWM
CBI (TCCR2A, WGM21);
CBI (TCCR2B, WGM22);
}
#ifdef FILTER_LPF_BIQUAD
char filtValueA1 = 0, filtValueA2 = 0, filtValueA3 = 0, filtValueB1 = 0, filtValueB2 = 0;
volatile unsigned char filtCoeffA1 = 255;
flyktiga char filtCoeffB1 = 127;
volatile unsigned char filtCoeffB2 = 255;
#endif
#ifdef FILTER_LPF_HACK
hackade lågpassfilter - 2 polig resonant-
en += f*((in-a) + q*(a-b)
b + = f * (a-b)
int filterA = 0;
int filterB = 0;
unsigned char filterQ = 0;
unsigned char filterF = 255;
inline void setFilterRaw (unsigned char filterF, unsigned char resonans)
{
unsigned char tempReg = 0, tempReg2 = 0;
ASM flyktiga ("ldi % [tempReg], 0xff" "\n\t"
"sub % [tempReg], [filtF]" "\n\t"
"lsr % [tempReg]" "\n\t"
"ldi % [tempReg2], 0x04" "\n\t"
"Lägg % [tempReg], [tempReg2]" "\n\t"
"sub % [reso], [tempReg]" "\n\t"
"brcc Res_Overflow % =" "\n\t"
"ldi % [reso], 0x00" "\n\t"
"Res_Overflow % =:" "\n\t"
"mov % [filtQ], [reso]" "\n\t"
: [tempReg] "= & d" (tempReg), [tempReg2] "= & d" (tempReg2), [filtQ] "= & d" (filterQ): [reso] "d" (resonans), [filtF] "d" (filterF));
}
inline void setFilter (unsigned char f, unsigned char resonans)
{
IF(f>127) f = 127;
filterF = logCutoffs [f];
setFilterRaw(filterF,resonance);
}
#endif
#define HIBYTE(__x) ((char) (((unsigned int) __x) >> 8))
#define LOBYTE(__x) ((char) (((unsigned int) __x) & 0xff))
oscillator huvudloop (öka wavetable pekaren och lägga det till register som utdata)
13 instruktioner - bör ta 14 processorcykler enligt databladet
i teorin tror jag att detta innebär att varje oscillator bör ta 1,5% av cpu
(plus en konstant overhead för avbrott kallar etc.)
Obs: detta brukade göra alla stepvolume laddar nära början, men de är nu interleaved i den
kod, detta beror på att ldd (load med offset) tar 2 instruktioner,
kontra ld, + 1 (load med post ökning) och st, + 1 som är 1 instruktion - kan vi göra detta eftersom:
//
en) steg (som inte behöver lagras tillbaka) är i minnet innan den
fasen ackumulator (som behöver lagras tillbaka när steget läggs
//
b) fas assumulator lagras i låg byte, hög byteordningen, menande att vi
kan lägga till första byte tillsammans, sedan lagra det byte uppräkning pekaren,
sedan ladda den höga byten, lägga till hög byte tillsammans och lagra uppräkning pekaren
//
Jag tror detta är det minsta antalet operationer möjligt att koda detta oscillator i, eftersom
1) det finns 6 belastning som krävs (att läsa in stepHigh/låg, phaseH/L, volym och värde från vågen)
2) det är 2 lägga till operationer som krävs för att lägga till fas ackumulatorn
3) finns det 2 butik åtgärder krävs för att spara fas ackumulatorn
Är 4) där 1 multiplicera (2 instruktion cykler) krävs för att göra volymen
5) finns det 2 lägga till operationer som krävs för att lägga till i den slutliga utmatningen
//
6 + 2 + 2 + 2 + 2 = 14 instruktion cykler
#define OSCILLATOR_ASM \
/ * Ladda fas steg och volym * / \
"ld %A [tempStep], % en [stepVolume] +" "\n\t" \
"ld %B [tempStep], % en [stepVolume] +" "\n\t" \
"ld % [tempVolume], [stepVolume] +" "\n\t" \
/ * belastning fasen ackumulator - övre byte går rak * / \
/ * i våg lookup vektorn (wave är på 256 byte gräns * / \
/ * så vi kan göra detta utan att någon lägger * / \
/ * Fasen läggs mellan de två lasterna, som laddar med offset är långsammare än
bara en normal belastning
*/\
"ld %A [tempPhaseLow], % en [stepVolume]" "\n\t" \
/ * Lägg till fas steg låg * / \
"Lägg % [tempPhaseLow], %A [tempStep]" "\n\t"\
/ * lagra fas ackumulator låg * / \
"st %a [stepVolume] + % [tempPhaseLow]" "\n\t" \
/ * Ladda fas ackumulator hög * / \
"ld %A [waveBase], % en [stepVolume]" "\n\t" \
/ * lägga till fas steg höga - med bär från Lägg till ovan * / \
"adc %A [waveBase], %B [tempStep]" "\n\t"\
/ * lagra fas steg hög * / \
"st %a [stepVolume] + %A [waveBase]" "\n\t" \
/ * nu sökning från våg - övre byte = våg pekare, låg byte = offset * / \
"ld % [tempPhaseLow], [waveBase]" "\n\t" \
/ * nu multiplicera med volym * / \
"muls % [tempPhaseLow], [tempVolume]" "\n\t" \
/ * r0 innehåller nu ett prov - Lägg till det att mata värde * / \
"Lägg till %A [outValue], r0" "\n\t" \
"adc %B [outValue], r1" "\n\t" \
/ * gå till nästa oscillator - stepVolume pekar på nästa * / \
/ * oscillatorn redan * / \
//******************************************************************
Timer2 avbryta tjänsten på 31372,550 KHz = 32uSec
Detta är timebase REFCLOCK för DDS generator
FOUT = (M (REFCLK)) / (2 exp 32)
runtime:?
ISR(TIMER2_OVF_vect) {
nu ställa in nästa värde
denna slinga tar ungefär 172 cykler (214 inklusive de push/pop) - vi har 510, så ungefär 50% av processor kommer reservdelar för icke-audio uppgifter
lågpass filtret tar även några cykler
int outValue;
Tips:
X = oscillator fas ackumulator
Y = oscillator steg och volym
Z = våg pos - lägga till om du vill basera
int tempStep = 0;
char tempPhaseLow = 0, tempVolume = 0;
int tempWaveBase = 0;
ASM flyktiga)
"ldi %A [outValue], 0" "\n\t"
"ldi %B [outValue], 0" "\n\t"
oscillator 0
avkommentera koden nedan för att kontrollera
att registren inte får dubbel tilldelade
/ * "lds %A [outValue], 0x00" "\n\t"
"lds %B [outValue], 0x01" "\n\t"
"lds %A [tempPhaseLow], 0x02" "\n\t"
"lds %B [tempPhase], 0x03" "\n\t"
"lds %A [tempStep], 0x04" "\n\t"
"lds %B [tempStep], 0x05" "\n\t"
"lds % [tempVolume], 0x06" "\n\t"
"lds % [noll], 0x07" "\n\t"
"lds %A [tempWaveBase], 0x08" "\n\t"
"lds %B [tempWaveBase], 0x09" "\n\t"
"lds %A [phaseAccu], 0x0a" "\n\t"
"lds %B [phaseAccu], 0x0b" "\n\t"
"lds %A [stepVolume], 0x0c" "\n\t"
"lds %B [stepVolume], 0x0d" "\n\t"
"lds %A [waveBase], 0x0e" "\n\t"
"lds %B [waveBase], 0x0f" "\n\t"*/
OSCILLATOR_ASM
OSCILLATOR_ASM
OSCILLATOR_ASM
OSCILLATOR_ASM
OSCILLATOR_ASM
OSCILLATOR_ASM
OSCILLATOR_ASM
OSCILLATOR_ASM
:
utgångar
[tempPhaseLow] "= & d" (tempPhaseLow),
[tempStep] "= & d" (tempStep),
[tempVolume] "= & d" (tempVolume),
[outValue] "= & d" (outValue)
:
ingångar
[stepVolume] "y" (& oscillators[0].phaseStep),
[waveBase] "z" (256 * (((unsigned int) curWave) >> 8))
:
andra register vi clobber (genom att göra uppförökningar)
"r1"
);
på denna punkt outValue = oscillator värde
Det är för närvarande maxade till full volym / 4
att tillåta vissa utrymme för filtrering
#ifdef FILTER_LPF_HACK
ett lågpassfilter baserat på en från MeeBlip (http://meeblip.noisepages.com)
en += f*((in-a) + q*(a-b)
b + = f * (a-b)
outValue >> = 3;
började på 4700
4686
int tempReg, tempReg2 = 0;
unsigned char zeroRegFilt = 0;
de-volatilisati
unsigned char filtF = filterF;
unsigned char filtQ = filterQ;
ASM flyktiga)
"sub %A [outVal], administrationskostnader [filtA]" "\n\t"
"sbc %B [outVal], %B [filtA]" "\n\t"
"brvc No_overflow1% =" "\n\t"
"ldi %A [outVal], 0b00000001" "\n\t"
"ldi %B [outVal], 0b10000000" "\n\t"
"No_overflow1% =:" "\n\t"
outVal = (i - filtA)
"mov %A [tempReg], administrationskostnader [filtA]" "\n\t"
"mov %B [tempReg], %B [filtA]" "\n\t"
"sub %A [tempReg], administrationskostnader [filtB]" "\n\t"
"sbc %B [tempReg], %B [filtB]" "\n\t"
"brvc No_overflow3% =" "\n\t"
"ldi %A [tempReg], 0b00000001" "\n\t"
"ldi %B [tempReg], 0b10000000" "\n\t"
"No_overflow3% =:" "\n\t"
tempReg = (a-b)
"mulsu %B [tempReg], % [filtQ]" "\n\t"
"movw %A [tempReg2], r0" "\n\t"
tempReg2 = (HIBYTE(a-b)) * Q
"mul %A [tempReg], % [filtQ]" "\n\t"
"Lägg till %A [tempReg2], r1" "\n\t"
"adc %B [tempReg2] % [noll]" "\n\t"
"rol r0" "\n\t"
"brcc No_Round1% =" "\n\t"
"inkl %A [tempReg2]" "\n\t"
"No_Round1% =:" "\n\t"
på denna punkt tempReg2 = (a-b) * Q (skiftat på lämpligt sätt och rundade)
"clc" "\n\t"
"Amilia %A [tempReg2]" "\n\t"
"rol %B [tempReg2]" "\n\t"
"clc" "\n\t"
"Amilia %A [tempReg2]" "\n\t"
"rol %B [tempReg2]" "\n\t"
tempReg2 = (a-b) * Q * 4
"Lägg till %A [outVal], administrationskostnader [tempReg2]" "\n\t"
"adc %B [outVal], %B [tempReg2]" "\n\t"
"brvc No_overflow4% =" "\n\t"
"ldi %A [outVal], 0b11111111" "\n\t"
"ldi %B [outVal], 0b01111111" "\n\t"
"No_overflow4% =:" "\n\t"
outVal = ((in-a) + (a-b) * (Q >> 8) * 4) - klippt etc
"mulsu %B [outVal] % [filtF]" "\n\t"
"movw %A [tempReg], r0" "\n\t"
"mul %A [outVal] % [filtF]" "\n\t"
"Lägg till %A [tempReg], r1" "\n\t"
"adc %B [tempReg], % [noll]" "\n\t"
"rol r0" "\n\t"
"brcc No_Round2% =" "\n\t"
"inkl %A [tempReg]" "\n\t"
tempReg = f * ((in-a) + (a-b) * (Q >> 8) * 4)
"No_Round2% =:" "\n\t"
"Lägg till %A [filtA], administrationskostnader [tempReg]" "\n\t"
"adc %B [filtA], %B [tempReg]" "\n\t"
A = A + f * ((in-a) + (a-b) * (Q >> 8) * 4)
"brvc No_overflow5% =" "\n\t"
"ldi %A [outVal], 0b11111111" "\n\t"
"ldi %B [outVal], 0b01111111" "\n\t"
"No_overflow5% =:" "\n\t"
nu beräkna B = f * (a - b)
"mov %A [tempReg], administrationskostnader [filtA]" "\n\t"
"mov %B [tempReg], %B [filtA]" "\n\t"
"sub %A [tempReg], administrationskostnader [filtB]" "\n\t"
"sbc %B [tempReg], %B [filtB]" "\n\t"
"brvc No_overflow6% =" "\n\t"
"ldi %A [tempReg], 0b00000001" "\n\t"
"ldi %B [tempReg], 0b10000000" "\n\t"
"No_overflow6% =:" "\n\t"
tempReg = (a-b)
"mulsu %B [tempReg], % [filtF]" "\n\t"
"movw %A [tempReg2], r0" "\n\t"
"mul %A [tempReg], % [filtF]" "\n\t"
"Lägg till %A [tempReg2], r1" "\n\t"
"adc %B [tempReg2] % [noll]" "\n\t"
tempReg2 = f*(a-b)
"Lägg till %A [filtB], administrationskostnader [tempReg2]" "\n\t"
"adc %B [filtB], %B [tempReg2]" "\n\t"
"brvc No_overflow7% =" "\n\t"
"ldi %A [filtB], 0b11111111" "\n\t"
"ldi %B [filtB], 0b01111111" "\n\t"
"No_overflow7% =:" "\n\t"
nu b = b+f*(a-b)
"mov %A [outVal], administrationskostnader [filtB]" "\n\t"
"mov %B [outVal], %B [filtB]" "\n\t"
multiplicera outval av 4 och klipp
"Lägg till %A [outVal], administrationskostnader [filtB]" "\n\t"
"adc %B [outVal], %B [filtB]" "\n\t"
"brbs 3, Overflow_End % =" "\n\t"
"Lägg till %A [outVal], administrationskostnader [filtB]" "\n\t"
"adc %B [outVal], %B [filtB]" "\n\t"
"brbs 3, Overflow_End % =" "\n\t"
"Lägg till %A [outVal], administrationskostnader [filtB]" "\n\t"
"adc %B [outVal], %B [filtB]" "\n\t"
"brbs 3, Overflow_End % =" "\n\t"
"rjmp No_overflow % =" "\n\t"
"Overflow_End % =:" "\n\t"
"brbs 2, Overflow_High % =" "\n\t"
"ldi %A [outVal], 0b00000001" "\n\t"
"ldi %B [outVal], 0b10000000" "\n\t"
"rjmp No_overflow % =" "\n\t"
"Overflow_High % =:" "\n\t"
"ldi %A [outVal], 0b11111111" "\n\t"
"ldi %B [outVal], 0b01111111" "\n\t"
"No_overflow % =:" "\n\t"
char valOut = ((osignerade int)(outValue)) >> 8.
valOut += 128;
OCR2A = (byte) valOut;
"Johan %B [outVal], 0x80" "\n\t"
"sts 0x00b3, %B [outVal]" "\n\t"
ovanlig linjen nedan för att se de register anslag
/*
"lds %A [filtA], 0x01" "\n\t"
"lds %B [filtA], 0x02" "\n\t"
"lds %A [filtB], 0x03" "\n\t"
"lds %B [filtB], 0x04" "\n\t"
"lds % [filtQ], 0x05" "\n\t"
"lds % [filtF], 0x06" "\n\t"
"lds %A [outVal], 0x07" "\n\t"
"lds %B [outVal], 0x08" "\n\t"
"lds %A [tempReg], 0x09" "\n\t"
"lds %B [tempReg], 0x0a" "\n\t"
"lds %A [tempReg2], 0x0b" "\n\t"
"lds %B [tempReg2], 0x0c" "\n\t"
"lds % [noll], 0x0d" "\n\t"*/
:
utgångar / läsa/skriva argument
[filtA] "+ & w" (filterA),
[filtB] "+ & w" (filterB),
[tempReg] "= & en" (tempReg),
[tempReg2] "= & d" (tempReg2)
:
[filtQ] "a" (filtQ),
[filtF] "a" (filtF),
[outVal] "a" outValue (),
[NOLL] "d" (zeroRegFilt)
ingångar
: "r1");
#endif
produktionen sker i filtret assembler kod om filtren är på
annars mata vi den för hand här
#ifdef FILTER_LPF_NONE
full vinst
outValue * = 4;
vid denna punkt, outValue är en 16-bitars signerad version av vad vi vill dvs. 0 -> 32767,-32768- > -1 (0xffff)
Vi vill ha 0 -> 32767 för att gå till 32768-65535 och-32768 -> -1 att gå till 0-32767, då vi vill bara den övre byten
ta övre byte, och sedan lägga till 128, sedan till osignerade. (Unsigned int) i den nedan är att undvika att behöva skifta (ie.just tar övre byte)
char valOut = ((osignerade int)(outValue)) >> 8.
valOut += 128;
OCR2A = (byte) valOut;
#endif
öka loop steg counter (och hög counter)
dessa används eftersom vi stoppa timern
avbryta igång, så har inget annat sätt att berätta tid
denna asm behövs förmodligen inte riktigt, men det sparar ca 10 instruktioner
eftersom variabler måste vara flyktiga
ASM)
"inc % [loopSteps]" "\n\t"
"brbc 1, loopend % =" "\n\t"
"inkl %A [loopStepsHigh]" "\n\t"
"brbc 1, loopend % =" "\n\t"
"inkl %B [loopStepsHigh]" "\n\t"
"loopend % =:" "\n\t"
: [loopSteps] "+" (loopSteps), [loopStepsHigh] "+" (loopStepsHigh):);
}