Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 2 1 2 LastLast
Results 1 to 25 of 38

Thread: High frequency square wave output

  1. #1
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    321

    High frequency square wave output

    I was wondering whether it would be possible to produce a high frequency square wave output (say in the range of 10kHz to 10MHz) with the Teensy 3.6. which is adjustable in frequency.

    GOAL:
    * a minimum-hardware software defined radio [SDR] with:
    * Teensy as local oscillator (square wave: maybe from 10kHz to 10 MHz (or higher, if feasible ;-) )
    * one IC mixer (direct conversion) mixing the RF signal with the Teensy produced LO signal down to audio baseband
    * Teensy built-in ADC sampling the audio baseband signal at a sample rate of 8 or 16kHz
    * Teensy DSP: producing IQ signals from the ADC mono input
    * DSP demodulation running in the Teensy
    * Teensy DAC output

    The only external hardware would be one mixer IC (and some Rs and Cs for antialiasing and bypassing) and a buffer amp after the DAC for headphones.

    The internal ADC and DAC would be set at a speed of 16ksps or 8ksps.

    Now, my question would be:

    Under these circumstances, would there be a possibility for the Teensy to produce a square wave with a duty cycle of 50%
    adjustable in frequency from about 10Khz to 10MHz? That would eliminate the need for an external local oscillator for the mixer input. I would not need a sine, a square would be sufficient.

    Maybe with the PWM functionality or the FrequencyTimer2 library?

    Would be nice if somebody could point me in the right direction or provide a link (or tell me that this is a naive question and impossible to do with the Teensy :-))

    All the best,

    Frank DD4WH
    Last edited by DD4WH; 09-10-2018 at 01:45 PM.

  2. #2
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,069
    Should be doable with one of the FTMs, directly writing to the MOD and Channel compare value register.
    What you need to know is the internal system clock frequency F_BUS which is for example 60MHz in a Teensy 3.6 running at 180MHz. Since you need a PWM output with a 50/50 duty cycle, the MOD value has to be a even number between 2 and 65534. For a given desired output frequency f0, divide F_BUS by f0 and take the closest even integer and take it as FTM MOD value and set the channel compare register to MOD/2 which is MOD >>1.
    Example: f0=15kHz; mod=60MHz/15kHz=4000, channel compare value (Register depends on your selected pin) =2000 and you are done.

  3. #3
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    321
    Theremingenieur,

    thanks a lot for your quick response with an example!

    I have another two questions:

    * is there example code to modify the FTMs? Do I need to define an ISR for that?
    * have I understood it right, that not all frequencies can be programmed, but only those where F_BUS / f0 is an even integer? That would mean, 10MHz is possible with FTM MOD == 6, but not 12MHz, because MOD would have to be 2.5
    that would mean, one could not tune the radio to all Rx frequencies, but only to a few selected ones? AM radio could be feasible then (500 - 1800kHz receive frequency, but not shortwave 3-30MHz). Maybe I should think about an external programmable oscillator then, eg. the Si5351

  4. #4
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,069
    No need for an ISR, if you can’t figure it out by looking at the analogWrite() and analogWriteFrequency() code in the core files, I could write the needed code for you.
    You can use 32767 different fixed frequencies between ca. 900Hz and 30MHz with this simple zero cost approach. I say zero cost because the FTM will run autonomously without eating one single CPU cycle. Due to that integer division nature, continuous tuning is definitively not possible, but such low frequencies as you required (10kHz to 10MHz) look to me like IFs which would allow a fixed frequency approach, since almost no more broadcasting of public interest seems to happen in these frequency bands nowadays.

    At least in France where I live and in the neighbored Germany and Switzerland, everything below analog FM radio (87.5MHz) seems deserted.

  5. #5
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,069
    Thinking further in IF terms, but with still more coarse steps, one could think of coupling 2 channels of the same FTM to get 2 outputs with 90 phase shift, still without any processor load. But that would require a even channel compare register value and thus a mod value which had to be a multiple of 4 which gives “only” 16382 different frequencies in the range cited above.

  6. #6
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,069
    Still just thinking out loud, another approach could be mis-using one of the I2S modules which have fractional dividers and thus would allow to generate square waves in a linear frequency raster. The price for that luxury would be that you’d get just a single frequency without the 90 phase shift option.

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,691
    With Teensy 3.6, no need to fiddle with the timer registers. All you need is this:

    Code:
    void setup() {
      analogWriteFrequency(3, 10000000);
      analogWrite(3, 128);
    }
    
    void loop() {
    }
    This does depend on F_BUS being a multiple of 20 MHz. On 3.5 & 3.6 it defaults to 60 MHz. At other speeds or on Teensy 3.2 F_BUS is other frequencies like 48 MHz.

    Tried it just now on a Teensy 3.6. Here's the waveform (using a short wire and ground lead clip - not the best probing for a high speed signal so you see a little ringning due to the leads, but quick and easy to connect)

    Click image for larger version. 

Name:	file.png 
Views:	31 
Size:	32.4 KB 
ID:	14706

  8. #8
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    321
    Paul & Theremingenieur, thank you very much!

    the whole thing is (so far) just a quick idea and thoughts on whether such a very simple SDR would be possible (but its a nice simplistic goal: just the Teensy and one other active component ;-)).

    Promising! I did not think it would be that simple to have the Teensy produce RF signals ;-)!

    I tested 10MHz, 5Mhz, 6MHz and 1621.5kHz, unfortunately as you explained there are large gaps in between the possible frequency values.

    Here you can see the 1621.5kHz signal and its even and odd harmonics on my direct-sampling-SDR (I used a 15cm wire on pin 3 as a transmit antenna):

    Click image for larger version. 

Name:	FMT1621_5.JPG 
Views:	16 
Size:	113.5 KB 
ID:	14707

    So far, so good. So this could theoretically work as an SDR Receiver for selected frequencies (only even divides of 60MHz). Good for a simple WWV time signal receiver at 10MHz or the Hawaiian WWVH at 15MHz.

    But it would be nice to be able to have general coverage: the frequency steps could be as wide as 24kHz or even 48kHz, depending on the sample rate for the audio base band. We could use a tunable software LO to mix it to baseband again inside the 48kHz window.

    Could you elaborate a little more on the "misuse of one of the I2S modules"?

    All the best,

    Frank DD4WH

  9. #9
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    2,808
    have you tried adding this to your sketch and re-testing?

    Code:
    void yield(void) {};

  10. #10
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    321
    Yes, I just did. Not sure what this should alter. Could you explain?

    I did not observe any difference, tested 6MHz and 1621.5kHz output.
    Code:
    void setup() {
      //analogWriteFrequency(3, 10000000);
      //analogWriteFrequency(3, 1621500);
      //analogWriteFrequency(3, 6000000);
      analogWriteFrequency(3, 6090000);
      analogWrite(3, 128);
    }
    
    void yield(void) {};
    
    void loop() {
    }

  11. #11
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,069
    The idea is to use only the master clock and/or bit clock generation of the I2S module without really transmitting I2S data. The i2s clock generator allows to take either F_PLL (often identical to F_CPU) or F_BUS and to do a f * x / y operation within a relatively wide range. I’ve not the reference manual at hands for the moment (sitting on the sofa with my iPad) but imagine starting from 60 MHz f_bus and starting with a y=2500 divider which gives 24kHz, then you could choose x as a multiplier from 1 to 255, thus covering a range from 24kHz to 6.120MHz

  12. #12
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    321
    Theremingenieur, would that be possible to do independently of the ADC and DAC sample rate?

  13. #13
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,069
    Yes, the I2S clock generation is independent and can run independently without impact on other modules and without eating CPU cycles.

  14. #14
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,069
    By the way, the long Theremingenieur is a surname given to me by other people. I’m perfectly fine with being called by my first name, Thierry.

  15. #15
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    321
    Click image for larger version. 

