Maximum periodic D/A speed
2006-01-16 by drareve
Yahoo Groups archive
Index last updated: 2026-04-28 23:31 UTC
Thread
2006-01-16 by drareve
Does anyone know what is the maximum speed that I could send data to the D/A at fixed frequency? I am using a LPC2148 with a 10MHz crystal and a PLL M value of 6, and P value of 2. My PCLK should be 60Mhz (VPBDIV=0x1) I have tried setting up a timer to send a sample every 1uS, but the output appears to be quite unstable. Thank you
2006-01-16 by Karl Olsen
---- Original Message ----
From: "drareve" <everard.kamphorst@...>
To: <lpc2000@yahoogroups.com>
Sent: Monday, January 16, 2006 9:40 PM
Subject: [lpc2000] Maximum periodic D/A speed
> Does anyone know what is the maximum speed that I could send
> data to the D/A at fixed frequency?
>
> I am using a LPC2148 with a 10MHz crystal and a PLL M value of 6, and
> P value of 2. My PCLK should be 60Mhz (VPBDIV=0x1)
>
> I have tried setting up a timer to send a sample every 1uS, but the
> output appears to be quite unstable.
As far as I know, the D/A converter itself doesn't limit the update rate,
other than its fast/slow settling time. But having a timer interrupt that
is called every 60 clocks that updates the DAC, requires some very careful
programming, and in the best case, you'll get very few spare clocks left for
the foreground program. Just the stores that write to DACR and T0IR take 7
clocks each since they are behind the slow APB bridge.
Something like this (gcc):
unsigned short buf[1024];
int index;
void timer0_handler (void) __attribute__ ((interrupt("IRQ")));
void timer0_handler (void)
{
int next_index;
DACR = buf[index] << 6;
if ((next_index = index+1) == 1024)
next_index = 0;
index = next_index;
T0IR = 0x01;
VICVectAddr = 0x00;
}
with the usual LDR PC, [PC, #-0x0FF0] at 0x0018 and MAM enabled and
MAMTIM=3, will take around 83 clocks. Check the compiler output and see
http://groups.yahoo.com/group/lpc2000/message/7808 . If you use FIQ instead
of IRQ, and carefully write it in assembler, you may be able to get below 60
clocks.
The DAC updating will have a jitter of a few clocks, because at each timer
interrupt, the current instruction of the foreground program must complete,
and that can take a variable number of clocks.
Karl Olsen2006-01-16 by David Hawkins
>>Does anyone know what is the maximum speed that I could send >>data to the D/A at fixed frequency? You can eliminate the software jitter by introducing a set of latches. Use the hardware timer or PWM hardware to generate a fixed frequency square-wave (or edge at least) on an output pin. Use this to latch the input to the DAC. In your software, triggered from the same timer, write the next valid sample to the input of the latch, eg. on the output pins of the micro, or to another latch that preceeds the DAC latch. The software jitter then only affects the data written to the first latch, data written to the second latch (or DAC internal latch) is done by the timer I/O pin, so is unaffected by the software jitter. If you use software to fill a FIFO, then the DAC can be driven by the FIFO draining, and software can fill it up on an 'almost empty' interrupt. You'll get higher performance from the DAC with this scheme. Cheers Dave
2006-01-17 by brendanmurphy37
Hi, I presume you're talking about using some form of external DAC as part of your suggestion? If not, can you explain the statement "Use this to latch the input to the DAC". A significant problem with the on-board DAC is that there is no latch signal that can be applied, making some degree of jitter inevitable on any software-driven setup. We had to abandon the idea of using the on-board DAC for our software modem for this very reason: even a few clocks of jitter at 60 Mhz is enough to generate significant noise on the output. I suspect anyone else (the original questioner on this topic?) trying to drive the DAC at high speeds will hit this problem before they hit the maximum o/p speed problem (unless having a noisy o/p isn't a concern). This is unfortunate, as it means that the DAC can't really be used for even relatively simple signal generation without a noisy o/p. A very simple addition to the DAC, namely a latch signal, would be a great help here. Of course, a DMA-fed FIFO arrangement would be even better..... Brendan P.S. as an aside, we did come up with a jitter-free software-fed DAC, but it consumed significant MIPS, and just wasn't worth the effort. --- In lpc2000@yahoogroups.com, David Hawkins <dwh@o...> wrote:
> > > >>Does anyone know what is the maximum speed that I could send > >>data to the D/A at fixed frequency? > > You can eliminate the software jitter by introducing a set of > latches. > > Use the hardware timer or PWM hardware to generate a fixed > frequency square-wave (or edge at least) on an output pin. > Use this to latch the input to the DAC. > > In your software, triggered from the same timer, write the > next valid sample to the input of the latch, eg. on the > output pins of the micro, or to another latch that > preceeds the DAC latch. > > The software jitter then only affects the data written > to the first latch, data written to the second latch > (or DAC internal latch) is done by the timer I/O pin, > so is unaffected by the software jitter. > > If you use software to fill a FIFO, then the DAC can be > driven by the FIFO draining, and software can fill it > up on an 'almost empty' interrupt. You'll get higher > performance from the DAC with this scheme. > > Cheers > Dave >
2006-01-17 by brendanmurphy37
Karl,
As a further suggestion to anyone taking this approach, I'd suggest
the following optimisations (which can be applied in other scenarios
as well that require speedy o/p).
1. Prepare the samples in buffers that are "ready to go", rather than
doing any processing in the o/p interrupt. I know that on ARM shifts
can sometimes be "free", but in some cases they're not.
2. Use power-of two sized buffers, and load using something like:
#define BUFF_SIZE 256
#define BUFF_SIZE_MASK (BUFF_SIZE - 1)
REG = buffer[index++];
index &= (BUFF_SIZE_MASK);
3. If you're really pushed for cycles for one particular interrupt,
you can use an FIQ interrupt and "pre-load" certain registers.
For example, in this case, in your start-up code:
load r8 with the DAC o/p register address
load r9 with the buffer address
load r10 with the current index
In the FIQ interrupt:
- just fall through from the bottom of the vector table (i.e. don't
branch or jump)
- use the pre-loaded r8, r9 and r10 (and others): no need to save
these as they're unique to FIQ interrupts
- update the pre-loaded registers of required for next time: they are
preserved across interrupts
We use these (and other) techniques in a system that both generates
and samples at high speed (200 Khz and above), and it works very well
Hope this of help to someone.
Regards
Brendan
--- In lpc2000@yahoogroups.com, "Karl Olsen" <kro@p...> wrote:
>
> ---- Original Message ----
> From: "drareve" <everard.kamphorst@g...>
> To: <lpc2000@yahoogroups.com>
> Sent: Monday, January 16, 2006 9:40 PM
> Subject: [lpc2000] Maximum periodic D/A speed
>
> > Does anyone know what is the maximum speed that I could send
> > data to the D/A at fixed frequency?
> >
> > I am using a LPC2148 with a 10MHz crystal and a PLL M value of 6,
and
> > P value of 2. My PCLK should be 60Mhz (VPBDIV=0x1)
> >
> > I have tried setting up a timer to send a sample every 1uS, but
the
> > output appears to be quite unstable.
>
> As far as I know, the D/A converter itself doesn't limit the update
rate,
> other than its fast/slow settling time. But having a timer
interrupt that
> is called every 60 clocks that updates the DAC, requires some very
careful
> programming, and in the best case, you'll get very few spare clocks
left for
> the foreground program. Just the stores that write to DACR and
T0IR take 7
> clocks each since they are behind the slow APB bridge.
>
> Something like this (gcc):
>
> unsigned short buf[1024];
> int index;
>
> void timer0_handler (void) __attribute__ ((interrupt("IRQ")));
> void timer0_handler (void)
> {
> int next_index;
>
> DACR = buf[index] << 6;
> if ((next_index = index+1) == 1024)
> next_index = 0;
> index = next_index;
> T0IR = 0x01;
> VICVectAddr = 0x00;
> }
>
> with the usual LDR PC, [PC, #-0x0FF0] at 0x0018 and MAM enabled
and
> MAMTIM=3, will take around 83 clocks. Check the compiler output
and see
> http://groups.yahoo.com/group/lpc2000/message/7808 . If you use
FIQ instead
> of IRQ, and carefully write it in assembler, you may be able to get
below 60
> clocks.
>
> The DAC updating will have a jitter of a few clocks, because at
each timer
> interrupt, the current instruction of the foreground program must
complete,> and that can take a variable number of clocks. > > Karl Olsen >
2006-01-17 by brendanmurphy37
Just to clarify the example below:
In your startup code, you can pre-load FIQ registers, but obviously
you have to be in FIQ mode to do this! We do this as part of the
initial startup that switches between modes to initialise the stack
pointers for each mode.
Brendan
--- In lpc2000@yahoogroups.com, "brendanmurphy37"
<brendan.murphy@i...> wrote:
>
>
> Karl,
>
> As a further suggestion to anyone taking this approach, I'd suggest
> the following optimisations (which can be applied in other
scenarios
> as well that require speedy o/p).
>
> 1. Prepare the samples in buffers that are "ready to go", rather
than
> doing any processing in the o/p interrupt. I know that on ARM
shifts
> can sometimes be "free", but in some cases they're not.
>
> 2. Use power-of two sized buffers, and load using something like:
>
> #define BUFF_SIZE 256
> #define BUFF_SIZE_MASK (BUFF_SIZE - 1)
>
> REG = buffer[index++];
> index &= (BUFF_SIZE_MASK);
>
> 3. If you're really pushed for cycles for one particular interrupt,
> you can use an FIQ interrupt and "pre-load" certain registers.
>
> For example, in this case, in your start-up code:
>
> load r8 with the DAC o/p register address
> load r9 with the buffer address
> load r10 with the current index
>
> In the FIQ interrupt:
>
> - just fall through from the bottom of the vector table (i.e. don't
> branch or jump)
>
> - use the pre-loaded r8, r9 and r10 (and others): no need to save
> these as they're unique to FIQ interrupts
>
> - update the pre-loaded registers of required for next time: they
are
> preserved across interrupts
>
> We use these (and other) techniques in a system that both generates
> and samples at high speed (200 Khz and above), and it works very
well
>
> Hope this of help to someone.
>
> Regards
> Brendan
>
> --- In lpc2000@yahoogroups.com, "Karl Olsen" <kro@p...> wrote:
> >
> > ---- Original Message ----
> > From: "drareve" <everard.kamphorst@g...>
> > To: <lpc2000@yahoogroups.com>
> > Sent: Monday, January 16, 2006 9:40 PM
> > Subject: [lpc2000] Maximum periodic D/A speed
> >
> > > Does anyone know what is the maximum speed that I could send
> > > data to the D/A at fixed frequency?
> > >
> > > I am using a LPC2148 with a 10MHz crystal and a PLL M value of
6,
> and
> > > P value of 2. My PCLK should be 60Mhz (VPBDIV=0x1)
> > >
> > > I have tried setting up a timer to send a sample every 1uS, but
> the
> > > output appears to be quite unstable.
> >
> > As far as I know, the D/A converter itself doesn't limit the
update
> rate,
> > other than its fast/slow settling time. But having a timer
> interrupt that
> > is called every 60 clocks that updates the DAC, requires some
very
> careful
> > programming, and in the best case, you'll get very few spare
clocks
> left for
> > the foreground program. Just the stores that write to DACR and
> T0IR take 7
> > clocks each since they are behind the slow APB bridge.
> >
> > Something like this (gcc):
> >
> > unsigned short buf[1024];
> > int index;
> >
> > void timer0_handler (void) __attribute__ ((interrupt("IRQ")));
> > void timer0_handler (void)
> > {
> > int next_index;
> >
> > DACR = buf[index] << 6;
> > if ((next_index = index+1) == 1024)
> > next_index = 0;
> > index = next_index;
> > T0IR = 0x01;
> > VICVectAddr = 0x00;
> > }
> >
> > with the usual LDR PC, [PC, #-0x0FF0] at 0x0018 and MAM
enabled
> and
> > MAMTIM=3, will take around 83 clocks. Check the compiler output
> and see
> > http://groups.yahoo.com/group/lpc2000/message/7808 . If you use
> FIQ instead
> > of IRQ, and carefully write it in assembler, you may be able to
get > below 60 > > clocks. > > > > The DAC updating will have a jitter of a few clocks, because at > each timer > > interrupt, the current instruction of the foreground program must > complete, > > and that can take a variable number of clocks. > > > > Karl Olsen > > >
2006-01-17 by Karl Olsen
--- In lpc2000@yahoogroups.com, "brendanmurphy37" <brendan.murphy@i...> wrote: > > I presume you're talking about using some form of external DAC as > part of your suggestion? If not, can you explain the statement "Use > this to latch the input to the DAC". > > A significant problem with the on-board DAC is that there is no > latch signal that can be applied, making some degree of jitter > inevitable on any software-driven setup. > > We had to abandon the idea of using the on-board DAC for our > software modem for this very reason: even a few clocks of jitter at > 60 Mhz is enough to generate significant noise on the output. > > I suspect anyone else (the original questioner on this topic?) > trying to drive the DAC at high speeds will hit this problem before > they hit the maximum o/p speed problem (unless having a noisy o/p > isn't a concern). This is unfortunate, as it means that the DAC > can't really be used for even relatively simple signal generation > without a noisy o/p. > > A very simple addition to the DAC, namely a latch signal, would be > a great help here. > > Of course, a DMA-fed FIFO arrangement would be even better..... Yep. You can add an external "analog latch", i.e. a sample-hold circuit with an analog switch and a capacitor, where the analog switch is controlled by a PWM output. The software then updates the DAC output (at an imprecise time) while the analog switch is off and the capacitor holds the voltage, and the PWM output later, at a precise time, turns the analog switch on and lets the new voltage get to the capacitor. Karl Olsen