Skip to content

Instantly share code, notes, and snippets.

@NT7S
Created April 2, 2015 16:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save NT7S/7a6e42f2693d447988be to your computer and use it in GitHub Desktop.
Save NT7S/7a6e42f2693d447988be to your computer and use it in GitHub Desktop.
Generate PSK with an Arduino and Si5351
#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;
const uint16_t baud_rate = 3125;
//const uint16_t baud_rate = 6250;
const uint16_t clock_mult = 1000;
uint32_t freq = 14100000UL;
uint32_t clock_freq = baud_rate * clock_mult;
String mystring = "DE NT7S CN85NM\n";
int psk_bit_prev = 0;
const unsigned long long pll_freq = 87000000000ULL;
int led = 13;
int external_clock_pin = 2;
void setup()
{
Serial.begin(57600);
// Setup external interrupt for clock input
pinMode(external_clock_pin, INPUT);
attachInterrupt(0, ext_clock, RISING);
// 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(-67);
//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_CLK0);
si5351.set_freq((freq * 100ULL), pll_freq, SI5351_CLK1);
si5351.set_freq((3138100ULL), pll_freq, SI5351_CLK2);
si5351.set_phase(SI5351_CLK0, 0);
si5351.set_phase(SI5351_CLK1, 0);
si5351.set_phase(SI5351_CLK2, 0);
si5351.si5351_write(16, 0x0c);
si5351.si5351_write(17, 0x0c);
si5351.si5351_write(18, 0x0c);
si5351.pll_reset(SI5351_PLLA);
// 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 = 7969d;// = (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)
{
if(psk_bit)
{
psk_one();
}
else
{
psk_zero();
}
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 = 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_CLK0);
si5351.set_freq((freq * 100ULL) - (baud_rate / 2), pll_freq, SI5351_CLK1);
digitalWrite(led, LOW);
//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_CLK0);
si5351.set_freq((freq * 100ULL), pll_freq, SI5351_CLK1);
digitalWrite(led, HIGH);
//si5351.set_phase(SI5351_CLK1, 0);
//si5351.set_phase(SI5351_CLK2, 0);
//si5351.si5351_write(16, 0x0c);
//si5351.si5351_write(17, 0x0c);
}
void ext_clock()
{
static uint32_t ext_ticks = 0;
ext_ticks++;
if(ext_ticks >= clock_mult)
{
set_vfo = 1;
ext_ticks = 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment