Skip to content

Instantly share code, notes, and snippets.

@samyk
Last active September 8, 2020 19:17
Show Gist options
  • Select an option

  • Save samyk/6273cf9a45d63a50c38c8b50a39a8f52 to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown

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
Copy Markdown
Author

samyk commented Sep 6, 2020

@petitmouss
Copy link
Copy Markdown

Great! Many thanksssss

@samyk
Copy link
Copy Markdown
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
Copy Markdown

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
Copy Markdown
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
Copy Markdown

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