Name:	simplistic teensy SDR DD4WH.jpg 
Views:	34 
Size:	61.4 KB 
ID:	14708first idea on hardware (upper half) and software (lower half) setup
    the idea to use the MCP2036 is taken from Martin Ossmann, Funkamateur 06/2018

  16. #16
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    321
    everything below analog FM radio (87.5MHz) seems deserted.
    Thierry, if you switch on your AM radio right now, you will hear a vast lot of medium wave stations from southern Europe: Spain, Italy, Romania, also JilFM from Algeria on 531kHz: they play music all night, mostly cool stuff. Your are right: french and german stations have all closed down, but there is still a lot to hear (at night), even US and south american stations can be heard around dawn here in Central Europe, but not every day . . .

  17. #17
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,069
    Looks simple and efficient.

  18. #18
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    321
    The idea is to use only the master clock and/or bit clock generation of the I2S module without really transmitting I2S data.
    OK, I will have a look into the I2S audio lib code in the next days, thanks very much!

  19. #19
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,691
    The MCLK generator doesn't give a square wave, except for a very limited range.

  20. #20
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    321
    Hi Paul,

    MCLK generator doesn't give a square wave, except for a very limited range.
    I am not sure how to interpret this. But I am totally unexperienced with the details of the I2S protocol.

    All figures I have seen of clock SCK (Wikipedia and the Philips I2S bus specification), however, show square waves. My interpretation would be: if SCK is a square, theoretically also MCLK should be a square. So could you point me to a reference where I can read more about waveforms and I2S in the Teensy 3.6?

  21. #21
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,069
    The master clock is not guaranteed to be perfectly symmetrical with 50% duty cycle, due to the fractional frequency division. That’s why I’d tend to make the master clock (as usual in I2S configurations) 2 or 4 times higher and then use the bit clock which is the master clock divided by 2 or 4 and which should, after this division, be with a perfect duty cycle.

  22. #22
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    321
    Thierry,

    OK, I understand:

    * MCK = MCLK is the master clock which is the fastest clock, but does not provide exact 50% duty cycles, but is "freely" adjustable in frequency because you can use fractional dividers

    * SCK is the bit clock, which is derived from an integer divide of the MCLK, so has a better duty cycle

    So, is my interpretation correct, that the highest setting for MCLK would be 60MHz as in the FTM? That would mean an output of 30MHz max SCK with a divide-by-2 (ideal for RF reception) and 15MHz max SCK with a divide-by-4 (misses some of the upper bands, but not really important, because it remains to be seen whether the cheap MCP2036 sets a hardware upper frequency limit here: reported as about 10MHz)

    Now, the only thing I have to do for a first test is to figure out how to set the I2S clocks, will have a look into the code in i2s.h in the audio lib and try to figure out whats going on there!

    Thanks a lot for your help so far!

    All the best,

    Frank DD4WH

  23. #23
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,069
    If I remember well, but you’d have to look up that in the reference manual, there is a limit of 25 or 30MHz for the master clock.

  24. #24
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    321
    I had a look into the reference manual . . . (> 2200 pages, thats a lot ;-)) and did not find a word about max frequency.

    Inspired by this post (https://forum.pjrc.com/threads/38753...l=1#post182458) I found in the technical datasheet page 18, which says:

    f I2S_MCLK max is 12.5MHz
    f I2S_BCLK max is 4 MHz

    on page 66 however, it says about the MIN cycle time (and the figure 31 clearly shows that cycle time means one full cycle):

    MCLK 40nsec which is 25MHz
    BCLK 80nsec which is 12.5MHz

    So, I would hope that BCLK would provide a nice 50% duty cycle square up to 12.5MHz and I could use MCLK for frequencies from 12.5 - 25MHz

    Up to now, I did not figure out exactly how to set BCLK, but could it be that only this needs to be done once to set and enable MCLK frequency generation?:

    Code:
    // enable MCLK output
    I2S0_MCR = I2S_MCR_MICS(MCLK_SRC) | I2S_MCR_MOE;
    while (I2S0_MCR & I2S_MCR_DUF);
    I2S0_MDR = I2S_MDR_FRACT((MCLK_MULT-1)) | I2S_MDR_DIVIDE((MCLK_DIV-1));
    I would expect the signal at pin 11 (I2S0_MCLK), lets see . . . I will try

  25. #25
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    321
    It works:

    Code:
    /*************************************************************
     * 
     *  Use I2S transmitter to produce an RF frequency
     *  as a local oscillator for a minimum hardware SDR
     *  
     *  compile with 180MHz F_CPU
     *  
     *  DD4WH 2018-09-11
     * 
     *  GNU GPLv3
     * 
     *************************************************************/
    
      #include "kinetis.h"
    
      // pin 11 MCLK
      // pin 9 BCLK
    
      #define MCLK_MULT   9
      #define MCLK_DIV    99
      #define MCLK_SRC    0
      #define BCLK_DIV    4   // has to be even !
      
    // MCLK = MULT * 180MHz / DIV
    // BCLK = MCLK / 4
    
    // mult 16 div 255
    // MCLK = 11294k
    // BCLK = 2823.5k
    
    // mult 10 and div 255 = 7059k
    // mult 12 and div 255 = 8470k
    // mult 9 and div 99 = MCLK 16363.6kHz, BCLK 12272.6kHz ???
    // mult 10 and div 100 = MCLK 18MHz
    // mult 15 and div 100 = MCLK 27MHz
    // mult 100 and div 150 = BCLK 3MHz
    
    
      void setup() 
      {
        config_i2s();
        start_i2s();
      }
    
      void config_i2s(void)
      {
      // abbreviations taken from kinetis.h
      // System Clock Gating Control Register 6
          SIM_SCGC6 |= SIM_SCGC6_I2S;
    
          // this enables the I2S master clock
          I2S0_MCR = I2S_MCR_MICS(MCLK_SRC) | I2S_MCR_MOE;
    
          // wait until divider update is ready!?
          // I2S_MCR_DUF: Divider Update Flag
          while (I2S0_MCR & I2S_MCR_DUF);
    
          // F_CPU = 180MHz
          // MCLK = MULT * F_CPU / DIV
          // change mult and div to control MCLK frequency
          // SAI MCLK Divide Register
          I2S0_MDR = I2S_MDR_FRACT((MCLK_MULT-1)) | I2S_MDR_DIVIDE((MCLK_DIV-1));
    
          // I2S0_TCR2: SAI Transmit Configuration 2 Register 
          // I2S_TCR2_MSEL: MCLK select, 0=bus clock, 1=I2S0_MCLK   
          // I2S_TCR2_SYNC: 0=async 1=sync with receiver
          // I2S_TCR2_BCP: Bit clock polarity
          // I2S_TCR2_BCD: Bit clock direction
          // I2S_TCR2_DIV --> Bit clock divide by (DIV+1)*2, 
          //     if 1, divide-by-4; if 0, divide-by-2
          I2S0_TCR2 = I2S_TCR2_SYNC(0) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1)
                    | I2S_TCR2_BCD | I2S_TCR2_DIV(BCLK_DIV / 2 - 1);
    
          // Pin Mux Control
          CORE_PIN11_CONFIG = PORT_PCR_MUX(6); // pin 11, PTC6, I2S0_MCLK
          CORE_PIN9_CONFIG  = PORT_PCR_MUX(6); // pin  9, PTC3, I2S0_TX_BCLK
      }
    
      void start_i2s(void)
      {
        // I2S_TCSR_TE: Transmitter Enable
        // I2S_TCSR_BCE: Bit Clock Enable
          I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE; // TX clock enable
      }
    
    
      void loop() 
      {
        
      }
    It would be nice of somebody could have a look at the code whether I am missing something.

    I could observe MCLK signal at pin 11 as expected and BCLK at pin 9, again observed with a wire antenna at the pins and using a direct sampling SDR as a spectrum analyser.

    It seems MCLK can be produced up to at least 36MHz.

    I observe some strange frequencies in BCLK when I use higher frequencies, but I have to test some more.

    * Is there some kind of algorithm that is able to calculate the multipliers and dividers with a given MCLK frequency?
    * is there an upper limit for MCLK_MULT and MCLK_DIV?

    All the best,

    Frank DD4WH

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •