Skip to content

Instantly share code, notes, and snippets.

@samyk
Last active September 8, 2020 19:17
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samyk/6273cf9a45d63a50c38c8b50a39a8f52 to your computer and use it in GitHub Desktop.
Save samyk/6273cf9a45d63a50c38c8b50a39a8f52 to your computer and use it in GitHub Desktop.
134kHz sine wave w/DMA, DAC and PDB on Teensy 3.6
// Generating a 134kHz sine wave using Teensy 3.6 with virtually
// 0 cpu usage by filling the DAC up via DMA triggered by PDB
// -samy kamkar
#include <DMAChannel.h>
#include "pdb.h"
DMAChannel dma(false);
static volatile uint16_t sinetable[] = {
2048,2277,2503,2724,2936,3137,3324,3495,3648,3781,3892,3980,4044,4082,4095,4082,4044,3980,3892,3781,3648,3495,3324,3137,2936,2724,2503,2277,2048,1818,1592,1371,1159,958,771,600,447,314,203,115,51,13,0,13,51,115,203,314,447,600,771,958,1159,1371,1592,1818
};
void setup()
{
dma.begin(true); // allocate the DMA channel first
SIM_SCGC2 |= SIM_SCGC2_DAC0; // enable DAC clock
DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // enable the DAC module, 3.3V reference
// slowly ramp up to DC voltage, approx 1/4 second
for (int16_t i=0; i<2048; i+=8)
{
*(volatile int16_t *)&(DAC0_DAT0L) = i;
delay(1);
}
// set the programmable delay block to trigger DMA requests
SIM_SCGC6 |= SIM_SCGC6_PDB; // enable PDB clock
PDB0_IDLY = 0; // interrupt delay register
PDB0_MOD = 0; //PDB_PERIOD; // modulus register, sets period
PDB0_SC = PDB_CONFIG | PDB_SC_LDOK; // load registers from buffers
PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG; // reset and restart
PDB0_CH0C1 = 0x0101; // channel n control register?
dma.sourceBuffer(sinetable, sizeof(sinetable));
dma.destination(*(volatile uint16_t *)&(DAC0_DAT0L));
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_PDB);
dma.enable();
}
void loop() {
}
@petitmouss
Copy link

Hi Samky, I've tried you code on a Teensy but it can not be compiled because "pdb.h" is not provided. Can you add this file ?
Many thanks.

@samyk
Copy link
Author

samyk commented Sep 6, 2020

@petitmouss
Copy link

Great! Many thanksssss

@samyk
Copy link
Author

samyk commented Sep 7, 2020

🎉 (I would've applied that to your response but just learned gist comments don't allow emojis applied, only github issue comments do!)

@petitmouss
Copy link

Hi Samky,

I'm progress in my project (thanks to you) and I come back to you to say that your software works well on a Teensy3.2. The max frequency is around 60 kHz at 72Mhz's cpu frequency.

Well, I don't have the ratio "CPU Freq / Output Freq" but I've the desired frequency 15 kHz (14.998 Hz) by setting the register PDB0_MOD equals to 0x2A. To avoid crenels, I've added a capacitor to smooth the output signal.

I don't tried yet to involve additional code (like an OLED display or other) but I hope that the frequency will be stable.

Any way: THANKS 💯

@samyk
Copy link
Author

samyk commented Sep 8, 2020

Nice! I'm surprised you're saying the max freq is 15kHz? I know I was able to generate either 125kHz or 134kHz on a Teensy 3.1 and 3.2 as well (those were specific frequencies I wanted, not maximums). I'm sure I adjusted the sinetable and perhaps something else.

I also was doing it in the main loop with a separate test, but I'm guessing you want to keep your main loop unoccupied.

@petitmouss
Copy link

The frequency I was looking for was 15kHz so I've updated the register. It is not the max frequency that we can see on the scope before setting PDB0_MOD register.

However, if a better method exist, it welcome.

I will use 2 interrupts to calculate the phase difference between reference frequency (fixed at 15kHz) and a 2nd incoming signal.

The loop will populated with some functions like a OLED display and capacitive touch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment