Discussion about a simple way to change the sample-rate

I've just got a test version of the Talkie library working directly with the Audio board by setting the sampling rate to 8000Hz.

Pete
 
Nice work, Talkie is fun - and yes 8KHz, with it running on a 125us timer, makes sense.

Now if only there were a way to expand the talkie sound database. The code that did it was Windows XP era and lost it seems.
 
The PT8211 "driver" uses oversampling - so, yes, higher samplerates are possible.
I'll extend the table (and see what I can do with the SGTL5000 Settings)
 
I've updated the table:

- there was little bug
- added more frequencies, up to 192KHz.

All freqs should work now (hopefully).
 
Last edited:
The PT8211 "driver" uses oversampling - so, yes, higher samplerates are possible.
I'll extend the table (and see what I can do with the SGTL5000 Settings)

Frank,

I am very excited to hear this, because that would enable the building of a bat detector, as chip suggested ! Also, I am trying to build up a floating point audio chain for a software defined radio that uses different decimation/interpolation factors depending on the desired userdefined bandwidth of the signal or for heavy processing in digital modes. I could throw away the decimation/interpolation and just set the desired sample rates, as Pete suggested. So, for these two applications the setting of the sampling rate seems perfectly suited! However, I have a few questions:

1. Is it possible to change the sample rate while the loop runs or do I have to restart the Teensy?

2. I am a bit confused about the sample rate that I would have to use for the design of the filter coefficients ;-). I do not use the audio lib for the audio processing except for one queue object for input and one queue object for output. All the audio processing is done in float32_t by directly manipulating the block samples. So, if I set the sample rate to 8ksps, the samples would come from the audio lib queue object with that rate, i.e. one block of 128 samples every 16msec (128/8000 = 0.016) ? So, all my filter coeffs would have to be calculated for 8ksps sampling rate, do they?

3. it would be perfect to have the possibility to use 96ksps (or even dream of 192ksps) on the Teensy audio board with the SGTL5000, because then bat detection would be quite easy to do . . . and with 192ksps we could detect the majority of the bats occuring in the wild, with 96ksps (and 48kHz upper limit) bat detection would be limited to a smaller subset of the existing species

Frank

EDIT:
@Frank: our postings crossed, thanks for the higher sample rates! will test that on the Teensy 3.5 with Teensy audio board
 
Last edited:
Hi Frank,

you can change the samplerate at runtime - anytime - but it is better to do it between "blocks"
(use AudioNoInterrupts() )

@all please note, that it will cause problems if you try to use internal ADC/DAC and I2S in the same sketch - the samplerates do not match in most cases.
All other combinations should work flawlessly.
 
Tested the settings of the sample rates for my simple queue-In - queue-out-sketch (HERE, but without all the decimation/interpolation and without filtering, just the queue in and out) on Teensy 3.5 with Teensy audio board:

WORKS, wow!!! 8000, 11025, 16000, 22050, 32000, 44100, 44117.64706, 48000 all work very nicely, although I would have to check audio quality and the need for additional low pass filtering.

DOES NOT WORK: from 88200 upwards (tested every possible setting): artefacts = stuttering audio, it gets worse with higher sample rate. However, the Teensy seems to accept the higher sample rate, because the spectrum analyser gets faster, the faster the sample rate is, i.e. the blocks get pushed through faster with faster sample rate !?

Frank
 
..would be great to see a workin sketch (+schematics??) for "bat detection".

In summer, sometimes i see bats flying in my garden - would be so cool to hear them !
 
Hi Frank - my mic in - out sketch from post#14 works flawlessly up to 192KHz.

Perhaps theres is something wrong with your sketch ? Remember, that the whole lib runs (more than!) 4 times faster @ 192kHz
Or, it might be, that is simply too slow.. :-(
 
Sorry, I see that I had to clean my sketch from all the filter garbage, I am using this sketch now:

Code:
/***********************************************************************
 * 
 * Test higher/lower sample rates
 * that Frank B has implemented
 * 
 * https://forum.pjrc.com/threads/38753-Discussion-about-a-simple-way-to-change-the-sample-rate/page2
 * 
 * Frank DD4WH 2016_10_31
 * 
 *  first experiment 
 */

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <Metro.h>
#include "font_Arial.h"
#include <ILI9341_t3.h>

#define BACKLIGHT_PIN 0

#define TFT_DC      20
#define TFT_CS      21
#define TFT_RST     32  // 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);

Metro five_sec=Metro(2000); // Set up a 0.5 second Metro

// this audio comes from the codec by I2S2

AudioInputI2S            i2s_in; 
           
AudioRecordQueue         Q_in_L;    
AudioRecordQueue         Q_in_R;    

AudioPlayQueue           Q_out_L; 
AudioPlayQueue           Q_out_R; 
//AudioAnalyzeFFT256  myFFT;
AudioOutputI2S           i2s_out;           
AudioConnection          patchCord1(i2s_in, 0, Q_in_L, 0);
AudioConnection          patchCord2(i2s_in, 1, Q_in_R, 0);
//AudioConnection      patchCord5(Q_out_R,0,myFFT,0); 
AudioConnection          patchCord3(Q_out_L, 0, i2s_out, 1);
AudioConnection          patchCord4(Q_out_R, 0, i2s_out, 0);
AudioControlSGTL5000     sgtl5000_1;     //xy=265.212

int idx_t = 0;
int idx = 0;
int64_t sum;
float32_t mean;
int n_L;
int n_R;
long int n_clear;

int peak[512];
int barm[512];

ulong samp_ptr = 0;
bool FFT_state = false;

const int myInput = AUDIO_INPUT_LINEIN;

// We're only processing one buffer at a time so the
// number of samples is fixed at 128
#define BUFFER_SIZE 128

float32_t float_buffer_L [BUFFER_SIZE];
float32_t float_buffer_R [BUFFER_SIZE];
float32_t float_buffer_L_3 [BUFFER_SIZE];
float32_t float_buffer_R_3 [BUFFER_SIZE];

void setup() {
  Serial.begin(115200);
  delay(1000);

  // Audio connections require memory. and the record queue
  // uses this memory to buffer incoming audio.
  AudioMemory(100);

  // Enable the audio shield. select input. and enable output
  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(myInput);
  sgtl5000_1.volume(0.5);
  sgtl5000_1.adcHighPassFilterDisable(); // does not help too much!
  setI2SFreq (192000);

  pinMode( BACKLIGHT_PIN, OUTPUT );
  analogWrite( BACKLIGHT_PIN, 1023 );

  tft.begin();
  tft.setRotation( 3 );
  tft.fillScreen(ILI9341_BLACK);
  tft.setCursor(10, 1);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE);
  tft.setFont(Arial_14);
  tft.print("Floating point audio processing");


 /****************************************************************************************
 *  begin to queue the audio from the audio library
 ****************************************************************************************/
    delay(100);
    Q_in_L.begin();
    Q_in_R.begin();    
} // END SETUP


int16_t *sp_L;
int16_t *sp_R;

