Hallo Leute,
ich versuche gerade den Code für mein Theremin zu verstehen/optimieren.
Allerdings verstehe ich einfach nicht, wie und warum gewisse Codezeilen funktionieren.
Ich poste hier mal den Teil des Codes, der mir Schwierigkeiten bereitet.
Es gibt ein Array mit 1024 Einträgen, das ist die Wavetable (gekürzt):
include <avr/pgmspace.h>
const int16_t sine_table0[1024] PROGMEM = {\
2319,
2334,
2348,
2363,
2376,
2391,
2404,
2419,
2433,
2447,
2462,
2475,
2490,
2503,
2518,
2531,
2546,
usw ......
Diese Wavetable wird in einer Interrupt-Routine verwendet, im Endeffekt werden ausgewählte Einträge an den DAC gesendet …
/* General variables */
int32_t pitch_init = 0; // Initialization value of pitch
int32_t vol_init = 0; // Initialization value of volume
int32_t pitch_v,pitch_l; // Last value of pitch (for filtering)
int32_t vol_v,vol_l; // Last value of volume (for filtering)
uint16_t pitch = 0; // Pitch value
uint16_t pitch_counter = 0; // Pitch counter
uint16_t pitch_counter_l = 0; // Last value of pitch counter
uint16_t vol = 0; // Volume value
uint16_t vol_counter_l = 0; // Last value of volume counter
/* volatile varables - used in the ISR Routine*/
volatile uint8_t vol8; // Volume byte
volatile bool flag_vol,flag_pitch = 0; // Volume read flag
volatile uint16_t vol_counter,vol_counter_i = 0; // Volume counter
volatile uint16_t pointer = 0; // Table pointer
volatile uint16_t add_val = 0; // Table pointer increment
volatile uint16_t timer = 0; // Timer value
volatile uint8_t deb_p,deb_v = 0; // Counters vor debouncing
/* 16 bit by 8 bit multiplication */
static inline uint32_t mul_16_8(uint16_t a, uint8_t b)
{
uint32_t product;
asm (
"mul %A1, %2\n\t"
"movw %A0, r0\n\t"
"clr %C0\n\t"
"clr %D0\n\t"
"mul %B1, %2\n\t"
"add %B0, r0\n\t"
"adc %C0, r1\n\t"
"clr r1"
:
"=&r" (product)
:
"r" (a), "r" (b));
return product;
}
/* Externaly generated 31250 Hz Interrupt for WAVE generator (32us) */
ISR (INT1_vect)
{
// Interrupt takes up a total of max 25 us
EIMSK &= ~ (1<<INT1); // Disable External Interrupt INT1 to avoid recursive interrupts
interrupts(); // Enable Interrupts to allow counter 1 interrupts
int16_t temp_val; // temporary variable 1
uint32_t temp2_val; // temporary variable 2
// Wie und warum funktioniert diese Konstrukt
temp_val = (signed int)pgm_read_word_near (sine_table + ((unsigned int)(pointer>>6) & 0x3ff)); //Read next wave table value (3.0us)
// Aber das nicht ?
//temp_val = (signed int)pgm_read_word_near (sine_table0[pointer]);
// multiply 16 bit wave number by 8 bit volume value (11.2us / 5.4us)
temp2_val=mul_16_8(temp_val,vol8);
temp2_val=temp2_val>>9;
mcpDacSend(temp2_val); //Send result to Digital to Analogue Converter (audio out) (9.6 us)
pointer = pointer + add_val; // increment table pointer (ca. 2us)
timer++; // update 32us timer
};
Es gibt natürlich noch mehr Code, aber im Moment interessiert mich nur dieser Teil.
Meiner Meinung nach kann das erste pgm_read_word_near( … ) keine sinvollen Einträge aus der Tabelle liefen, aber es funktioniert.
Das zweite pgm_read_word_near() sollte (nach Recherchen im I-Net) funktionieren ohne Tricks und doppelten
Boden , tut es aber nicht, da kommt nur Krach raus …
Verrückt ist auch, dass
pointer = pointer + add_val;
zu einem Überlauf führen sollte … macht es aber nicht, wie man so auf die 1024 Elemente des Arrays korrekt zugreifen kann ist mir ein Rätsel …
Vielleicht bin ich auch beriebsblind … wer weiß.
Es gibt noch mehr Code, aber keinen, der pointer betrifft und auich nicht das Array …
die Interupt-Routine habe ich natürlich gekürzt, da steht zwar noch einiges aber nichts,
was mit dem Array zu tun hat.
So, ich hoffe/weiß jemand von euch wird das Rätsel lösen.
Viele Grüße Harry
PS: Wenn ihr mehr Infos braucht, ich gebe alles was ich habe …