Table of Contents
RFM22B
- Modified library RFM22 on github
Setup
The RFM22B radio default data rates are too fast for use as long range transmitters so we need to set it up to allow us to control the transmitter for Hellschreiber and RTTY.
Hardware
- 3.3v
- Gnd
- SPI
- GPIO → nSEL
- SCK → SCK
- MOSI → SDI
- MISO → SD0
- Connect SDN to a GPIO on the uC. This allows you to turn the radio completely on and off, if you don't need power saving then this pin can be connected to GND to be always on.
- GPIO0 → TX_ANT
- GPIO1 → RX_ANT
Software
#include <SPI.h> #include <RFM22.h> //Setup radio on SPI with NSEL on pin 10 rfm22 radio1(10); void setupRadio(){ digitalWrite(5, LOW); delay(1000); rfm22::initSPI(); radio1.init(); radio1.write(0x71, 0x00); // unmodulated carrier //This sets up the GPIOs to automatically switch the antenna depending on Tx or Rx state, only needs to be done at start up radio1.write(0x0b,0x12); radio1.write(0x0c,0x15); radio1.setFrequency(434.201); //Quick test radio1.write(0x07, 0x08); // turn tx on delay(1000); radio1.write(0x07, 0x01); // turn tx off }
Hellschreiber
Hellschreiber is an On/Off keying mode which 'prints' out the characters as pixels. It is simple to use and easily decoded by eye though for tracking does require manual inputing of the data. In the case of the RFM22b it is necessary to setup an unmodulated carrier and then turn the transmitter on and off as required.
Hardware
- Control is via SPI
Software
//***************Hellschreiber****************** struct t_htab { char c; int hellpat[5]; } ; struct t_htab helltab[] = { {'1', { B00000100, B00000100, B01111100, B00000000, B00000000 } }, {'2', { B01001000, B01100100, B01010100, B01001100, B01000000 } }, {'3', { B01000100, B01000100, B01010100, B01010100, B00111100 } }, {'4', { B00011100, B00010000, B00010000, B01111100, B00010000 } }, {'5', { B01000000, B01011100, B01010100, B01010100, B00110100 } }, {'6', { B00111100, B01010010, B01001010, B01001000, B00110000 } }, {'7', { B01000100, B00100100, B00010100, B00001100, B00000100 } }, {'8', { B00111100, B01001010, B01001010, B01001010, B00111100 } }, {'9', { B00001100, B01001010, B01001010, B00101010, B00111100 } }, {'0', { B00111000, B01100100, B01010100, B01001100, B00111000 } }, {'A', { B01111000, B00101100, B00100100, B00101100, B01111000 } }, {'B', { B01000100, B01111100, B01010100, B01010100, B00101000 } }, {'C', { B00111000, B01101100, B01000100, B01000100, B00101000 } }, {'D', { B01000100, B01111100, B01000100, B01000100, B00111000 } }, {'E', { B01111100, B01010100, B01010100, B01000100, B01000100 } }, {'F', { B01111100, B00010100, B00010100, B00000100, B00000100 } }, {'G', { B00111000, B01101100, B01000100, B01010100, B00110100 } }, {'H', { B01111100, B00010000, B00010000, B00010000, B01111100 } }, {'I', { B00000000, B01000100, B01111100, B01000100, B00000000 } }, {'J', { B01100000, B01000000, B01000000, B01000000, B01111100 } }, {'K', { B01111100, B00010000, B00111000, B00101000, B01000100 } }, {'L', { B01111100, B01000000, B01000000, B01000000, B01000000 } }, {'M', { B01111100, B00001000, B00010000, B00001000, B01111100 } }, {'N', { B01111100, B00000100, B00001000, B00010000, B01111100 } }, {'O', { B00111000, B01000100, B01000100, B01000100, B00111000 } }, {'P', { B01000100, B01111100, B01010100, B00010100, B00011000 } }, {'Q', { B00111000, B01000100, B01100100, B11000100, B10111000 } }, {'R', { B01111100, B00010100, B00010100, B00110100, B01011000 } }, {'S', { B01011000, B01010100, B01010100, B01010100, B00100100 } }, {'T', { B00000100, B00000100, B01111100, B00000100, B00000100 } }, {'U', { B01111100, B01000000, B01000000, B01000000, B01111100 } }, {'V', { B01111100, B00100000, B00010000, B00001000, B00000100 } }, {'W', { B01111100, B01100000, B01111100, B01000000, B01111100 } }, {'X', { B01000100, B00101000, B00010000, B00101000, B01000100 } }, {'Y', { B00000100, B00001000, B01110000, B00001000, B00000100 } }, {'Z', { B01000100, B01100100, B01010100, B01001100, B01100100 } }, {'.', { B01000000, B01000000, B00000000, B00000000, B00000000 } }, {',', { B10000000, B10100000, B01100000, B00000000, B00000000 } }, {'/', { B01000000, B00100000, B00010000, B00001000, B00000100 } }, {'*', { B00000000, B00000000, B00000100, B00001110, B00000100 } } }; #define N_HELL (sizeof(helltab)/sizeof(helltab[0])) void helldelay() { //Slow Hell delay(64); delayMicroseconds(900); //Feld-Hell //delay(8); //delayMicroseconds(160); } void on() { radio1.write(0x07, 0x08); //on helldelay(); radio1.write(0x07, 0x01); //off } void hellsend(char c) { int i ; if (c == ' ') { for (int d=0; d<14; d++){ helldelay(); } return ; } for (i=0; i<N_HELL; i++) { if (helltab[i].c == c) { //Serial.print(helltab[i].c) ; for (j=0; j<=4; j++) { byte mask = B10000000; for (q=0; q<=6; q++) { if(helltab[i].hellpat[j] & mask) { on(); } else { helldelay(); } mask >>= 1; } } for (int d=0; d<14; d++){ helldelay(); } return ; } } /* if we drop off the end, then we send a space */ //Serial.print("?") ; } void hellsendmsg(char *str) { radio1.setFrequency(434.201); delay(1000); while (*str) hellsend(*str++) ; //Serial.println(""); } void loop(){ hellsendmsg(superbuffer); radio1.write(0x07, 0x01); // turn tx off }
RTTY
RTTY can be generated on the RFM22b by switching the frequency of the transmitter between MARK and SPACE. The radio is setup to transmit and unmodulated carrier and then over SPI we just change the frequency via the library. Using this it is quite possible to transmit at 50baud with a 500Hz shift.
Hardware
- All control is via SPI
Software
Library functions
//Taken from the RF22 Library (http://www.open.com.au/mikem/arduino/RF22/) // Returns true if centre + (fhch * fhs) is within limits // Caution, different versions of the RF22 suport different max freq // so YMMV boolean rfm22::setFrequency(float centre) { uint8_t fbsel = 0x40; if (centre < 240.0 || centre > 960.0) // 930.0 for early silicon return false; if (centre >= 480.0) { centre /= 2; fbsel |= 0x20; } centre /= 10.0; float integerPart = floor(centre); float fractionalPart = centre - integerPart; uint8_t fb = (uint8_t)integerPart - 24; // Range 0 to 23 fbsel |= fb; uint16_t fc = fractionalPart * 64000; write(0x73, 0); // REVISIT write(0x74, 0); write(0x75, fbsel); write(0x76, fc >> 8); write(0x77, fc & 0xff); }
Code
// RTTY Functions - from RJHARRISON's AVR Code void rtty_txstring (char * string) { /* Simple function to sent a char at a time to ** rtty_txbyte function. ** NB Each char is one byte (8 Bits) */ char c; c = *string++; while ( c != '\0') { rtty_txbyte (c); c = *string++; } } void rtty_txbyte (char c) { /* Simple function to sent each bit of a char to ** rtty_txbit function. ** NB The bits are sent Least Significant Bit first ** ** All chars should be preceded with a 0 and ** proceded with a 1. 0 = Start bit; 1 = Stop bit ** ** ASCII_BIT = 7 or 8 for ASCII-7 / ASCII-8 */ int i; rtty_txbit (0); // Start bit // Send bits for for char LSB first for (i=0;i<8;i++) { if (c & 1) rtty_txbit(1); else rtty_txbit(0); c = c >> 1; } rtty_txbit (1); // Stop bit rtty_txbit (1); // Stop bit } void rtty_txbit (int bit) { if (bit) { // high radio1.setFrequency(434.2010); } else { // low radio1.setFrequency(434.2015); } delayMicroseconds(19500); // 10000 = 100 BAUD 20150 } void loop(){ radio1.write(0x07, 0x08); // turn tx on delay(5000); rtty_txstring("$$$$"); rtty_txstring(superbuffer); radio1.write(0x07, 0x01); // turn tx off }
TX_ANT and RX_ANT
On the RFM22b it is necessary to control the TX_ANT and RX_ANT pins. These pins control antenna diversity regarding the Rx state, its not clear in the datasheet what is really required however various user experience seems to suggest that while everything works when these pins are left floating its not the most efficient setup, instead by controlling the pins you can increase the transmission by up to 5db. This is probably the cause of the failure of PicoAtlas6 MK2 where the pins were wired up correctly but hadn't been set in the right mode.
Hardware
- GPIO0 → TX_ANT
- GPIO1 → RX_ANT
Software
//This sets up the GPIOs to automatically switch the antenna depending on Tx or Rx state, only needs to be done at start up radio1.write(0x0b,0x12); radio1.write(0x0c,0x15);
Info taken from the RF22 library (2)
Testing
- Rx = Yaesu FT790r no antenna
- Tx = RFM22b, wired up correctly, no antenna
- 0.5m range
- Before setting the GPIOs correctly in software S1
- After S9
DominoEX
With a few external components, The RFM22b can be used to send poor mans DominoEX.
I say 'poor mans' as whilst this can be made stable for flight, it is a bit fiddly and non ideal. The RFM must be kept on TX all the time as the RFM22b's internal crystal oscillator circuit has a series capacitance that wanders according to the die temperature. For the best results it is better to have an external crystal and oscillator circuit which does not get affected by the changing capacitance.
This circuit works by using the PWM output of the microprocessor, through a filter to remove the AC component and to pull the onboard crystal of the RFM22b via a varicap diode. The RFM crystal is only 30MHz and is multiplied up by approximatly 14.5 times. Since the tone spacing of Domino is only 17.5Hz at 434Mhz, the shift at 30MHz is in the order of only 1Hz per tone or about 20Hz total
The varicap needs to be biased so that it is not being used at the bottom of its working range, so in the sample code the PWM is set to a minimum output level of say 100 and then the actual symbol is added to this.
The code example also reprograms the timer counter so that the PWM is 8 bit fast mode so that the pwm frequency is easily filtered to give the dc level required by the varicap.
Circuit Diagram
For a full description see Crystal Pulling. The sensitivity of the circuit can be reduced by reducing the value of C2
Code
note: Since the Timer counter is being used for fast pwm, software serial cannot be used to talk to the GPS.
unsigned char varicode[][3] = { /* Primary alphabet */ { 1,15, 9}, { 1,15,10}, { 1,15,11}, { 1,15,12}, { 1,15,13}, { 1,15,14}, { 1,15,15}, { 2, 8, 8}, { 2,12, 0}, { 2, 8, 9}, { 2, 8,10}, { 2, 8,11}, { 2, 8,12}, { 2,13, 0}, { 2, 8,13}, { 2, 8,14}, { 2, 8,15}, { 2, 9, 8}, { 2, 9, 9}, { 2, 9,10}, { 2, 9,11}, { 2, 9,12}, { 2, 9,13}, { 2, 9,14}, { 2, 9,15}, { 2,10, 8}, { 2,10, 9}, { 2,10,10}, { 2,10,11}, { 2,10,12}, { 2,10,13}, { 2,10,14}, { 0, 0, 0}, { 7,11, 0}, { 0, 8,14}, { 0,10,11}, { 0, 9,10}, { 0, 9, 9}, { 0, 8,15}, { 7,10, 0}, { 0, 8,12}, { 0, 8,11}, { 0, 9,13}, { 0, 8, 8}, { 2,11, 0}, { 7,14, 0}, { 7,13, 0}, { 0, 8, 9}, { 3,15, 0}, { 4,10, 0}, { 4,15, 0}, { 5, 9, 0}, { 6, 8, 0}, { 5,12, 0}, { 5,14, 0}, { 6,12, 0}, { 6,11, 0}, { 6,14, 0}, { 0, 8,10}, { 0, 8,13}, { 0,10, 8}, { 7,15, 0}, { 0, 9,15}, { 7,12, 0}, { 0, 9, 8}, { 3, 9, 0}, { 4,14, 0}, { 3,12, 0}, { 3,14, 0}, { 3, 8, 0}, { 4,12, 0}, { 5, 8, 0}, { 5,10, 0}, { 3,10, 0}, { 7, 8, 0}, { 6,10, 0}, { 4,11, 0}, { 4, 8, 0}, { 4,13, 0}, { 3,11, 0}, { 4, 9, 0}, { 6,15, 0}, { 3,13, 0}, { 2,15, 0}, { 2,14, 0}, { 5,11, 0}, { 6,13, 0}, { 5,13, 0}, { 5,15, 0}, { 6, 9, 0}, { 7, 9, 0}, { 0,10,14}, { 0,10, 9}, { 0,10,15}, { 0,10,10}, { 0, 9,12}, { 0, 9,11}, { 4, 0, 0}, { 1,11, 0}, { 0,12, 0}, { 0,11, 0}, { 1, 0, 0}, { 0,15, 0}, { 1, 9, 0}, { 0,10, 0}, { 5, 0, 0}, { 2,10, 0}, { 1,14, 0}, { 0, 9, 0}, { 0,14, 0}, { 6, 0, 0}, { 3, 0, 0}, { 1, 8, 0}, { 2, 8, 0}, { 7, 0, 0}, { 0, 8, 0}, { 2, 0, 0}, { 0,13, 0}, { 1,13, 0}, { 1,12, 0}, { 1,15, 0}, { 1,10, 0}, { 2, 9, 0}, { 0,10,12}, { 0, 9,14}, { 0,10,12}, { 0,11, 8}, { 2,10,15}, { 2,11, 8}, { 2,11, 9}, { 2,11,10}, { 2,11,11}, { 2,11,12}, { 2,11,13}, { 2,11,14}, { 2,11,15}, { 2,12, 8}, { 2,12, 9}, { 2,12,10}, { 2,12,11}, { 2,12,12}, { 2,12,13}, { 2,12,14}, { 2,12,15}, { 2,13, 8}, { 2,13, 9}, { 2,13,10}, { 2,13,11}, { 2,13,12}, { 2,13,13}, { 2,13,14}, { 2,13,15}, { 2,14, 8}, { 2,14, 9}, { 2,14,10}, { 2,14,11}, { 2,14,12}, { 2,14,13}, { 2,14,14}, { 2,14,15}, { 0,11, 9}, { 0,11,10}, { 0,11,11}, { 0,11,12}, { 0,11,13}, { 0,11,14}, { 0,11,15}, { 0,12, 8}, { 0,12, 9}, { 0,12,10}, { 0,12,11}, { 0,12,12}, { 0,12,13}, { 0,12,14}, { 0,12,15}, { 0,13, 8}, { 0,13, 9}, { 0,13,10}, { 0,13,11}, { 0,13,12}, { 0,13,13}, { 0,13,14}, { 0,13,15}, { 0,14, 8}, { 0,14, 9}, { 0,14,10}, { 0,14,11}, { 0,14,12}, { 0,14,13}, { 0,14,14}, { 0,14,15}, { 0,15, 8}, { 0,15, 9}, { 0,15,10}, { 0,15,11}, { 0,15,12}, { 0,15,13}, { 0,15,14}, { 0,15,15}, { 1, 8, 8}, { 1, 8, 9}, { 1, 8,10}, { 1, 8,11}, { 1, 8,12}, { 1, 8,13}, { 1, 8,14}, { 1, 8,15}, { 1, 9, 8}, { 1, 9, 9}, { 1, 9,10}, { 1, 9,11}, { 1, 9,12}, { 1, 9,13}, { 1, 9,14}, { 1, 9,15}, { 1,10, 8}, { 1,10, 9}, { 1,10,10}, { 1,10,11}, { 1,10,12}, { 1,10,13}, { 1,10,14}, { 1,10,15}, { 1,11, 8}, { 1,11, 9}, { 1,11,10}, { 1,11,11}, { 1,11,12}, { 1,11,13}, { 1,11,14}, { 1,11,15}, { 1,12, 8}, { 1,12, 9}, { 1,12,10}, { 1,12,11}, { 1,12,12}, { 1,12,13}, { 1,12,14}, { 1,12,15}, { 1,13, 8}, { 1,13, 9}, { 1,13,10}, { 1,13,11}, { 1,13,12}, { 1,13,13}, { 1,13,14}, { 1,13,15}, { 1,14, 8}, { 1,14, 9}, { 1,14,10}, { 1,14,11}, { 1,14,12}, { 1,14,13}, { 1,14,14}, { 1,14,15}, { 1,15, 8}, /* Secondary alphabet */ { 6,15, 9}, { 6,15,10}, { 6,15,11}, { 6,15,12}, { 6,15,13}, { 6,15,14}, { 6,15,15}, { 7, 8, 8}, { 4,10,12}, { 7, 8, 9}, { 7, 8,10}, { 7, 8,11}, { 7, 8,12}, { 4,10,13}, { 7, 8,13}, { 7, 8,14}, { 7, 8,15}, { 7, 9, 8}, { 7, 9, 9}, { 7, 9,10}, { 7, 9,11}, { 7, 9,12}, { 7, 9,13}, { 7, 9,14}, { 7, 9,15}, { 7,10, 8}, { 7,10, 9}, { 7,10,10}, { 7,10,11}, { 7,10,12}, { 7,10,13}, { 7,10,14}, { 3, 8, 8}, { 4,15,11}, { 5, 8,14}, { 5,10,11}, { 5, 9,10}, { 5, 9, 9}, { 5, 8,15}, { 4,15,10}, { 5, 8,12}, { 5, 8,11}, { 5, 9,13}, { 5, 8, 8}, { 4,10,11}, { 4,15,14}, { 4,15,13}, { 5, 8, 9}, { 4,11,15}, { 4,12,10}, { 4,12,15}, { 4,13, 9}, { 4,14, 8}, { 4,13,12}, { 4,13,14}, { 4,14,12}, { 4,14,11}, { 4,14,14}, { 5, 8,10}, { 5, 8,13}, { 5,10, 8}, { 4,15,15}, { 5, 9,15}, { 4,15,12}, { 5, 9, 8}, { 4,11, 9}, { 4,12,14}, { 4,11,12}, { 4,11,14}, { 4,11, 8}, { 4,12,12}, { 4,13, 8}, { 4,13,10}, { 4,11,10}, { 4,15, 8}, { 4,14,10}, { 4,12,11}, { 4,12, 8}, { 4,12,13}, { 4,11,11}, { 4,12, 9}, { 4,14,15}, { 4,11,13}, { 4,10,15}, { 4,10,14}, { 4,13,11}, { 4,14,13}, { 4,13,13}, { 4,13,15}, { 4,14, 9}, { 4,15, 9}, { 5,10,14}, { 5,10, 9}, { 5,10,15}, { 5,10,10}, { 5, 9,12}, { 5, 9,11}, { 3, 8,12}, { 4, 9,11}, { 4, 8,12}, { 4, 8,11}, { 3, 8, 9}, { 4, 8,15}, { 4, 9, 9}, { 4, 8,10}, { 3, 8,13}, { 4,10,10}, { 4, 9,14}, { 4, 8, 9}, { 4, 8,14}, { 3, 8,14}, { 3, 8,11}, { 4, 9, 8}, { 4,10, 8}, { 3, 8,15}, { 4, 8, 8}, { 3, 8,10}, { 4, 8,13}, { 4, 9,13}, { 4, 9,12}, { 4, 9,15}, { 4, 9,10}, { 4,10, 9}, { 5,10,12}, { 5, 9,14}, { 5,10,12}, { 5,11, 8}, { 7,10,15}, { 7,11, 8}, { 7,11, 9}, { 7,11,10}, { 7,11,11}, { 7,11,12}, { 7,11,13}, { 7,11,14}, { 7,11,15}, { 7,12, 8}, { 7,12, 9}, { 7,12,10}, { 7,12,11}, { 7,12,12}, { 7,12,13}, { 7,12,14}, { 7,12,15}, { 7,13, 8}, { 7,13, 9}, { 7,13,10}, { 7,13,11}, { 7,13,12}, { 7,13,13}, { 7,13,14}, { 7,13,15}, { 7,14, 8}, { 7,14, 9}, { 7,14,10}, { 7,14,11}, { 7,14,12}, { 7,14,13}, { 7,14,14}, { 7,14,15}, { 5,11, 9}, { 5,11,10}, { 5,11,11}, { 5,11,12}, { 5,11,13}, { 5,11,14}, { 5,11,15}, { 5,12, 8}, { 5,12, 9}, { 5,12,10}, { 5,12,11}, { 5,12,12}, { 5,12,13}, { 5,12,14}, { 5,12,15}, { 5,13, 8}, { 5,13, 9}, { 5,13,10}, { 5,13,11}, { 5,13,12}, { 5,13,13}, { 5,13,14}, { 5,13,15}, { 5,14, 8}, { 5,14, 9}, { 5,14,10}, { 5,14,11}, { 5,14,12}, { 5,14,13}, { 5,14,14}, { 5,14,15}, { 5,15, 8}, { 5,15, 9}, { 5,15,10}, { 5,15,11}, { 5,15,12}, { 5,15,13}, { 5,15,14}, { 5,15,15}, { 6, 8, 8}, { 6, 8, 9}, { 6, 8,10}, { 6, 8,11}, { 6, 8,12}, { 6, 8,13}, { 6, 8,14}, { 6, 8,15}, { 6, 9, 8}, { 6, 9, 9}, { 6, 9,10}, { 6, 9,11}, { 6, 9,12}, { 6, 9,13}, { 6, 9,14}, { 6, 9,15}, { 6,10, 8}, { 6,10, 9}, { 6,10,10}, { 6,10,11}, { 6,10,12}, { 6,10,13}, { 6,10,14}, { 6,10,15}, { 6,11, 8}, { 6,11, 9}, { 6,11,10}, { 6,11,11}, { 6,11,12}, { 6,11,13}, { 6,11,14}, { 6,11,15}, { 6,12, 8}, { 6,12, 9}, { 6,12,10}, { 6,12,11}, { 6,12,12}, { 6,12,13}, { 6,12,14}, { 6,12,15}, { 6,13, 8}, { 6,13, 9}, { 6,13,10}, { 6,13,11}, { 6,13,12}, { 6,13,13}, { 6,13,14}, { 6,13,15}, { 6,14, 8}, { 6,14, 9}, { 6,14,10}, { 6,14,11}, { 6,14,12}, { 6,14,13}, { 6,14,14}, { 6,14,15}, { 6,15, 8}, }; void dominoex_txsym(uint8_t sym) { _sym = (_sym + 2 + sym) % 18; analogWrite(radio, 8*_sym+100); delay(64); } void dominoex_txchar(uint16_t code) { uint8_t i, c; for(i = 0; i < 3; i++) { c = varicode[code][i]; if(i && !(c & 0x8)) break; dominoex_txsym(c); } } void dominoex_string(char *s) { for(; *s; s++) dominoex_txchar(*s); } void setPwmFrequency(int pin, int divisor) { byte mode; if(pin == 5 || pin == 6 || pin == 9 || pin == 10) { switch(divisor) { case 1: mode = 0x01; break; case 8: mode = 0x02; break; case 64: mode = 0x03; break; case 256: mode = 0x04; break; case 1024: mode = 0x05; break; default: return; } if(pin == 5 || pin == 6) { TCCR0B = TCCR0B & 0b11111000 | mode; } else { TCCR1B = TCCR1B & 0b11111000 | mode; } } else if(pin == 3 || pin == 11) { switch(divisor) { case 1: mode = 0x01; break; case 8: mode = 0x02; break; case 32: mode = 0x03; break; case 64: mode = 0x04; break; case 128: mode = 0x05; break; case 256: mode = 0x06; break; case 1024: mode = 0x7; break; default: return; } TCCR2B = TCCR2B & 0b11111000 | mode; } } void setup() { pinMode(radio, OUTPUT); setPwmFrequency(9, 1); } void loop() { dominoex_string("The quick brown fox jumped over the lazy dog \n"); }
Tuning
Since the circuit will have pulled the oscillator off frequency you will need to find the signal as it is not where the set frequency call says it will be.
- connect a receiver to fldigi and select dominoex16.
- Turn down the volume as the sound is like two squirrels in a bag and gets rather irritating after a short time.
- move the cursors over the tones as per the picture below.
- Adjust the potentiometer so that the overall width of the tones are just inside the red lines.
- Keep adjusting till the message becomes readable.
This isn't quite as easy as it sounds as the bias voltage is also being set by the potentiometer so it will be necessary to retune the receiver and move the reference lines as you try to adjust the width of the tones
Possible improvements.
- Have a separate bias voltage potentiometer to make it easier to set up.
- External Crystal oscillator
- Pre amp for level shifting and improved filtering.
Thanks to
Fsphil and UPU for the DominoEX code.