void loop() {
 
 elapsedMicros usec = 0;
/**********************************************************************************
 *  Get samples from queue buffers
 **********************************************************************************/

    // this is supposed to prevent overfilled queue buffers
    if (Q_in_L.available() > 3 || Q_in_R.available() > 3) {
      Q_in_L.clear();
      Q_in_R.clear();
      n_clear ++; // just for debugging to check how often this occurs
    }
    // is there at least one buffer in each channel available ?
    if (Q_in_L.available() >= 1 && Q_in_R.available() >= 1)
    {   
    sp_L = Q_in_L.readBuffer();
    sp_R = Q_in_R.readBuffer();

      // convert to float
     arm_q15_to_float (sp_L, float_buffer_L, BUFFER_SIZE); // convert int_buffer to float 32bit
     arm_q15_to_float (sp_L, float_buffer_R, BUFFER_SIZE); // convert int_buffer to float 32bit
     Q_in_L.freeBuffer();
     Q_in_R.freeBuffer();

/**************************************************************************
 * From here, all the 32 bit float audio processing can start
 * ************************************************************************

      
/**************************************************************************
 * END of 32 bit float audio processing
 * ************************************************************************
 */
    sp_L = Q_out_L.getBuffer();
    sp_R = Q_out_R.getBuffer();
    arm_float_to_q15 (float_buffer_L, sp_L, BUFFER_SIZE); 
    arm_float_to_q15 (float_buffer_R, sp_R, BUFFER_SIZE); 
      Q_out_L.playBuffer(); // play it !
      Q_out_R.playBuffer(); // play it !

/**********************************************************************************
 *  PRINT ROUTINE FOR ELAPSED MICROSECONDS
 **********************************************************************************/
 
      sum = sum + usec;
      idx_t++;
      if (idx_t > 1000) {
          tft.fillRect(240,50,90,20,ILI9341_BLACK);   
          tft.setCursor(240, 50);
          mean = sum / idx_t;
          tft.print (mean);
          Serial.print (mean);
          Serial.print (" microsec for 2 stereo blocks    ");
          Serial.println();
          idx_t = 0;
          sum = 0;
         
      }

     }
/**********************************************************************************
 *  PRINT ROUTINE FOR AUDIO LIBRARY PROCESSOR AND MEMORY USAGE
 **********************************************************************************/
          if (five_sec.check() == 1)
    {
      Serial.print("Proc = ");
      Serial.print(AudioProcessorUsage());
      Serial.print(" (");    
      Serial.print(AudioProcessorUsageMax());
      Serial.print("),  Mem = ");
      Serial.print(AudioMemoryUsage());
      Serial.print(" (");    
      Serial.print(AudioMemoryUsageMax());
      Serial.println(")");
      Serial.print("Cleared the audio buffer ");    
      Serial.print(n_clear); Serial.println (" times. ");

/*      tft.fillRect(100,120,200,80,ILI9341_BLACK);
      tft.setCursor(10, 120);
      tft.setTextSize(2);
      tft.setTextColor(ILI9341_WHITE);
      tft.setFont(Arial_14);
      tft.print ("Proc = ");
      tft.setCursor(100, 120);
      tft.print (AudioProcessorUsage());
      tft.setCursor(180, 120);
      tft.print (AudioProcessorUsageMax());
      tft.setCursor(10, 150);
      tft.print ("Mem  = ");
      tft.setCursor(100, 150);
      tft.print (AudioMemoryUsage());
      tft.setCursor(180, 150);
      tft.print (AudioMemoryUsageMax());
     */ 
      AudioProcessorUsageMaxReset();
      AudioMemoryUsageMaxReset();
    }
//   spectrum();
}

/*
 void spectrum() { // spectrum analyser code by rheslip - modified
     if (myFFT.available()) {
    int scale;
    scale = 2;
  for (int16_t x=2; x < 100; x+=2) {

     int bar = (abs(myFFT.output[x]) * scale);
     if (bar >180) bar=180;
     // this is a very simple IIR filter to smooth the reaction of the bars
     bar = 0.2 * bar + 0.8 * barm[x]; 
     if (bar > peak[x]) peak[x]=bar;
//     tft.drawFastVLine(x, 210-bar,bar, ILI9341_PURPLE);
     tft.drawFastVLine(x*2+10, 210-bar,bar, ILI9341_PINK);

     tft.drawFastVLine(x*2+10, 20, 210-bar-20, ILI9341_BLACK);    

     tft.drawPixel(x*2+10,209-peak[x], ILI9341_YELLOW);

     if(peak[x]>0) peak[x]-=1;
     barm[x] = bar;
  }
  } //end if

   } // end void spectrum
*/

void setI2SFreq(int freq) {
  typedef struct {
    uint8_t mult;
    uint16_t div;
  } tmclk;

  const int numfreqs = 14;
  const int samplefreqs[numfreqs] = { 8000, 11025, 16000, 22050, 32000, 44100, 44117.64706 , 48000, 88200, 44117.64706 * 2, 96000, 176400, 44117.64706 * 4, 192000};

#if (F_PLL==16000000)
  const tmclk clkArr[numfreqs] = {{16, 125}, {148, 839}, {32, 125}, {145, 411}, {64, 125}, {151, 214}, {12, 17}, {96, 125}, {151, 107}, {24, 17}, {192, 125}, {127, 45}, {48, 17}, {255, 83} };
#elif (F_PLL==72000000)
  const tmclk clkArr[numfreqs] = {{32, 1125}, {49, 1250}, {64, 1125}, {49, 625}, {128, 1125}, {98, 625}, {8, 51}, {64, 375}, {196, 625}, {16, 51}, {128, 375}, {249, 397}, {32, 51}, {185, 271} };
#elif (F_PLL==96000000)
  const tmclk clkArr[numfreqs] = {{8, 375}, {73, 2483}, {16, 375}, {147, 2500}, {32, 375}, {147, 1250}, {2, 17}, {16, 125}, {147, 625}, {4, 17}, {32, 125}, {151, 321}, {8, 17}, {64, 125} };
#elif (F_PLL==120000000)
  const tmclk clkArr[numfreqs] = {{32, 1875}, {89, 3784}, {64, 1875}, {147, 3125}, {128, 1875}, {205, 2179}, {8, 85}, {64, 625}, {89, 473}, {16, 85}, {128, 625}, {178, 473}, {32, 85}, {145, 354} };
#elif (F_PLL==144000000)
  const tmclk clkArr[numfreqs] = {{16, 1125}, {49, 2500}, {32, 1125}, {49, 1250}, {64, 1125}, {49, 625}, {4, 51}, {32, 375}, {98, 625}, {8, 51}, {64, 375}, {196, 625}, {16, 51}, {128, 375} };
#elif (F_PLL==180000000)
  const tmclk clkArr[numfreqs] = {{46, 4043}, {49, 3125}, {73, 3208}, {98, 3125}, {183, 4021}, {196, 3125}, {16, 255}, {128, 1875}, {107, 853}, {32, 255}, {219, 1604}, {214, 853}, {64, 255}, {219, 802} };
#elif (F_PLL==192000000)
  const tmclk clkArr[numfreqs] = {{4, 375}, {37, 2517}, {8, 375}, {73, 2483}, {16, 375}, {147, 2500}, {1, 17}, {8, 125}, {147, 1250}, {2, 17}, {16, 125}, {147, 625}, {4, 17}, {32, 125} };
#elif (F_PLL==216000000)
  const tmclk clkArr[numfreqs] = {{32, 3375}, {49, 3750}, {64, 3375}, {49, 1875}, {128, 3375}, {98, 1875}, {8, 153}, {64, 1125}, {196, 1875}, {16, 153}, {128, 1125}, {226, 1081}, {32, 153}, {147, 646} };
#elif (F_PLL==240000000)
  const tmclk clkArr[numfreqs] = {{16, 1875}, {29, 2466}, {32, 1875}, {89, 3784}, {64, 1875}, {147, 3125}, {4, 85}, {32, 625}, {205, 2179}, {8, 85}, {64, 625}, {89, 473}, {16, 85}, {128, 625} };
#endif

  for (int f = 0; f < numfreqs; f++) {
    if ( freq == samplefreqs[f] ) {
      while (I2S0_MCR & I2S_MCR_DUF) ;
      I2S0_MDR = I2S_MDR_FRACT((clkArr[f].mult - 1)) | I2S_MDR_DIVIDE((clkArr[f].div - 1));
      return;
    }
  }
}

I see that we would have to open another thread for bat detection, will do that the next days ;-)

Frank

EDIT: perhaps Teensy 3.5 is too slow and it runs on the Teensy 3.6 ? EDIT EDIT: no, it is fast enough
EDIT EDIT: changed the script to a working script!
 
Last edited:
WOW, it works up to 192ksps (Teensy 3.5 & Teensy audio board)!

It was my fault, had the spectrum analyser still in the script and that used the audio library FFT256 object, which horribly slowed down the whole thing!

Now the bat detector is within reach ;-). Those small electret mics should be able to pick up a lot of ultrasound, will dig into that later and open up a bat detector thread.

Thanks Frank for that very very nice thing! Will test further in the next days and report here.
 
Great !
I've commented out the display only - works.
But a 3.6 is better !

The output @ 192MHz is:
Code:
Proc = 5.58 (6.22),  Mem = 5 (7) Cleared the audio buffer 0 times.
 
Great !
I've commented out the display only - works.
But a 3.6 is better !

yes, I agree, I will order a 3.6 today ;-). For a bat detector, we would certainly need FFTs and a display. It would be extremely cool, if we could use the Teensy + audio board without further hardware (except an electret mic) for bat detection. Exciting . . .

Frank
 
Hm. I wonder why 192KHz works...

I just read in the Datasheet that the SGTL5000 is specified up to 96KHz...
The SGTL5000 can accept an external standard master clock at a multiple of the sampling frequency (i.e. 256*Fs, 385*Fs, 512*Fs). In addition it can take non-standard frequencies and use the internal PLL to derive the audio clocks. The device supports 8.0 kHz, 11.025 kHz, 12 kHz, 16 kHz, 22.05 kHz, 24 kHz, 32 kHz, 44.1kHz, 48 kHz, 96 kHz sampling frequencies.

Can someone measure if the 192KHz input is ok ? (I don't have the equipment for such measurings)
In addition, the PLL-Config is wrong at the moment...

But..if it works... never change a winning team ;-)

Perhaps it is better to switch to the internal ADC for bat-detection.

Edit:
I wonder, what the internal filters do..?
 
Last edited:
Ah..ok... reading helps :) the PLL is not used :O)
So, as i understand it, we do not need to change the SGTL5000-Configration ?
(That's better anyway..we are way out of spec...double..)

LOL i never thought that i ever overclock a soundchip... unintentionally.
 
Last edited:
Here's the line for 168MHz:

Code:
#elif (F_PLL==168000000)
  const tmclk clkArr[numfreqs] = {{32, 2625}, {21, 1250}, {64, 2625}, {21, 625}, {128, 2625}, {42, 625}, {8, 119}, {64, 875}, {84, 625}, {16, 119}, {128, 875}, {168, 625}, {32, 119}, {189, 646} };
 
Frank B: It appears that the volume control for I2S output (SGTL5000) doesn't work with some clock speeds. Of the five speeds I've checked, 8000 and 11025 don't work and 16000 22050 and (of course) 44100 do work.
Below is a simple test case. Try it as-is first to verify the volume control works. Then uncomment the setI2SFreq call.

Pete

Code:
// This example code is in the public domain.
// I've added a test for different sampling rates
// and allow passthru of line-in instead of mic

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>


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


AudioInputI2S            audioInput;
AudioOutputI2S           audioOutput;

AudioConnection          patchCord1(audioInput, 0, audioOutput, 0);
AudioConnection          patchCord2(audioInput, 0, audioOutput, 1);

AudioControlSGTL5000     sgtl5000_1;


#include <Arduino.h>

// From FrankB - brilliant!
void setI2SFreq(int freq)
{
  typedef struct {
    uint8_t mult;
    uint16_t div;
  } __attribute__((__packed__)) tmclk;

  const int numfreqs = 8;
  const int samplefreqs[numfreqs] = { 8000, 11025, 16000, 22050, 32000, 44100, 44117 , 48000 };

#if (F_PLL==16000000)
  const tmclk clkArr[] = {{16, 125}, {148, 839}, {32, 125}, {145, 411}, {64, 125}, {151, 214}, {12, 17}, {96, 125} };
#elif (F_PLL==72000000)
  const tmclk clkArr[] = {{32, 1125}, {49, 1250}, {64, 1125}, {49, 625}, {128, 1125}, {98, 625}, {8, 51}, {64, 375} };
#elif (F_PLL==96000000)
  const tmclk clkArr[] = {{8, 375}, {60, 2041}, {16, 375}, {120, 2041}, {32, 375}, {147, 1250}, {2, 17}, {16, 125} };
#elif (F_PLL==120000000)
  const tmclk clkArr[] = {{32, 1875}, {29, 1233}, {64, 1875}, {89, 1892}, {128, 1875}, {89, 946}, {8, 85}, {64, 625} };
#elif (F_PLL==144000000)
  const tmclk clkArr[] = {{16, 1125}, {40, 2041}, {32, 1125}, {49, 1250}, {64, 1125}, {49, 625}, {4, 51}, {32, 375} };
#elif (F_PLL==180000000)
  const tmclk clkArr[] = {{9, 791}, {31, 1977}, {37, 1626}, {62, 1977}, {73, 1604}, {107, 1706}, {16, 255}, {128, 1875} };
#elif (F_PLL==192000000)
  const tmclk clkArr[] = {{4, 375}, {30, 2041}, {8, 375}, {60, 2041}, {16, 375}, {120, 2041}, {1, 17}, {8, 125} };
#elif (F_PLL==216000000)
  const tmclk clkArr[] = {{17, 1793}, {17, 1301}, {34, 1793}, {49, 1875}, {49, 1292}, {98, 1875}, {8, 153}, {64, 1125} };
#elif (F_PLL==240000000)
  const tmclk clkArr[] = {{16, 1875}, {24, 2041}, {32, 1875}, {29, 1233}, {64, 1875}, {89, 1892}, {4, 85}, {32, 625} };
#endif

  for (int f = 0; f < numfreqs; f++) {
    if ( freq == samplefreqs[f] ) {
      while (I2S0_MCR & I2S_MCR_DUF) ;
      I2S0_MDR = I2S_MDR_FRACT((clkArr[f].mult - 1)) | I2S_MDR_DIVIDE((clkArr[f].div - 1));
      return;
    }
  }
}


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

  AudioMemory(8);

  sgtl5000_1.enable();

  sgtl5000_1.inputSelect(myInput);
  // micgain for the MEMS microphone with 67dB preamp should be zero
  // micgain for my Sony microphone with no preamp should be 26-30
  sgtl5000_1.micGain(0);

  sgtl5000_1.volume(0.6);
//  setI2SFreq(8000);
}


