Problem with DDS

Started by Leon Heller December 3, 2003
I'm using the following code for software direct digital waveform synthesis:

int main(void)
{
unsigned int i;
unsigned long int acc, adder;
unsigned int ptr, temp;

initPLL();
MAMCR = 0;
MAMTIM = 5;
MAMCR = 2;
VPBDIV = 0x01;
portInit();
//main loop
//add value to accumulator
//load byte from current table
//output byte to port
//repeat

adder = 2000; //set up adder
acc = 0; //clear accumulator
while (1)
{
acc = acc + adder; //update phase accumulator
ptr = (acc &= 0xFF); //pointer into table
IOSET = square[ptr] << 8;//output byte to port
IOCLR = ~(square[ptr] << 8);
}
return 0;
}

but I can't get an equal mark-space ratio out of it for a square wave, and
sine waves are completely screwed up.

The following code for an AVR works very well:

; main loop
;
; r28,r29,r30 is the phase accumulator
; r24,r25,r26 is the adder value determining frequency
;
; add value to accumulator
; load byte from current table in ROM
; output byte to port
; repeat
;
LOOP1:
add r28,r24 ; 1
adc r29,r25 ; 1
adc r30,r26 ; 1
lpm ; 3
out PORTB,r0 ; 1
rjmp LOOP1 ; 2 => 9 cycles

I'm using the same AD557 8-bit DAC and the same look-up tables. I'm
obviously doing something silly, but I can't see what it is. Can anyone
help?

Leon
--
Leon Heller, G1HSM
Email:
http://webspace.webring.com/people/jl/leon_heller/




An Engineer's Guide to the LPC2100 Series

Hi Leon -
I don't step deep into it but as you using variables greater 8 bits what's
about little-endian/big-endian confusion, maybe?
Regards -
Henry

-----Ursprgliche Nachricht-----
Von: Leon Heller <>
An: <>
Datum: Mittwoch, 3. Dezember 2003 11:46
Betreff: [lpc2100] Problem with DDS >I'm using the following code for software direct digital waveform
synthesis:
>
>int main(void)
>{
> unsigned int i;
> unsigned long int acc, adder;
> unsigned int ptr, temp;
>
> initPLL();
> MAMCR = 0;
> MAMTIM = 5;
> MAMCR = 2;
> VPBDIV = 0x01;
> portInit();
> //main loop
> //add value to accumulator
> //load byte from current table
> //output byte to port
> //repeat
>
> adder = 2000; //set up adder
> acc = 0; //clear accumulator
> while (1)
> {
> acc = acc + adder; //update phase accumulator
> ptr = (acc &= 0xFF); //pointer into table
> IOSET = square[ptr] << 8;//output byte to port
> IOCLR = ~(square[ptr] << 8);
> }
> return 0;
>}
>
>but I can't get an equal mark-space ratio out of it for a square wave, and
>sine waves are completely screwed up.
>
>The following code for an AVR works very well:
>
>; main loop
>;
>; r28,r29,r30 is the phase accumulator
>; r24,r25,r26 is the adder value determining frequency
>;
>; add value to accumulator
>; load byte from current table in ROM
>; output byte to port
>; repeat
>;
>LOOP1:
> add r28,r24 ; 1
> adc r29,r25 ; 1
> adc r30,r26 ; 1
> lpm ; 3
> out PORTB,r0 ; 1
> rjmp LOOP1 ; 2 => 9 cycles
>
>I'm using the same AD557 8-bit DAC and the same look-up tables. I'm
>obviously doing something silly, but I can't see what it is. Can anyone
>help?
>
>Leon
>--
>Leon Heller, G1HSM
>Email:
>http://webspace.webring.com/people/jl/leon_heller/ >To unsubscribe from this group, send an email to: >
>
>">http://docs.yahoo.com/info/terms/




On Wed, Dec 03, 2003 at 10:44:28AM -0000, Leon Heller wrote:
> I'm using the following code for software direct digital waveform synthesis:
>
> int main(void)
> {
> unsigned int i;
> unsigned long int acc, adder;
> unsigned int ptr, temp;
>
> initPLL();
> MAMCR = 0;
> MAMTIM = 5;
> MAMCR = 2;
> VPBDIV = 0x01;
> portInit();
> //main loop
> //add value to accumulator
> //load byte from current table
> //output byte to port
> //repeat
>
> adder = 2000; //set up adder
> acc = 0; //clear accumulator
> while (1)
> {
> acc = acc + adder; //update phase accumulator
> ptr = (acc &= 0xFF); //pointer into table
> IOSET = square[ptr] << 8;//output byte to port
> IOCLR = ~(square[ptr] << 8);
> }
> return 0;
> }
>
> but I can't get an equal mark-space ratio out of it for a square wave, and
> sine waves are completely screwed up.

what is the compiler outputing for this code? do you have a disassembly
of the code being produced?

[snip]

--
Ben

Q: What's a light-year?
A: One-third less calories than a regular year.



Attachment (not stored)
attachment
Type: application/pgp-signature


--- In , Ben Dooks <ben@f...> wrote:
> On Wed, Dec 03, 2003 at 10:44:28AM -0000, Leon Heller wrote:
> > I'm using the following code for software direct digital waveform
synthesis:
> >
> > int main(void)
> > {
> > unsigned int i;
> > unsigned long int acc, adder;
> > unsigned int ptr, temp;
> >
> > initPLL();
> > MAMCR = 0;
> > MAMTIM = 5;
> > MAMCR = 2;
> > VPBDIV = 0x01;
> > portInit();
> > //main loop
> > //add value to accumulator
> > //load byte from current table
> > //output byte to port
> > //repeat
> >
> > adder = 2000; //set up adder
> > acc = 0; //clear accumulator
> > while (1)
> > {
> > acc = acc + adder; //update phase accumulator
> > ptr = (acc &= 0xFF); //pointer into table
> > IOSET = square[ptr] << 8;//output byte to port
> > IOCLR = ~(square[ptr] << 8);
> > }
> > return 0;
> > }
> >
> > but I can't get an equal mark-space ratio out of it for a square
wave, and
> > sine waves are completely screwed up.
>
> what is the compiler outputing for this code? do you have a disassembly
> of the code being produced?
>

Thanks for the suggestion.

This is what I'm getting:

while (1)
40000150 E3A0024E mov r0, #0xe0000004
40000154 E280090A add r0, r0, #0x28000
40000158 E59F1028 ldr r1, [pc, #40]
4000015C E3A022CE mov r2, #0xe000000c
40000160 E282290A add r2, r2, #0x28000
{
acc = acc + adder; //update phase accumulator
40000164 E084400C add r4, r4, r12
ptr = (acc &= 0xFF); //pointer into table
40000168 E20440FF and r4, r4, #0xff
IOSET = square[ptr] << 8;//output byte to port
4000016C E7D43001 ldrb r3, [r4, r1]
40000170 E1A03403 mov r3, r3, lsl #0x8
40000174 E5803000 str r3, [r0, #0]
IOCLR = ~(square[ptr] << 8);
40000178 E7D43001 ldrb r3, [r4, r1]
4000017C E1E03403 mvn r3, r3, lsl #0x8
40000180 E5823000 str r3, [r2, #0]
40000184 EAFFFFF6 b -10 ; 0x40000164
40000188 4000062C andmi r0, r0, r12, lsr #0xc
}

I'm not all that familiar with ARM assembler, but it looks about
right. I'm using the Rowley tools, which use the GNU compiler.

Leon



On Wed, Dec 03, 2003 at 12:34:16PM -0000, leon_heller wrote:
> --- In , Ben Dooks <ben@f...> wrote:
> > On Wed, Dec 03, 2003 at 10:44:28AM -0000, Leon Heller wrote:
> > > I'm using the following code for software direct digital waveform
> synthesis:
> > >
> > > int main(void)
> > > {
> > > unsigned int i;
> > > unsigned long int acc, adder;
> > > unsigned int ptr, temp;
> > >
> > > initPLL();
> > > MAMCR = 0;
> > > MAMTIM = 5;
> > > MAMCR = 2;
> > > VPBDIV = 0x01;
> > > portInit();
> > > //main loop
> > > //add value to accumulator
> > > //load byte from current table
> > > //output byte to port
> > > //repeat
> > >
> > > adder = 2000; //set up adder
> > > acc = 0; //clear accumulator
> > > while (1)
> > > {
> > > acc = acc + adder; //update phase accumulator
> > > ptr = (acc &= 0xFF); //pointer into table
> > > IOSET = square[ptr] << 8;//output byte to port
> > > IOCLR = ~(square[ptr] << 8);

possibly you want to assign `square[ptr] << 8` to a temporary
register to stop it trying to load it from the array twice.

> > > }
> > > return 0;
> > > }
> > >
> > > but I can't get an equal mark-space ratio out of it for a square
> wave, and
> > > sine waves are completely screwed up.
> >
> > what is the compiler outputing for this code? do you have a disassembly
> > of the code being produced?
> >
>
> Thanks for the suggestion.
>
> This is what I'm getting:
>
> while (1)
> 40000150 E3A0024E mov r0, #0xe0000004
> 40000154 E280090A add r0, r0, #0x28000
> 40000158 E59F1028 ldr r1, [pc, #40]
> 4000015C E3A022CE mov r2, #0xe000000c
> 40000160 E282290A add r2, r2, #0x28000
> {
> acc = acc + adder; //update phase accumulator
> 40000164 E084400C add r4, r4, r12
> ptr = (acc &= 0xFF); //pointer into table

you did mean to do
ptr = acc & 0xff;
acc = acc & 0xff; ?

> 40000168 E20440FF and r4, r4, #0xff
> IOSET = square[ptr] << 8;//output byte to port
> 4000016C E7D43001 ldrb r3, [r4, r1]
> 40000170 E1A03403 mov r3, r3, lsl #0x8
> 40000174 E5803000 str r3, [r0, #0]
> IOCLR = ~(square[ptr] << 8);
> 40000178 E7D43001 ldrb r3, [r4, r1]
> 4000017C E1E03403 mvn r3, r3, lsl #0x8
> 40000180 E5823000 str r3, [r2, #0]
> 40000184 EAFFFFF6 b -10 ; 0x40000164
> 40000188 4000062C andmi r0, r0, r12, lsr #0xc
> }
>
> I'm not all that familiar with ARM assembler, but it looks about
> right. I'm using the Rowley tools, which use the GNU compiler.
>
> Leon >
> To unsubscribe from this group, send an email to: >
>
> ">http://docs.yahoo.com/info/terms/

--
--
Ben

Q: What's a light-year?
A: One-third less calories than a regular year.



Attachment (not stored)
attachment
Type: application/pgp-signature

Hi Leon,

To check the value written you need this :

> ptr = (acc &= 0xFF); //pointer into table
> 40000168 E20440FF and r4, r4, #0xff

ptr is R4.

> IOSET = square[ptr] << 8;//output byte to port
> 4000016C E7D43001 ldrb r3, [r4, r1]
> 40000170 E1A03403 mov r3, r3, lsl #0x8
> 40000174 E5803000 str r3, [r0, #0]

The ldrb instruction loads R3 with what R4, offset by R1, points to.
So you need to know what's in R1 to work out the offset, and thus what's
actually
written to IOCLR and IOSET

> I'm not all that familiar with ARM assembler, but it looks about
> right. I'm using the Rowley tools, which use the GNU compiler.
>
> Leon

Best regards
-- Kris


Also BTW, I think you need to mask off the other bits on I/O
(D0-D7, D16-D31), especially with the write to IOCLR.

I've actually been thinking of a boolean macro that turns IOSET,IOCLR into
"one port", where you just write a zero or a one to the macro to set/clear
IO pins, and it does the 1 bit writing to CLR or SET for you.

-- Kris
----- Original Message -----
From: "microbit" <>
To: <>
Sent: Wednesday, December 03, 2003 11:54 PM
Subject: Re: [lpc2100] Re: Problem with DDS > Hi Leon,
>
> To check the value written you need this :
>
> > ptr = (acc &= 0xFF); //pointer into table
> > 40000168 E20440FF and r4, r4, #0xff
>
> ptr is R4.
>
> > IOSET = square[ptr] << 8;//output byte to port
> > 4000016C E7D43001 ldrb r3, [r4, r1]
> > 40000170 E1A03403 mov r3, r3, lsl #0x8
> > 40000174 E5803000 str r3, [r0, #0]
>
> The ldrb instruction loads R3 with what R4, offset by R1, points to.
> So you need to know what's in R1 to work out the offset, and thus what's
> actually
> written to IOCLR and IOSET
>
> > I'm not all that familiar with ARM assembler, but it looks about
> > right. I'm using the Rowley tools, which use the GNU compiler.
> >
> > Leon
>
> Best regards
> -- Kris > Yahoo! Groups Sponsor >
> To unsubscribe from this group, send an email to: >
>
>
>



At 11:23 AM 12/3/03 +0000, you wrote:
>On Wed, Dec 03, 2003 at 10:44:28AM -0000, Leon Heller wrote:
> > I'm using the following code for software direct digital waveform
> synthesis:
> >
> > int main(void)
> > {
> > unsigned int i;
> > unsigned long int acc, adder;
> > unsigned int ptr, temp;
> >
> > initPLL();
> > MAMCR = 0;
> > MAMTIM = 5;
> > MAMCR = 2;
> > VPBDIV = 0x01;
> > portInit();
> > //main loop
> > //add value to accumulator
> > //load byte from current table
> > //output byte to port
> > //repeat
> >
> > adder = 2000; //set up adder
> > acc = 0; //clear accumulator
> > while (1)
> > {
> > acc = acc + adder; //update phase accumulator
> > ptr = (acc &= 0xFF); //pointer into table
> > IOSET = square[ptr] << 8;//output byte to port
> > IOCLR = ~(square[ptr] << 8);
> > }
> > return 0;
> > }
> >
> > but I can't get an equal mark-space ratio out of it for a square wave, and
> > sine waves are completely screwed up.

Strangely enough your original message doesn't seem to have propagated Leon.

There are definitely issues with how fast you can update the output ports
though. Given there is no delay in your loop that is likely to be having
an effect. If you insert a delay I expect that will square things up (of
course you'll get a slower wave :()

Robert

" 'Freedom' has no meaning of itself. There are always restrictions,
be they legal, genetic, or physical. If you don't believe me, try to
chew a radio signal. "

Kelvin Throop, III


At 10:44 AM 12/3/03 +0000, you wrote:
>I'm using the following code for software direct digital waveform synthesis:

Ah, it just showed up.

> adder = 2000; //set up adder
> acc = 0; //clear accumulator
> while (1)
> {
> acc = acc + adder; //update phase accumulator
> ptr = (acc &= 0xFF); //pointer into table
> IOSET = square[ptr] << 8;//output byte to port
> IOCLR = ~(square[ptr] << 8);
> }
> return 0;
>}
>
>but I can't get an equal mark-space ratio out of it for a square wave, and
>sine waves are completely screwed up.
>
>The following code for an AVR works very well:
>
>; main loop
>;
>; r28,r29,r30 is the phase accumulator
>; r24,r25,r26 is the adder value determining frequency
>;
>; add value to accumulator
>; load byte from current table in ROM
>; output byte to port
>; repeat
>;
>LOOP1:
> add r28,r24 ; 1
> adc r29,r25 ; 1
> adc r30,r26 ; 1
> lpm ; 3
> out PORTB,r0 ; 1
> rjmp LOOP1 ; 2 => 9 cycles
>
>I'm using the same AD557 8-bit DAC and the same look-up tables. I'm
>obviously doing something silly, but I can't see what it is. Can anyone
>help?

OK, this makes things a little more clear.

Q: Is your distortion coming from loop to loop delay or from the delay
between set and clear? (I suspect the latter).

Robert