Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 19 of 19

Thread: Creating 150khz sine wave

  1. #1
    Junior Member
    Join Date
    Nov 2019
    Posts
    8

    Creating 150khz sine wave

    Hello everybody,
    I am trying to produce a 150 khz sine wave from the teensy 3.6 I understand that this is far greater than the DAC speed according to the spec sheet. I was wondering if this is possible to do with the timers on the teensy 3.6 and has anybody tried ?
    My final application is to produce a Binary FSK transmittion at around 600 bps using just the Teensy 3.6.

  2. #2
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,862
    Sounds like a job for a DDS module, not a microcontroller. Cheap AD9833 module perhaps?

  3. #3
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,862
    Sounds like a job for a DDS module, not a microcontroller. Cheap AD9833 module perhaps?

    Or you could use square wave output and a high-order low-pass filter on the output to kill the harmonics.

  4. #4
    Junior Member
    Join Date
    Nov 2019
    Posts
    8
    Quote Originally Posted by MarkT View Post
    Sounds like a job for a DDS module, not a microcontroller. Cheap AD9833 module perhaps?

    Or you could use square wave output and a high-order low-pass filter on the output to kill the harmonics.

    I understand. Is there anyway to do it natively on the teensy ? maybe with some LPF attached ?

  5. #5
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,862
    I've not played with the T3.6, but I wouldn't be surprized if you can generate suitable square waves from the PWM units in it?

    This thread seems relevant. https://forum.pjrc.com/threads/40241...AC-performance

  6. #6
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,995
    In theory, you could connect resistors in a R-2R ladder or just binary weighted to several pins and write 8 bit numbers to a native port. You'd probably set up a timer to trigger a DMA channel to copy bytes from a buffer to the pins. It would probably look similar to the code in OctoWS2811, except using only 1 DMA channel instead of 3, since you just want to write all the pins once per update rather than 3 times.

    Realistically, you can probably expect to get about 3 to 5 million updates per second using DMA, for about 20 to 33 updates per period of 150 kHz.

    To do this, you'll need to dive into some fairly low-level coding. Probably best to start with OctoWS2811 and connect resistors to the 8 pins. I'd suggest starting simple with the code, like configuring the LED strip length to be the number of points per waveform and fill the output buffer with your sine wave data. When you watch the waveform on your oscilloscope, you should see an 800 kHz waveform for the LED protocol, where the first part is maximum voltage because all pins drive high, then your analog voltage should be in the middle part, and the last part should be minimum voltage because all the pins drive low. Before you dive into the complexity of timers and DMA channels, I highly recommend just using the existing code as-is (maybe even use setPixel with specific colors to get your sine wave written into the buffer) to get to that point.

    Once you get that waveform, then the next step would be cutting away the 2 unneeded DMA channels, so you're not driving the pin high and low at the beginning and end of each 800 kHz cycle of the timer. Again, get that working before messing with the timer. The key to success with this sort of project is approaching it in small steps and leveraging each success to move on to the next. If you just start tearing into all the complex hardware details at the same time, odds of getting everything working are slim.

  7. #7
    Junior Member
    Join Date
    Nov 2019
    Posts
    8
    Quote Originally Posted by PaulStoffregen View Post
    In theory, you could connect resistors in a R-2R ladder or just binary weighted to several pins and write 8 bit numbers to a native port. You'd probably set up a timer to trigger a DMA channel to copy bytes from a buffer to the pins. It would probably look similar to the code in OctoWS2811, except using only 1 DMA channel instead of 3, since you just want to write all the pins once per update rather than 3 times.

    Realistically, you can probably expect to get about 3 to 5 million updates per second using DMA, for about 20 to 33 updates per period of 150 kHz.

    To do this, you'll need to dive into some fairly low-level coding. Probably best to start with OctoWS2811 and connect resistors to the 8 pins. I'd suggest starting simple with the code, like configuring the LED strip length to be the number of points per waveform and fill the output buffer with your sine wave data. When you watch the waveform on your oscilloscope, you should see an 800 kHz waveform for the LED protocol, where the first part is maximum voltage because all pins drive high, then your analog voltage should be in the middle part, and the last part should be minimum voltage because all the pins drive low. Before you dive into the complexity of timers and DMA channels, I highly recommend just using the existing code as-is (maybe even use setPixel with specific colors to get your sine wave written into the buffer) to get to that point.

    Once you get that waveform, then the next step would be cutting away the 2 unneeded DMA channels, so you're not driving the pin high and low at the beginning and end of each 800 kHz cycle of the timer. Again, get that working before messing with the timer. The key to success with this sort of project is approaching it in small steps and leveraging each success to move on to the next. If you just start tearing into all the complex hardware details at the same time, odds of getting everything working are slim.
    Hey Paul thank you for replying. Sounds like a fairly daunting task. What would be the simplest solution to generate a BFSK signal at 600 BPS from the Teensy 3.6 considering that I am willing add some cheap single module ? Also is it possible to do it easier on some other teensy revision (4.1 ??)

  8. #8
    Junior Member
    Join Date
    Nov 2019
    Posts
    8
    The signal being at 150 Khz that is.

  9. #9
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,862
    BTW what signal quality requirements do you have?

  10. #10
    Junior Member
    Join Date
    Nov 2019
    Posts
    8
    Quote Originally Posted by MarkT View Post
    BTW what signal quality requirements do you have?

    Hey Mark, I don't have specific signal requirements per say. My goal is to make an AM transmission with minimum parts added which uses B-FSK at 600 BPS. I guess I can add filtering externally if the signal is too dirty to transmit. At such low frequencies the transmission will be so inefficient with any traditional antenna setup that I think it wont go far anyway so will be very close range. What do you recommend ?

  11. #11
    Senior Member
    Join Date
    May 2019
    Posts
    133
    Single GPIO and a resonator tank after it. Modulate the amplitude with a LDR? Or JFET?

  12. #12
    Junior Member
    Join Date
    Nov 2019
    Posts
    8
    Sorry I did not mean Amplitude modulation. I mean B-FSK modulation at 150 khz frequency :P I am a radio guy yet I mix frequencies and modulation :P

  13. #13
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,995
    When I suggested you connect only resistors and adapt the OctoWS2811 code, you said:

    Quote Originally Posted by kushagra View Post
    Sounds like a fairly daunting task. What would be the simplest solution to generate a BFSK signal at 600 BPS from the Teensy 3.6 considering that I am willing add some cheap single module ?

    Then when Mark asks about your requirements:

    Quote Originally Posted by kushagra View Post
    My goal is to make an AM transmission with minimum parts added which uses B-FSK at 600 BPS. I guess I can add filtering externally if the signal is too dirty to transmit.

    There is no magical answer here, like someone has already done a very similar project and shared their entire design as open source. **

    We can try to help you, but you're going to have to do some work. If you build a crude-but-fast DAC using pins and resistors, you can put that work into the software side to synthesize the waveform at high sample rate and stream it to the pins. Or if you want to keep things simpler (maybe even just a matter of using analogWriteFrequency 600 times per second), you can generate a square wave and put work into the difficult filtering to remove the harmonics.

    I do have one question... I missed it in these 10 messages, but have we even heard how far you wish to modulate (or "shift") the 150 kHz frequency?



    ** - Unless Frank comes along and shares his FM modulation with PLL & DMA wizardry...

  14. #14
    Junior Member
    Join Date
    Nov 2019
    Posts
    8
    Hey Paul,
    A shift of 0.5 khz is what I am aiming for.
    So between the space and mark frequency a shift of 500 Hz. I understand what you are saying, I am just trying to wonder if there is a simpler way to produce the same signal. Kind of spoilt from using high speed DACs and ADCs in moderns SDRs I guess :P

  15. #15
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,862
    For transmission quality I don't think direct from a microcontroller is clean enough, all that digital noise on the rails...

    Something like a DDS-60 module might be more reasonable, but with modifications to go below 1MHz.

  16. #16
    Junior Member
    Join Date
    Nov 2019
    Posts
    8
    Makes sense I guess. I might try an AD9833 DDS module from Analog Devices which is a bit low spec compared to the AD9851 in the DDS-60 but I need 150 khz anyways so it doesn't really matter. Read that it should be able to do basic B-FSK with the two internal frequency registers from the datasheet. Thank you for helping !!

  17. #17
    Senior Member
    Join Date
    May 2017
    Posts
    372
    A basic idea without any details: you could set up a PWM pin at 150 khz, set up another PWM pin at 150500 hz, run those outputs to a 2:1 mux and toggle the mux select pin at the 600 baud rate. And then lowpass filter the output.

  18. #18
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,995
    Isn't turning a square to a pure enough sine pretty difficult, analog filter wise?

    A chip like AD9833 could give a nice sine with harmonics all above 20 MHz, which ought to be pretty easy to filter away.

    Doing it with only resistors and DMA to the pins would probably achieve 4-5 Msample/sec and about 5 or 6 bits resolution. So more harmonic content around 5 MHz to filter away.... but only ordinary 1% resistors, and much more on the software size to synthesize the waveform and maintain the high data rate with DMA buffers.

  19. #19
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    1,092
    Quote Originally Posted by MarkT View Post
    Sounds like a job for a DDS module, not a microcontroller. Cheap AD9833 module perhaps?
    That was my first thought as well. Since I had such a $2.50 module laying around, I decided to give it a try.
    The nice thing about the AD9833 is that it has 2 frequency registers that you can pre-program and than dynamically switch between those 2 registers and thus send out these 2 frequencies alternatingly.

    Here is the code:
    Code:
    // AD9833 bd    Teensy 3.x
    // VCC          Vin 5V
    // DGND         GND
    // SDATA        11 MOSI
    // SCLK         13 SCK
    // FSYNC        10 SS
    
    #include <SPI.h>
    #define FSYNC 10
    #define SPI_CLOCK_SPEED 12000000      // 12MHz SPI clock
    
    uint32_t spaceFreqWord = 0x1888f8;    // 150kHz - 250Hz, FreqWord = (frequency * pow(2, 28))/MCLK
    uint32_t markFreqWord = 0x189df1;     // 150kHz + 250Hz
    uint16_t MSB;
    uint16_t LSB;
    
    void setup() {
      pinMode (FSYNC, OUTPUT);
      digitalWrite(FSYNC, HIGH);
      SPI.begin();
      AD9833setFrequencies();
    }
    
    void loop() {
      // switch between freq 0 and freq 1
      WriteRegister(0x2000);              // output freq 0 "SPACE"
      delay(50);
      WriteRegister(0x2800);              // output freq 1 "MARK"
      delay(50);
    }
    
    void AD9833setFrequencies() {
      WriteRegister(0x2100);              // put AD9833 into reset and tell it to accept 14bit words (DB13=1, DB8=1)
    
      MSB = (uint16_t)((spaceFreqWord & 0xFFFC000) >> 14);    // only lower 14 bits are used for data
      LSB = (uint16_t)(spaceFreqWord & 0x3FFF);
      LSB |= 0x4000;                      // DB 15=0, DB14=1    FreqReg0
      MSB |= 0x4000;                      // DB 15=0, DB14=1
      WriteRegister(LSB);                 // write lower 16 bits to AD9833 registers
      WriteRegister(MSB);                 // write upper 16 bits to AD9833 registers
    
      MSB = (uint16_t)((markFreqWord & 0xFFFC000) >> 14);    // only lower 14 bits are used for data
      LSB = (uint16_t)(markFreqWord & 0x3FFF);
      LSB |= 0x8000;                      // DB 15=1, DB14=0    FreqReg1
      MSB |= 0x8000;                      // DB 15=1, DB14=0
      WriteRegister(LSB);                 // write lower 16 bits to AD9833 registers
      WriteRegister(MSB);                 // write upper 16 bits to AD9833 registers
    
      WriteRegister(0xC000);              // write phase register 0
      WriteRegister(0xE000);              // write phase register 1
      WriteRegister(0x2000);              // take AD9833 out of reset, output freq 0
    }
    
    void WriteRegister(uint16_t data) {
      SPI.beginTransaction(SPISettings(SPI_CLOCK_SPEED, MSBFIRST, SPI_MODE2));
      digitalWrite(FSYNC, LOW);           // set FSYNC low before writing to AD9833 registers
      SPI.transfer16(data);
      digitalWrite(FSYNC, HIGH);          // write done, set FSYNC high
      SPI.endTransaction();
    }
    ...and the spectrum on pin "OUT":

    Click image for larger version. 

Name:	SDS00039.png 
Views:	53 
Size:	20.8 KB 
ID:	23461

    Seems to work.

    Paul

Posting Permissions

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