Friday 8 March 2019

Homebrew Panadapter

Homebrew panadapter using a Teensy 3.5.


Test Code


#include "SPI.h"
#include "ILI9341_t3.h"
#include <si5351.h>                        // Si5351Jason library
#include <Audio.h>

//const int myInput = AUDIO_INPUT_MIC;
const int myInput = AUDIO_INPUT_LINEIN;

uint16_t WaterfallData[100][128] = {1};
int Gain = 50;

static const long bandInit =  9008450;     // 8800000 8565000 to initially set the frequency. Was 9020000
volatile long freq = bandInit ;


// For optimized ILI9341_t3 library
#define TFT_DC    20
#define TFT_CS    21
#define TFT_RST   255  // 255 = unused, connect to 3.3V
#define TFT_MOSI  7
#define TFT_SCLK  14
#define TFT_MISO  12

ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);
Si5351 si5351;                            // Name for the Si5351 DDS

// Setup audio shield
AudioInputI2S            audioInput;
AudioMixer4              InputAmp;
AudioAnalyzeFFT256       FFT;

// Setup the audio connections
AudioConnection          patchCord1(audioInput, 0, InputAmp, 0);
AudioConnection          patchCord2(InputAmp, 0, FFT, 0);

// Instantiate the Audio Shield
AudioControlSGTL5000 audioShield;

void setup()
{
  Serial.begin(9600);

  // Setup screen
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(ILI9341_BLACK);
  tft.drawRect(31, 0, 257, 37, ILI9341_YELLOW);
  tft.drawRect(31, 36, 257, 103, ILI9341_YELLOW);
  tft.drawRect(31, 138, 257, 102, ILI9341_YELLOW);

  // Setup audio shield.
  AudioMemory(12);
  audioShield.enable();
  audioShield.inputSelect(myInput);
  InputAmp.gain(0, Gain);
  FFT.windowFunction(AudioWindowHanning256);
  FFT.averageTogether(30);

  // Setup the DDS
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_8MA);
  si5351.set_freq(freq * 100ULL, SI5351_CLK1);
}


void loop()
{
  if (FFT.available())
    UpdateDisplay();

  if (Serial.available() > 0)
  {
    char c = Serial.read();
    switch (c)
    {
      case 'w': Gain = Gain + 10; break;
      case 's': Gain = Gain - 10; break;
    }
    Serial.println(Gain);
    InputAmp.gain(0, Gain);
  }
}


void UpdateDisplay()
{
  int bar = 0;
  int xPos = 0;
  int low = 0;

  // Spectrum
  for (int x = 0; x <= 127; x++)
  {
    WaterfallData[0][x] = abs(FFT.output[x]);
    bar = WaterfallData[0][x];
    if (bar > 100)
      bar = 100;
    tft.drawFastVLine(32 + (xPos * 2), 138 - bar, bar, ILI9341_GREEN); //draw green bar
    tft.drawFastVLine(32 + (xPos * 2), 38, 100 - bar, ILI9341_BLACK);  //finish off with black to the top of the screen
    xPos++;
  }

  // Waterfall
  for (int row = 99; row >= 0; row--)
    for (int col = 0; col <= 127; col++)
    {
      WaterfallData[row][col] = WaterfallData[row - 1][col];

      if (WaterfallData[row][col] >= low + 75)
        tft.drawPixel(32 + (col * 2), 139 + row, ILI9341_RED);

      else if ((WaterfallData[row][col] >= low + 50) && (WaterfallData[row][col] < low + 75))
        tft.drawPixel(32 + (col * 2), 139 + row, ILI9341_MAGENTA);

      else if ((WaterfallData[row][col] >= low + 30) && (WaterfallData[row][col] < low + 50))
        tft.drawPixel(32 + (col * 2), 139 + row, ILI9341_YELLOW);

      else if ((WaterfallData[row][col] >= low + 20) && (WaterfallData[row][col] < low + 30))
        tft.drawPixel(32 + (col * 2), 139 + row, ILI9341_BLUE);

      else if (WaterfallData[row][col] < low + 20)
        tft.drawPixel(32 + (col * 2), 139 + row, ILI9341_BLACK);
    }
}


void SendFrequency()
{
  si5351.set_freq(freq * 100ULL, SI5351_CLK1);
}

1 comment:

  1. This comment has been removed by a blog administrator.

    ReplyDelete

Note: only a member of this blog may post a comment.