void loop(void)
{
  static int volume;
  int n = analogRead(15);
  if (n != volume) {
    volume = n;
    sgtl5000_1.volume(n / 1023.);
  }

}
 
Hi,

perhaps we can tweak the things a bit.
I have no time this evening, unfortunately.

The SGTL uses a "MCLK", which is, basically, the samplefreq multiplied with a factor.

<snip from PT8211>
Code:
    #if defined(AUDIO_PT8211_OVERSAMPLING)
        I2S0_TCR2 = I2S_TCR2_SYNC(0) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(0);
    #else
        I2S0_TCR2 = I2S_TCR2_SYNC(0) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(3);
    #endif

The PT8211 does not use the MCLK, so it was possible to just remove this setting (I2S_TCR2_DIV)
Maybe there is a way to use a lower multiplier for the SGTL5000 ? In this case, it needs some other settings - maybe take a look at the datasheet, and the SGTL500-Control.
 
Oh, I did not realise that, although I have been using the sample rate code heavily in the last days for the bat detector. But I used MIC GAIN for volume control, NOT the SGTL5000 volume.

Another issue with 8000 is a hiss noise (much higher than the possible frequency in that sample rate)
The same sounding hiss noise is present in 192000.
It occurs in none of these other sample rates: 11, 16, 22, 32, 44.1, 48, 96, 176

Frank DD4WH
 
I tried a few other F_CPU values and they don't change anything. BTW I was using 180MHz for the original tests.
I'll try to dig through the manual today.

Pete
 
Hmm, can you explain that a bit more in detail for a non-specialist ? ;-).

Where and how can I change F_CPU? Is that the CPU speed that I can choose in Teensyduino before I build the code?

And how can I calculate whether it is an optimal divider?

A link would be fine and sufficient, thanks in advance! Sorry if that is a very silly question . . .

Frank
 
F_CPU is set during IDE compile under Tools / CPU Speed.

Some multipliers are controlled by F_BUS that is adjustable in Kinetis.h by swapping commented items under the used F_CPU:
Code:
#if (F_CPU == 240000000)
 #define F_PLL 240000000
 #ifndef F_BUS
 #define F_BUS 60000000
 //#define F_BUS 80000000   // uncomment these to try peripheral overclocking
 //#define F_BUS 120000000  // all the usual overclocking caveats apply...
 #endif
 #define F_MEM 30000000
 
Last edited:
Back
Top