Skip to content

Instantly share code, notes, and snippets.

@antonl
Created January 15, 2014 06:00
Show Gist options
  • Save antonl/8431542 to your computer and use it in GitHub Desktop.
Save antonl/8431542 to your computer and use it in GitHub Desktop.
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#include <avr/pgmspace.h>
unsigned char byte_n = 0; // byte count
#define HDR_LEN 10
#define MAX_TUNING_WORD 0x3FFFFFFFul
#define ONE_HZ_CORRECTION 3036
#define TBL_LEN 512
#define LED 13
#define PB5 9
unsigned char cmd_header[HDR_LEN];
bool cmd_ready = false;
// Generated in python with np.array((np.sin(2*pi*arange(256)/256)+1)*128, int)
PROGMEM prog_uint16_t sin_table[TBL_LEN] =
{2048,2073,2098,2123,2148,2173,2198,2223,2248,2273,2298,2323,2348,2373,2398,
2422,2447,2472,2496,2521,2545,2569,2594,2618,2642,2666,2690,2714,2737,2761,
2785,2808,2831,2854,2877,2900,2923,2946,2968,2991,3013,3035,3057,3079,3100,
3122,3143,3164,3185,3206,3227,3247,3267,3288,3307,3327,3347,3366,3385,3404,
3423,3441,3460,3478,3496,3513,3531,3548,3565,3582,3598,3615,3631,3646,3662,
3677,3692,3707,3722,3736,3750,3764,3778,3791,3804,3817,3829,3842,3854,3865,
3877,3888,3899,3909,3920,3930,3940,3949,3958,3967,3976,3984,3992,4000,4007,
4014,4021,4028,4034,4040,4046,4051,4056,4061,4065,4069,4073,4077,4080,4083,
4086,4088,4090,4092,4093,4094,4095,4095,4096,4095,4095,4094,4093,4092,4090,
4088,4086,4083,4080,4077,4073,4069,4065,4061,4056,4051,4046,4040,4034,4028,
4021,4014,4007,4000,3992,3984,3976,3967,3958,3949,3940,3930,3920,3909,3899,
3888,3877,3865,3854,3842,3829,3817,3804,3791,3778,3764,3750,3736,3722,3707,
3692,3677,3662,3646,3631,3615,3598,3582,3565,3548,3531,3513,3496,3478,3460,
3441,3423,3404,3385,3366,3347,3327,3307,3288,3267,3247,3227,3206,3185,3164,
3143,3122,3100,3079,3057,3035,3013,2991,2968,2946,2923,2900,2877,2854,2831,
2808,2785,2761,2737,2714,2690,2666,2642,2618,2594,2569,2545,2521,2496,2472,
2447,2422,2398,2373,2348,2323,2298,2273,2248,2223,2198,2173,2148,2123,2098,
2073,2048,2022,1997,1972,1947,1922,1897,1872,1847,1822,1797,1772,1747,1722,
1697,1673,1648,1623,1599,1574,1550,1526,1501,1477,1453,1429,1405,1381,1358,
1334,1310,1287,1264,1241,1218,1195,1172,1149,1127,1104,1082,1060,1038,1016,
995, 973, 952, 931, 910, 889, 868, 848, 828, 807, 788, 768, 748, 729, 710,
691, 672, 654, 635, 617, 599, 582, 564, 547, 530, 513, 497, 480, 464, 449,
433, 418, 403, 388, 373, 359, 345, 331, 317, 304, 291, 278, 266, 253, 241,
230, 218, 207, 196, 186, 175, 165, 155, 146, 137, 128, 119, 111, 103, 95,
88, 81, 74, 67, 61, 55, 49, 44, 39, 34, 30, 26, 22, 18, 15,
12, 9, 7, 5, 3, 2, 1, 0, 0, 0, 0, 0, 1, 2, 3,
5, 7, 9, 12, 15, 18, 22, 26, 30, 34, 39, 44, 49, 55, 61,
67, 74, 81, 88, 95, 103, 111, 119, 128, 137, 146, 155, 165, 175, 186,
196, 207, 218, 230, 241, 253, 266, 278, 291, 304, 317, 331, 345, 359, 373,
388, 403, 418, 433, 449, 464, 480, 497, 513, 530, 547, 564, 582, 599, 617,
635, 654, 672, 691, 710, 729, 748, 768, 788, 807, 828, 848, 868, 889, 910,
931, 952, 973, 995,1016,1038,1060,1082,1104,1127,1149,1172,1195,1218,1241,
1264,1287,1310,1334,1358,1381,1405,1429,1453,1477,1501,1526,1550,1574,1599,
1623,1648,1673,1697,1722,1747,1772,1797,1822,1847,1872,1897,1922,1947,1972,
1997,2022};
uint16_t memory_table[TBL_LEN];
volatile uint32_t phase = 0ul;
volatile uint32_t tuning_word= 100ul;
inline void setup_timer1() {
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
// Set phase and frequency correct pwm mode
TCCR1A |= (1<<WGM10) | (1 << COM1A0); // clear on up count
TCCR1B |= (1<<WGM13); // Match to OCR1A
TCCR1B |= (1<<CS11) | (1<<CS10);
OCR1A = memory_table[phase >> 23]; // Take the top 9 bits
TIMSK1 |= (1<<OCIE1A) | (1<<TOIE1); // Enable timer
interrupts();
}
void setup() {
pinMode(LED, OUTPUT);
pinMode(9, OUTPUT);
TIMSK0 &= (1 << TOIE0);
setup_timer1(); // reference clock for DDS
Serial.begin(115200ul);
}
inline void load_sin() {
noInterrupts();
memcpy_P(memory_table, sin_table, TBL_LEN*sizeof(uint16_t));
Serial.println('K');
interrupts();
}
inline void set_freq() {
uint32_t a = 0, b = 0;
b = cmd_header[1];
a |= b << 24;
b = cmd_header[2];
a |= b << 16;
b = cmd_header[3];
a |= b << 8;
b = cmd_header[4];
a |= b;
if(a > MAX_TUNING_WORD) {
Serial.println('X');
} else {
noInterrupts();
tuning_word = a;
interrupts();
Serial.println('K');
}
}
inline void read_freq() {
Serial.print(tuning_word);
Serial.println('K');
}
inline void read_pts() {
for(int i=0; i < TBL_LEN; ++i) {
Serial.print(memory_table[i]);
Serial.print(',');
}
Serial.println('K');
}
inline void debug() {
Serial.print('P');
Serial.print(phase);
Serial.print(",O");
Serial.print(OCR1A);
Serial.print(",T");
Serial.print(TBL_LEN);
Serial.print(",S");
Serial.print(sizeof(unsigned long));
Serial.print(",N");
Serial.print(phase >> 23);
Serial.print(",mem");
Serial.print(memory_table[phase >> 23]);
Serial.println('K');
}
void loop() {
if(cmd_ready) {
noInterrupts();
switch(cmd_header[0]) {
case 'S': load_sin(); break; // load sin table
case 'F': set_freq(); break; // set frequency
case 'f': read_freq(); break;// read frequency
case 'p': read_pts(); break; // number of points
case 'd': debug(); break; // debug
default: Serial.println('X');
}
memset(cmd_header, 0, HDR_LEN);
cmd_ready = false;
byte_n = 0;
interrupts();
} else {
while (Serial.available()) {
// get the new byte:
cmd_header[byte_n] = (char)Serial.read();
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (cmd_header[byte_n] == '\n') {
cmd_ready = true;
byte_n = 0;
}
++byte_n;
if(byte_n > HDR_LEN) {
byte_n = 0;
cmd_ready = false;
memset(cmd_header, 0, HDR_LEN);
}
}
}
}
ISR(TIMER1_COMPA_vect) {
}
ISR(TIMER1_OVF_vect) {
phase += tuning_word;
OCR1A = memory_table[phase >> 23]; // Take the top 9 bits
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment