Forum - MCS Electronics

 

FAQFAQ SearchSearch RegisterRegister Log inLog in

Direct Digital Synthesis. (DDS)
Goto page Previous  1, 2, 3, 4, 5, 6  Next
 
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    www.mcselec.com Forum Index -> BASCOM-AVR Archive
View previous topic :: View next topic  
Author Message
davidapex

Bascom Member



Joined: 12 Mar 2006
Posts: 42
Location: Auckland

newzealand.gif
PostPosted: Sat May 13, 2006 12:41 pm    Post subject: Reply with quote

That's it - I'm going back to making model aeroplanes.
Found a major problem with the 3x4 keypad routine. After calling this routine the port pins are left partly as input and partly outputs, including my separate pin (portb.7) for the interrupt.

Thinking if I set all the port pins back to inputs after using the keypad I would be up and running ended in further confusion.

I suspect the ISR is being completed and returned to the frequency generating loop but it appears to be instantly interrupted again and going back to the keypad input routine.
Changing the ISRs "return" to a "goto" with a label just before the frequency loop at least allows the new frequency to be entered and generated but does not re-establish the interrupt.
Why doesn't my interrupt work the second time around?
Back to top
View user's profile
Luciano

Bascom Member



Joined: 29 Nov 2004
Posts: 3149
Location: Italy

blank.gif
PostPosted: Sat May 13, 2006 2:04 pm    Post subject: Reply with quote

David,

===============================================
If you are using an ATmeg168:

Set EIFR.0 ' clear Int0 flag of the ATmega168.

See my previous post where to put this line of code.
The code of my previous post is for a Tiny2313 where
the Int0 flag is bit 6. The Int0 flag of the ATmega168
is bit 0 of the EIFR register.

===============================================

When the interrupt occurs, the processor pushes the actual program
counter to the stack. RETI (return from the int routine) restores
the I-bit after the return address has been popped from the stack
and loaded to the program counter. (When you use RETURN in a Bascom
interrupt routine, Bascom will generate a RETI instruction).

This is not the only way to return from an interrupt routine.
If you use RETI you will avoid problems with the stack.

===============================================

These two lines must be before the assembly code:

Code:

config portb = input
waitms 50
 

This just because you don't know if "waitms 50" will use
R24, R25, R26, R28, R29, R30 or R31.


Code:

ldi ZH, high (Sine_table * 2)                     ' setup Z pointer hi
ldi ZL, low (Sine_table * 2)                      ' setup Z pointer lo

ldi r28,$00                                       ' clear accumulator
ldi r29,$00                                       ' clear accumulator

loadadr add0 , X                                  'LSB
ld r24, X
loadadr add8 , X
ld r25, X
loadadr add16 , X                                 'MSB
ld r26, X
 




Best regards,

Luciano


Last edited by Luciano on Sat May 13, 2006 2:16 pm; edited 1 time in total
Back to top
View user's profile
Ross_ValuSoft

Bascom Member



Joined: 20 Nov 2005
Posts: 275
Location: Melbourne, Australia

australia.gif
PostPosted: Sat May 13, 2006 2:07 pm    Post subject: Reply with quote

David,

Talking of model aeroplanes <g>....about 10 years ago I was the project manager for the Aerosonde (google it for more).

Regards,

Ross McKenzie
ValuSoft
melbourne Australia
Back to top
View user's profile
davidapex

Bascom Member



Joined: 12 Mar 2006
Posts: 42
Location: Auckland

newzealand.gif
PostPosted: Sat May 13, 2006 10:35 pm    Post subject: Reply with quote

Hello Luciano,
Many thanks for your continued support.
I will try this later today and report back. I seem to have waisted so much time and had little change in result.
I was a bit confused by the Atmel datasheet that said "The flag is cleared when the interrupt routine is executed" but I realise now this is for a different type of interrupt. If it needs the flag cleared then I guess it will be a one-shot.

Ross - nice project. Very impressive performance!

Cheers,
David
Back to top
View user's profile
davidapex

Bascom Member



Joined: 12 Mar 2006
Posts: 42
Location: Auckland

newzealand.gif
PostPosted: Sat May 13, 2006 10:45 pm    Post subject: Reply with quote

Hmmmm.....
Just realised - I'm using Pin Change Interrupts which will generate interrupts whether going high or low. Was this another bad call on my part and should I change them to low only interrupts?

Cheers,
David
Back to top
View user's profile
davidapex

Bascom Member



Joined: 12 Mar 2006
Posts: 42
Location: Auckland

newzealand.gif
PostPosted: Mon May 15, 2006 9:39 pm    Post subject: Reply with quote

Hi All,
Attached is my last attempt to ***** this before trying something a little easier such as blinking LEDs.

The code starts up outputing a garbage waveform as I have removed the starting values for the phase accumulator.
I have PortB.7 configured as a pin change interrupt with a pullup resistor.
A momentary low on this pin then interrupts and sends the code to the 3x4 keypad input routine.
The number that is keyed in is written to the display along with the 3 register values for the phase accumulator.
Upon hitting the "#" key the values are loaded and the assembler loop outputs the new frequency. The table is not yet indexed to a boundary so it is distorted but this is a minor concern.
All is OK so far but that is where it stops. It won't interrupt the second time indicating I have screwed up in the interrupt setup before the RETURN.
Now the code is not exactly in the form I want it but until I can get the interrupt working (more than once) I haven't bothered optimising it.
Please note I'm using PCInt0 and not Int0. I don't mind a challenge but this is getting quite frustrating.
Any pointers or guesses from anyone (including weather bureau) would be gratefully received. The PCInt example in the samples makes it look so easy.

Cheers,
David
Back to top
View user's profile
Luciano

Bascom Member



Joined: 29 Nov 2004
Posts: 3149
Location: Italy

blank.gif
PostPosted: Mon May 15, 2006 10:59 pm    Post subject: Reply with quote

David,

There is no RETI in your ISR. This because your RETURN is inside
an IF. When the RETURN is inside an IF, Bascom will generate the assembly RET.
To fix the problem just replace your RETURN with the assembly RETI.

Best regards,

Luciano


From the Bascom Help file:

ON INTERRUPT

The first RETURN statement that is encountered that is outside a condition will generate a RETI instruction. You may have only one such RETURN statement in your interrupt routine because the compiler restores the registers and generates a RETI instruction when it encounters a RETURN statement in the ISR. All other RETURN statements are converted to a RET instruction.
Back to top
View user's profile
davidapex

Bascom Member



Joined: 12 Mar 2006
Posts: 42
Location: Auckland

newzealand.gif
PostPosted: Tue May 16, 2006 1:32 am    Post subject: Reply with quote

Hello Luciano,
It may be time to give up on your worst student.

A quick change of code gives the following results:

An active low on the PCInt0 pin (portb.7) puts it in to keypad entry mode.
Upon entering "#" the RETI then returns somewhere but instantly ends up back at keypad entry with the PCInt pin as an active low (keypad mode?)
The interrupt pin briefly goes high (as it should) but almost immediately become low.
It's like another interrupt source occurs at the same time as the assembler routine runs.

Time to put it to one side I think.

Cheers,
David
Back to top
View user's profile
davidapex

Bascom Member



Joined: 12 Mar 2006
Posts: 42
Location: Auckland

newzealand.gif
PostPosted: Tue May 16, 2006 3:03 am    Post subject: Reply with quote

New theory - I think the RETI instruction is being ignored and the code simply runs in to the Goto Keypad instruction a couple of lines further on. I don't think it is going to the assembler routine at all.
The previous posted code does load the phase increment registers and run the assembler routine to output the new frequency but doesn't allow a second interrupt.

Cheers,
David
Back to top
View user's profile
Luciano

Bascom Member



Joined: 29 Nov 2004
Posts: 3149
Location: Italy

blank.gif
PostPosted: Tue May 16, 2006 9:12 pm    Post subject: Reply with quote

David,

I have fixed your code.

The interrupt is now triggered when you press one of the
key of the keypad. (Any key). Remember to remove the
external pull-up resistor on PortB7 if you have one.

* * *

After you flash the AVR, make sure you disconnect the ISP
programmer because also the ISP programmer uses pins of portB.
(With the 470 ohm resistors there is no danger for the AVR and the ISP).


* * *

The 256 bytes boundary for the table is not correctly set.
This is just a sample for your interrupt problem. The
code was tested with an ATmega48 and the STK500.

* * *

If you are using the ATmega168 and the ATMEL board STK500
make sure you remove the jumper XTAL1 on the STK500.
Also the PB6 and PB7 of the ATmega168 are not connected
to the port header PORTB of the STK500. These two pins
are connected to the port header PORTE/AUX where
PB6=XT1 and PB7=XT2.

* * *

Connect the keypad like that:
(The same code works with a 3x4 or a 4x4 keypad).

PB0---470 ohm----keypad c1
PB1---470 ohm----keypad c2
PB2---470 ohm----keypad c3
PB3---470 ohm----keypad c4
PB4---470 ohm----keypad r1
PB5---470 ohm----keypad r2
PB6---470 ohm----keypad r3
PB7---470 ohm----keypad r4

If you are using a 3x4 keypad, the pin PB3 is not connected.
(PB3 is not floating because the pin is an output and set to 0).


(Click to enlarge the picture)

Best regards,

Luciano


Code:

' Direct Digital Synthesis. (DDS)
' Frequency = r24/r25/r26* (xtal freq/cycles in loop)/16777216  (2^24)

$regfile = "m168def.DAT"
$crystal = 8000000
$hwstack = 32
$swstack = 16
$framesize = 32
'''$prog &HFF , &HC2 , &HFF , &HF9

'configure display on PORTC
Config Lcdpin = Pin,Db4=Portc.2,Db5=Portc.3,Db6=Portc.4,Db7=Portc.5,E=Portc.1,Rs=Portc.0
Config Lcd = 16 * 2
Cursor Off

' R2R ladder on PORTD
Config Portd = Output

'Enable Pin change interrupt on PB7,PB6,PB5,PB4
Pcmsk0 = &B11110000

'Set interrupt vector PCINT0 with NOSAVE
On Pcint0 Pcint0_isr Nosave

' 4x4 keypad port
Config Kbd = Portb , Debounce = 20 , Delay = 50

'Set data direction of PORTB
'INPUTS=PB7,PB6,PB5,PB4 / OUTPUTS=PB3,PB2,PB1,PB0
Ddrb = &B00001111

'OUTPUTS=PB3,PB2,PB1,PB0 set to 0
'Enable internal pull-up resistors on the inputs PB7,PB6,PB5,PB4.
Portb = &B11110000

Dim Add0 As Byte
Dim Add8 As Byte
Dim Add16 As Byte
Dim X As Byte
Dim Num As Byte

Dim Number As Long
Dim P As Long

'Wait that PORTB stabilizes
Waitms 10

'Clear Pcint0 flag set while the PORTB was stabilizing.
Set Pcifr.pcif0

' ===================================================================

Cls
Waitms 100
Lcd "Power on!"
Waitms 2000
Cls

Lcd "Main loop...."

Enable Pcint0
Enable Interrupts

 '***************************************************
$asm
Main_loop:

  add r28, r24        ' 1 cycle
  adc r29, r25        ' 1 cycle
  adc r30, r26        ' 1 cycle
  lpm                 ' 3 cycles
  Out Portd , R0      ' 1 cycle
  rjmp Main_loop      ' 2 cycles
$end Asm

End


'***************************************************

Pcint0_isr:

Disable Pcint0

Cls
Lcd "Interrupt!"
Waitms 1000
Cls

Locate 1 , 1
Lcd "Enter new value:"

Locate 2 , 1
Lcd "CLS=*  Enter=#"

Waitms 1000


Number = 0

Do

   X = Getkbd()
   Num = Lookup(x , Dta)

   If Num < 10 Then

      Locate 1 , 1
      Lcd "                "
      Number = Number * 10
      Number = Number + Num
      Locate 1 , 1
      Lcd Number

   End If


   If Num = 35 Then

      P = Number And &HFF0000
      Shift P , Right , 16
      Add16 = Low(p)

      P = Number And &H00FF00
      Shift P , Right , 8
      Add8 = Low(p)

      P = Number And &H0000FF
      Add0 = Low(p)

      Locate 2 , 1

      Lcd "HEX = " ; Hex(add16) ; " " ; Hex(add8) ; " " ; Hex(add0)
      Waitms 5000

      Exit Do

   End If


   ' * clear value
   If Num = 42 Then

      Locate 1 , 1
      Lcd "                "
      Number = 0

   End If

   'keypad repetition speed 500 ms
   Waitms 500

Loop


'**************************************

'Set data direction of PORTB
'INPUTS=PB7,PB6,PB5,PB4 / OUTPUTS=PB3,PB2,PB1,PB0
Ddrb = &B00001111

'OUTPUTS=PB3,PB2,PB1,PB0 set to 0
'Enable internal pull-up resistors on the inputs PB7,PB6,PB5,PB4.
Portb = &B11110000

'Wait that PORTB stabilizes
Waitms 10

Cls
Lcd "Exit Interrupt!"
Waitms 1000
Cls
Lcd "Main loop...."

' setup Z pointer hi
ldi ZH, high (Sine_table * 2)
' setup Z pointer lo
ldi ZL, low (Sine_table * 2)

' clear accumulator
ldi  r29,$00
ldi  r28,$00

'enable interrupt
Enable Pcint0

Loadadr Add0 , X      'LSB
ld r24, X
Loadadr Add8 , X
ld r25, X
Loadadr Add16 , X   'MSB
ld r26, X

'Clear Pcint0 flag
Set Pcifr.pcif0

' return to main loop.
' (Exit from interrupt routine, Bascom will generate a RETI).
Return


'***************************************************
'Keypad map
'A=65 B=66 C=67 D=68
'*=42 #=35
'No key pressed = 16

Dta:
Data 1 , 2 , 3 , 65
Data 4 , 5 , 6 , 66
Data 7 , 8 , 9 , 67
Data 42 , 0 , 35 , 68 , 16

'***************************************************
Dummy_data:

Data 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10
Data 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10
Data 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10
Data 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10
'Data 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10
'Data 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10
'Data 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10
'Data 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10
'Data 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10
'Data 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10
'Data 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10


' In this program the tables MUST begin at 256 byte boundary and the previous
' dummy_data bytes are used to reach the boundary.
' The boundaries are at (DEC) : 0, 256, 512, 768, 1024, 1280, 1536, 1792, 2048.......
' The boundaries are at (HEX) : 0, 100, 200, 300, 400, 500, 600, 700, 800.......
' You can use any of these boundaries.

Sine_table:
'256 values

Data &H80 , &H83 , &H86 , &H89 , &H8C , &H8F , &H92 , &H95
Data &H98 , &H9C , &H9F , &HA2 , &HA5 , &HA8 , &HAB , &HAE
Data &HB0 , &HB3 , &HB6 , &HB9 , &HBC , &HBF , &HC1 , &HC4
Data &HC7 , &HC9 , &HCC , &HCE , &HD1 , &HD3 , &HD5 , &HD8
Data &HDA , &HDC , &HDE , &HE0 , &HE2 , &HE4 , &HE6 , &HE8
Data &HEA , &HEC , &HED , &HEF , &HF0 , &HF2 , &HF3 , &HF5
Data &HF6 , &HF7 , &HF8 , &HF9 , &HFA , &HFB , &HFC , &HFC
Data &HFD , &HFE , &HFE , &HFF , &HFF , &HFF , &HFF , &HFF
Data &HFF , &HFF , &HFF , &HFF , &HFF , &HFF , &HFE , &HFE
Data &HFD , &HFC , &HFC , &HFB , &HFA , &HF9 , &HF8 , &HF7
Data &HF6 , &HF5 , &HF3 , &HF2 , &HF0 , &HEF , &HED , &HEC
Data &HEA , &HE8 , &HE6 , &HE4 , &HE2 , &HE0 , &HDE , &HDC
Data &HDA , &HD8 , &HD5 , &HD3 , &HD1 , &HCE , &HCC , &HC9
Data &HC7 , &HC4 , &HC1 , &HBF , &HBC , &HB9 , &HB6 , &HB3
Data &HB0 , &HAE , &HAB , &HA8 , &HA5 , &HA2 , &H9F , &H9C
Data &H98 , &H95 , &H92 , &H8F , &H8C , &H89 , &H86 , &H83
Data &H80 , &H7C , &H79 , &H76 , &H73 , &H70 , &H6D , &H6A
Data &H67 , &H63 , &H60 , &H5D , &H5A , &H57 , &H54 , &H51
Data &H4F , &H4C , &H49 , &H46 , &H43 , &H40 , &H3E , &H3B
Data &H38 , &H36 , &H33 , &H31 , &H2E , &H2C , &H2A , &H27
Data &H25 , &H23 , &H21 , &H1F , &H1D , &H1B , &H19 , &H17
Data &H15 , &H13 , &H12 , &H10 , &H0F , &H0D , &H0C , &H0A
Data &H09 , &H08 , &H07 , &H06 , &H05 , &H04 , &H03 , &H03
Data &H02 , &H01 , &H01 , &H00 , &H00 , &H00 , &H00 , &H00
Data &H00 , &H00 , &H00 , &H00 , &H00 , &H00 , &H01 , &H01
Data &H02 , &H03 , &H03 , &H04 , &H05 , &H06 , &H07 , &H08
Data &H09 , &H0A , &H0C , &H0D , &H0F , &H10 , &H12 , &H13
Data &H15 , &H17 , &H19 , &H1B , &H1D , &H1F , &H21 , &H23
Data &H25 , &H27 , &H2A , &H2C , &H2E , &H31 , &H33 , &H36
Data &H38 , &H3B , &H3E , &H40 , &H43 , &H46 , &H49 , &H4C
Data &H4F , &H51 , &H54 , &H57 , &H5A , &H5D , &H60 , &H63
Data &H67 , &H6A , &H6D , &H70 , &H73 , &H76 , &H79 , &H7C

 


Last edited by Luciano on Thu May 03, 2007 9:00 pm; edited 4 times in total
Back to top
View user's profile
davidapex

Bascom Member



Joined: 12 Mar 2006
Posts: 42
Location: Auckland

newzealand.gif
PostPosted: Wed May 17, 2006 9:19 am    Post subject: DDS Reply with quote

Hello Luciano,
That's fantastic! Worked like a treat. E-beers all round.

I very much appreciate the time you have taken to develop the code and although I now have a great solution I still need to go through the code and learn from it.

The only change needed to get it going perfectly was the dummy data offset (expected) and I also tweaked the timing as the keypad behaved a little sleepy.

I will go through the code carefully to be sure I can follow everything but it does not look too bad.
Now, about those dovetail waveforms.........

Thanks again. If you're ever down this way I will make those real beers.

Cheers,
David
Back to top
View user's profile
davidapex

Bascom Member



Joined: 12 Mar 2006
Posts: 42
Location: Auckland

newzealand.gif
PostPosted: Thu May 18, 2006 11:29 am    Post subject: DDS Reply with quote

Hi All,
As a final footnote to this interesting thread I have observed a curious trend in the input number vs output frequency of this DDS.

With the 8MHz oscillator the 24 bit phase accumulator register and 9 cycle assembler loop you would need to multiply the number keyed in by 18.874368 or approx 151/8 to get number in =frequency in Hz out. This is easily done by adding a few more lines of code to Luciano's good work. Regardless of this ratio the output frequency should be linear to the input number.

This is what I have found (without the fudge factor of 151/8 applied)

Input number Freq Hz
1000 41.27
2000 96.20
4000 206.2
8000 426.0
16000 851.2
32000 1717
64000 3436
128000 6872
256000 13740
512000 27480

It appears to be quite linear from around 16000 upwards but not below 16000. The lowest entry of 1000 should return a frequency of approx 53Hz. I don't think it's my set up as I have measured other DDS units over a similar range with complete linearity.
Can anyone suggest why the smaller numbers are running so much slower than they should?

The frequency is determined by the following loop and the phase increment constant.

Main_loop:

add r28, r24 ' 1 cycle
adc r29, r25 ' 1 cycle
adc r30, r26 ' 1 cycle
lpm ' 3 cycles
Out Portd , R0 ' 1 cycle
rjmp Main_loop ' 2 cycles

Can any of these instructions change from 1 to 2 cycles depending on the numbers used?

I'm happy with the results I'm getting but would be interested in any academic input to this odd effect.

Best regards,
David
Back to top
View user's profile
Luciano

Bascom Member



Joined: 29 Nov 2004
Posts: 3149
Location: Italy

blank.gif
PostPosted: Fri May 19, 2006 11:52 am    Post subject: Reply with quote

Hi,

(See original post on page 1 of this thread).

Code:

At 8 MHz:

' Output frequency (using 24 bit accumulator) :
  '
  ' f = deltaPhase * fClock/2^24
  '
  ' fClock is in this case the CPU clock divided by the
  ' number of cycles to output the data ( 9 cycles )
  '
  ' f = r24/r25/r26 * (8000000/9)/16777216
  '
  ' f = r24/r25/r26 * 0.0529819064670138
  '
  ' fMax (theoretical) = 0.5 * fClock



Example 1000 Hz:
1000 / 0.0529819064670138 = 18874.3680  (Value r24/r25/r26 = 18874)

Example 10000 Hz:
10000 / 0.0529819064670138 = 188743.6800 (Value r24/r25/r26 = 188743)

 


Best regards,

Luciano
Back to top
View user's profile
davidapex

Bascom Member



Joined: 12 Mar 2006
Posts: 42
Location: Auckland

newzealand.gif
PostPosted: Fri May 19, 2006 1:43 pm    Post subject: Reply with quote

Hello Luciano,
I did just format a reply to your post but the button I hit sent it off to data heaven. Here we go again.

The table I have shown is r24/r25/r26 value againt frequency output

Fisrt entry is
1000 * 0.0529.... = 52.9Hz but I am only seeing 41.27Hz.

The first three entries show a progressive non-linearity with only the higher values being correct.
To be out by over 20% at the low frequencies would require a further two clock cycles in the assembler routine.
It seems to me that the assembler loop delay is somewhat value dependent but this just does not seem possible. Have I overlooked something?

Cheers,
David
Back to top
View user's profile
Luciano

Bascom Member



Joined: 29 Nov 2004
Posts: 3149
Location: Italy

blank.gif
PostPosted: Fri May 19, 2006 2:20 pm    Post subject: Reply with quote

David,

The problem was the position of the line of code "Enable Pcint0" at
the end of the interrupt routine. (Bascom uses R24 for it).

I have also added the two lines below but this is not mandatory.

ldi r29,$00
ldi r28,$00

I have edited the code in my previous post.
You will have to set the 256 bytes boundary for the table.

Best regards,

Luciano
Back to top
View user's profile
Display posts from previous:   
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    www.mcselec.com Forum Index -> BASCOM-AVR Archive All times are GMT + 1 Hour
Goto page Previous  1, 2, 3, 4, 5, 6  Next
Page 3 of 6

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum