Last active
April 23, 2023 19:53
-
-
Save NT7S/aab7243e425da911f53b to your computer and use it in GitHub Desktop.
Generate PSK31 with an Si5351A
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <si5351.h> | |
#include "Wire.h" | |
Si5351 si5351; | |
uint16_t varicode[] = | |
{ | |
0b1010101011000000, // 0 NUL | |
0b1011011011000000, // 1 SOH | |
0b1011101101000000, // 2 STX | |
0b1101110111000000, // 3 ETX | |
0b1011101011000000, // 4 EOT | |
0b1101011111000000, // 5 ENQ | |
0b1011101111000000, // 6 ACK | |
0b1011111101000000, // 7 BEL | |
0b1011111111000000, // 8 BS | |
0b1110111100000000, // 9 HT | |
0b1110100000000000, // 10 LF | |
0b1101101111000000, // 11 VT | |
0b1011011101000000, // 12 FF | |
0b1111100000000000, // 13 CR | |
0b1101110101000000, // 14 SO | |
0b1110101011000000, // 15 SI | |
0b1011110111000000, // 16 DLE | |
0b1011110101000000, // 17 DC1 | |
0b1110101101000000, // 18 DC2 | |
0b1110101111000000, // 19 DC3 | |
0b1101011011000000, // 20 DC4 | |
0b1101101011000000, // 21 NAK | |
0b1101101101000000, // 22 SYN | |
0b1101010111000000, // 23 ETB | |
0b1101111011000000, // 24 CAN | |
0b1101111101000000, // 25 EM | |
0b1110110111000000, // 26 SUB | |
0b1101010101000000, // 27 ESC | |
0b1101011101000000, // 28 FS | |
0b1110111011000000, // 29 GS | |
0b1011111011000000, // 30 RS | |
0b1101111111000000, // 31 US | |
0b1000000000000000, // 32 SP | |
0b1111111110000000, // 33 ! | |
0b1010111110000000, // 34 " | |
0b1111101010000000, // 35 # | |
0b1110110110000000, // 36 $ | |
0b1011010101000000, // 37 % | |
0b1010111011000000, // 38 & | |
0b1011111110000000, // 39 ' | |
0b1111101100000000, // 40 ( | |
0b1111011100000000, // 41 ) | |
0b1011011110000000, // 42 * | |
0b1110111110000000, // 43 + | |
0b1110101000000000, // 44 , | |
0b1101010000000000, // 45 - | |
0b1010111000000000, // 46 . | |
0b1101011110000000, // 47 / | |
0b1011011100000000, // 48 0 | |
0b1011110100000000, // 49 1 | |
0b1110110100000000, // 50 2 | |
0b1111111100000000, // 51 3 | |
0b1011101110000000, // 52 4 | |
0b1010110110000000, // 53 5 | |
0b1011010110000000, // 54 6 | |
0b1101011010000000, // 55 7 | |
0b1101010110000000, // 56 8 | |
0b1101101110000000, // 57 9 | |
0b1111010100000000, // 58 : | |
0b1101111010000000, // 59 ; | |
0b1111011010000000, // 60 < | |
0b1010101000000000, // 61 = | |
0b1110101110000000, // 62 > | |
0b1010101111000000, // 63 ? | |
0b1010111101000000, // 64 @ | |
0b1111101000000000, // 65 A | |
0b1110101100000000, // 66 B | |
0b1010110100000000, // 67 C | |
0b1011010100000000, // 68 D | |
0b1110111000000000, // 69 E | |
0b1101101100000000, // 70 F | |
0b1111110100000000, // 71 G | |
0b1010101010000000, // 72 H | |
0b1111111000000000, // 73 I | |
0b1111111010000000, // 74 J | |
0b1011111010000000, // 75 K | |
0b1101011100000000, // 76 L | |
0b1011101100000000, // 77 M | |
0b1101110100000000, // 78 N | |
0b1010101100000000, // 79 O | |
0b1101010100000000, // 80 P | |
0b1110111010000000, // 81 Q | |
0b1010111100000000, // 82 R | |
0b1101111000000000, // 83 S | |
0b1101101000000000, // 84 T | |
0b1010101110000000, // 85 U | |
0b1101101010000000, // 86 V | |
0b1010111010000000, // 87 W | |
0b1011101010000000, // 88 X | |
0b1011110110000000, // 89 Y | |
0b1010101101000000, // 90 Z | |
0b1111101110000000, // 91 [ | |
0b1111011110000000, // 92 backslash | |
0b1111110110000000, // 93 ] | |
0b1010111111000000, // 94 ^ | |
0b1011011010000000, // 95 _ | |
0b1011011111000000, // 96 ` | |
0b1011000000000000, // 97 a | |
0b1011111000000000, // 98 b | |
0b1011110000000000, // 99 c | |
0b1011010000000000, // 100 d | |
0b1100000000000000, // 101 e | |
0b1111010000000000, // 102 f | |
0b1011011000000000, // 103 g | |
0b1010110000000000, // 104 h | |
0b1101000000000000, // 105 i | |
0b1111010110000000, // 106 j | |
0b1011111100000000, // 107 k | |
0b1101100000000000, // 108 l | |
0b1110110000000000, // 109 m | |
0b1111000000000000, // 110 n | |
0b1110000000000000, // 111 o | |
0b1111110000000000, // 112 p | |
0b1101111110000000, // 113 q | |
0b1010100000000000, // 114 r | |
0b1011100000000000, // 115 s | |
0b1010000000000000, // 116 t | |
0b1101110000000000, // 117 u | |
0b1111011000000000, // 118 v | |
0b1101011000000000, // 119 w | |
0b1101111100000000, // 120 x | |
0b1011101000000000, // 121 y | |
0b1110101010000000, // 122 z | |
0b1010110111000000, // 123 { | |
0b1101110110000000, // 124 | | |
0b1010110101000000, // 125 } | |
0b1011010111000000, // 126 ~ | |
0b1110110101000000 // 127 (del) | |
}; | |
volatile int index = 0; | |
volatile uint16_t symbol; | |
volatile int psk_bit = 0; | |
volatile int zero_count = 0; | |
volatile int set_vfo = 0; | |
uint32_t freq = 14100000UL; | |
//uint64_t freq = 1410000000ULL; | |
String mystring = "DE NT7S CN85NM\n"; | |
int psk_bit_prev = 0; | |
const int baud_rate = 3125; | |
//const int baud_rate = 6250; | |
const unsigned long long pll_freq = 87000000000ULL; | |
int led = 13; | |
void setup() | |
{ | |
Serial.begin(57600); | |
// Initialize the Si5351A | |
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0); | |
delay(10); | |
uint8_t temp = si5351.si5351_read(16); | |
Serial.println(temp, HEX); | |
temp = si5351.si5351_read(17); | |
Serial.println(temp, HEX); | |
//si5351.set_correction(14); | |
si5351.set_correction(-72); | |
si5351.si5351_write(187, 0x92); | |
si5351.set_pll(pll_freq, SI5351_PLLA); | |
//si5351.set_pll(pll_freq, SI5351_PLLB); | |
si5351.si5351_write(16, 0x80); | |
si5351.si5351_write(17, 0x80); | |
si5351.si5351_write(18, 0x80); | |
si5351.set_ms_source(SI5351_CLK0, SI5351_PLLA); | |
si5351.set_ms_source(SI5351_CLK1, SI5351_PLLA); | |
si5351.set_ms_source(SI5351_CLK2, SI5351_PLLA); | |
si5351.set_freq((freq * 100ULL), pll_freq, SI5351_CLK1); | |
si5351.set_freq((freq * 100ULL), pll_freq, SI5351_CLK2); | |
si5351.set_phase(SI5351_CLK0, 0); | |
si5351.set_phase(SI5351_CLK1, 0); | |
si5351.set_phase(SI5351_CLK2, 0); | |
//si5351.set_freq((freq * 100ULL), pll_freq, SI5351_CLK0); | |
//si5351.set_freq((freq * 100ULL) + (baud_rate / 2), pll_freq, SI5351_CLK1); | |
//si5351.set_freq((freq * 100ULL) - (baud_rate / 2), pll_freq, SI5351_CLK2); | |
si5351.si5351_write(16, 0x0c); | |
si5351.si5351_write(17, 0x0c); | |
si5351.si5351_write(18, 0x0c); | |
si5351.si5351_write(177, 0xAC); | |
// Load the first varicode symbol from the message | |
symbol = varicode[mystring.charAt(index)]; | |
// We'll flash the LED in sync with the PSK modulation | |
pinMode(led, OUTPUT); | |
// Set up Timer1 for interrupts at 31.25 Hz | |
cli(); //stop interrupts | |
TCCR1A = 0;// set entire TCCR1A register to 0 | |
TCNT1 = 0;//initialize counter value to 0 | |
// set compare match register | |
if(baud_rate == 3125) | |
{ | |
OCR1A = 7971;// = (16*10^6) / (1*1024) - 1 (must be <65536) | |
//OCR1A = 499;// = (16*10^6) / (1*1024) - 1 (must be <65536) | |
} | |
else if(baud_rate == 6250) | |
{ | |
OCR1A = 250; | |
} | |
// turn on CTC mode, set CS12 and CS10 bits for 1024 prescaler | |
//TCCR1B = (1 << WGM12) | (1 << CS12) | (1 << CS10); | |
// 64 | |
TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); | |
// enable timer compare interrupt | |
TIMSK1 = (1 << OCIE1A); | |
sei(); //allow interrupts | |
} | |
ISR(TIMER1_COMPA_vect) | |
{ | |
if(symbol == 0) | |
{ | |
if(zero_count) | |
{ | |
psk_bit = 0; | |
zero_count--; | |
} | |
else | |
{; | |
index++; | |
// Reset message pointer to beginning of string if at end | |
if(index >= mystring.length()) | |
{ | |
index = 0; | |
} | |
symbol = varicode[mystring.charAt(index)]; | |
} | |
} | |
else | |
{ | |
if(symbol & 0x8000) // 1 in the MSB position | |
{ | |
psk_bit = 1; | |
} | |
else // 0 in the MSB position | |
{ | |
psk_bit = 0; | |
} | |
symbol <<= 1; | |
if(symbol == 0) | |
{ | |
zero_count = 2; | |
} | |
else | |
{ | |
zero_count = 0; | |
} | |
} | |
set_vfo = 1; | |
} | |
void loop() | |
{ | |
if(set_vfo) | |
{ | |
set_vfo = 0; | |
if(psk_bit) | |
{ | |
if(psk_bit_prev == 0) | |
{ | |
psk_one(); | |
digitalWrite(led, HIGH); | |
} | |
psk_bit_prev = 1; | |
} | |
else | |
{ | |
if(psk_bit_prev == 1) | |
{ | |
psk_zero(); | |
digitalWrite(led, LOW); | |
} | |
psk_bit_prev = 0; | |
} | |
} | |
} | |
void psk_zero() | |
{ | |
//si5351.si5351_write(165, 0); | |
//si5351.si5351_write(166, 0); | |
//si5351.pll_reset(SI5351_PLLA); | |
//si5351.set_clock_source(SI5351_CLK0, SI5351_CLK_SRC_CLKIN); | |
//si5351.set_clock_source(SI5351_CLK1, SI5351_CLK_SRC_MS); | |
//si5351.set_clock_source(SI5351_CLK2, SI5351_CLK_SRC_MS); | |
si5351.set_freq((freq * 100ULL) + (baud_rate / 2), pll_freq, SI5351_CLK1); | |
si5351.set_freq((freq * 100ULL) - (baud_rate / 2), pll_freq, SI5351_CLK2); | |
//si5351.set_phase(SI5351_CLK1, 0); | |
//si5351.set_phase(SI5351_CLK2, 0); | |
//si5351.si5351_write(16, 0x0c); | |
//si5351.si5351_write(17, 0x0c); | |
} | |
void psk_one() | |
{ | |
//si5351.set_clock_source(SI5351_CLK0, SI5351_CLK_SRC_CLKIN); | |
//si5351.set_clock_source(SI5351_CLK1, SI5351_CLK_SRC_MS0); | |
//si5351.set_clock_source(SI5351_CLK2, SI5351_CLK_SRC_MS0); | |
//si5351.set_phase(SI5351_CLK1, 0); | |
//si5351.set_phase(SI5351_CLK2, 0); | |
si5351.set_freq((freq * 100ULL), pll_freq, SI5351_CLK1); | |
si5351.set_freq((freq * 100ULL), pll_freq, SI5351_CLK2); | |
//si5351.set_phase(SI5351_CLK1, 0); | |
//si5351.set_phase(SI5351_CLK2, 0); | |
//si5351.si5351_write(16, 0x0c); | |
//si5351.si5351_write(17, 0x0c); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment