40.00 KHz
BebopALot
Posts: 79
Hey folks, I wrote some code to produce as accurately a 40KHz wave as possible and my o-scope picks up 40.00 + / - .01 fluctuation. Is this pretty good (I really don't know with the SX) or should I try for better stability? I'm runningit at 5.120 MHz.
BBAL
BBAL
Comments
I wouldn't trust the oscope for a frequency measurement. That is not what they are designed for. Get a frequency counter.
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"SX-Video·Module" Now available from Parallax for only $28.95
http://www.parallax.com/detail.asp?product_id=30012
"SX-Video OSD module" Now available from Parallax for only·$49.95
http://www.parallax.com/detail.asp?product_id=30015
Product web site: www.sxvm.com
"Ability may get you to the top, but it takes character to keep you there."
·
Could you post your code, because if properly written, there should not be ANY fluctuation in the signal; it should be rock-steady. Perhaps your code is giving you some asymmetry.
Cheers,
Peter (pjv)
Generate_Waves
;HI WAVE 1
Mov w,#$0e
Mov !ra, w ; go HI bit 1 RA
mov w, #$10
mov Hi_Counter1, w
Delay_1:
decsz Hi_Counter1
jmp Delay_1
;LO WAVE 1
Mov w,#$0f
Mov !ra, w ; go LO bit 1 RA
mov w, #$0f
mov Lo_Counter1, w
Delay_2:
decsz Lo_Counter1
jmp Delay_2
NOP
NOP
;
;HI WAVE 2
Mov w,#$0e
Mov !ra, w ; go HI bit 1 RA
mov w, #$0f
mov Hi_Counter2, w
Delay_3:
decsz Hi_Counter2
jmp Delay_3
;LO WAVE 2
Mov w,#$0f
Mov !ra, w ; go LO bit 1 RA
mov w, #$0f
mov Lo_Counter3, w
Delay_4:
decsz Lo_Counter3
jmp Delay_4
NOP
NOP
;
;HI WAVE 3
Mov w,#$0e
Mov !ra, w ; go HI bit 1 RA
mov w, #$0f
mov Hi_Counter3, w
Delay_5:
decsz Hi_Counter3
jmp Delay_5
;LO WAVE 3
Mov w,#$0f
Mov !ra, w ; go LO bit 1 RA
mov w, #$0f
mov Lo_Counter3, w
Delay_6:
decsz Lo_Counter3
jmp Delay_6
NOP
JMP Generate_Waves
You are wiggling the port bit by alternately making it an input and then an output. That is not the correct way to do things. Write your code to make port ra.1 an output only once, and the make that output alternately be high or low. There are many ways to accomplish that, one simple way (not the best way) is included.
SetDir····· ·mov m,#$0f·· ·;set mode to access tris direction registers
·············· mov w,#%1111_1101 ;port bit 1
·············· mov !ra,w······ ;make port ra.1 be an output, all others remain input
Waves···· ·setb ra.1······· ·;set port a.1 high
·············· mov w,#$10··· ;delay value
·············· mov Delay,w·· ·;load the delay counter
Delay1···· ·decsz Delay··· ·;loop until
·············· jmp Delay1···· ·;delay is done
·············· nop·············· ·;time adjust for end of cycle "jump"
·············· nop·············· ·;time adjust for end of cycle "jump"
·············· nop·············· ·;time adjust for end of cycle "jump"
·············· clrb ra.1········· ;reset port a.1
···············mov w,#$10···· ;delay value
·············· mov Delay,w· ·;load the delay counter; can be same variable as before only one is running at a time
Delay2···· ·decsz Delay··· ·;loop until
·············· jmp Delay2···· ·;delay is done
·············· jmp Waves····· ;the jump consumes 3 instruction cycles
Hope this helps.
Cheers,
Peter (pjv)
Post Edited (pjv) : 2/4/2006 2:55:38 AM GMT
Thanks, PeterM
Two questions:
1. is "clrb" a compound statement?
2. I don't understand your syntax "mov w,#%1111_1101 ;port bit 1" - that is, what does the underscore do? RA in the SX28 is 4 bits so wouldn't we do...mov w,#%1101...to set ra.1 as output?? I think that's what you mean, I just want to make sure.
3. In Geunther's book and other literature the command to change the direction register is often NOT preceded by accesssing the mode. Sometimes you will see:
Mov rb!, #%00000001
Is that just a bad habit/another way of doing it?
4.finally, is ra! shorthand for TRIS_A...ciukd you write this:
mov M, $0f ;access mode
mov w, #%1110 ; make ra.0 an output
mov ra!, w
Much appreciated
BBAL
Post Edited (BebopALot) : 2/4/2006 1:50:21 PM GMT
Sorry, was travelling all day from San Juan Puerto Rico, so was out of touch since last nite.
PJ Monty is absolutely correct that this method is a poor way to tackle this issue, and the interrupt should be used instead.
Since you started this way, and you're struggling, I tought it best to help by continuing in the vain that you started, as that would probably be easier for you by not dumping you into the ISR issues all at once.
Now, to answer your questions.....
1. No, clrb and setb are proper SX instructions.....please READ the documentation.
2. The syntax %1111_1101 is a bit oriented syntax. Again, read the docs. The underscore is simply a convenience tolerated by the assembler to make a byte expressed in bits a little more readable. It has no other function. Yeah, my mistake, to be correct I should have limited the w value to 4 bits, but the assembler interprests it correctly, and in the SX52, ra DOES have 8 bits.
3. Unfortunately I have none of Guenther's books, so I can't comment there. But, there is no such thing as "mov rb!"....but there IS "mov !rb", and it refers to the affiliated port configuration registers, pre selected by the MODE value. The value in mode defaults to $0F on pwer-up and RESET, and its value is reatained until you change it by program.
4. No, (I presume you mean) "!ra" meand write the w valu to the ra port configuration register (pre)selected by m, the mode register.
Hope you're getting onto the right path, and when you feel ready to tackle this with an ISR, as PJ suggested, give a holler, and we'll help out.
Cheers,
Peter (pjv)
Post Edited (pjv) : 2/5/2006 5:33:09 AM GMT
I went ahead and recoded by toggling the output register and not the direction ports. Works OK. But now you and Mr.PJ Monty had to go and "muck it up" (hehe) by getting me interested in the ISR approach. Before I read up on it, but please explain to me why this would be better (big picture stuff) in acheiving accuracy so I understand. You know, what is the advantage.
Regards, BBAL
The Sx has an internal clock (RTCC) that can generate interrupts. How often they happen depends on the settings of RTCC. When an interrupt occurs, it literally "interrupts" the computer, stops processing whatever code it was in the middle of, and jumps to address 0. You place code at address 0 that you want executed during the interrupt. When you're done, you return from the interrupt and the SX will pickup exactly where it left off. There are details about how to handle all of this, but that is the essence of what you do and what happens.
The typical analogy given is to imagine if telephones didn't have ringers. In order to know if a call was coming, you would have to keep picking up the phone and saying, "Hello?" to see if anyone was calling. That would completely suck and it would occupy a lot of your day because if you didn't do it often enough, it possible that someone would call, you wouldn't check to see if anyone was calling, and they would hang up only to be followed by you checking after they hung up. An interrupt is like the ringer on the phone - when you hear it, you stop what you're doing, answer the phone, and then hangup and return to what you were doing - far more efficient.
Now, imagine that your interrupt was set to 80 khz. All you would have to do in your interrupt code is toggle a bit. The reason for 80 khz is that on every other interrupt, you would toggle the bit high or low. This would give you a 40 khz output with a 50% duty cycle. In addition, you could do anything else you wanted in your main code and the 40 khz output would continue unimpeded. It's nifty and incredibly powerful stuff, but it's also tricky since there are new and interesting ways to have buggy code.
Thanks, PeterM
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"SX-Video·Module" Now available from Parallax for only $28.95
http://www.parallax.com/detail.asp?product_id=30012
"SX-Video OSD module" Now available from Parallax for only·$49.95
http://www.parallax.com/detail.asp?product_id=30015
Product web site: www.sxvm.com
"Ability may get you to the top, but it takes character to keep you there."
·
I saw your SX-B code only after I struggled with the RTCC in assembly on my own. Downside: got blurry vision reading and less sleep. Upside: learned a lot.
Here is my intial code as a foundation of the final program I am writing. I am controlling 2 seperate bursts with long waits in between, but that code is pending.
Checked on SX-Sim the interrupt occurs every 64 cycles = 12.5 us (on + off = 40 KHz). I know my interupt routine can only be nc-7 cycles long otherwise I get an error. I'll post my final code when I get it working.
;5.120 MHz version
Device SX28L, Turbo, Stackx, OSCHS3
IRC_CAL IRC_SLOW
FREQ 5_120_000
RESET Start
ORG $000
Interrupt ; interrupt Routine - always starts at $00
Mov w,#-64
Retiw
Start
; configure ports
Mov M, #$0f ; access TRIS mode
Mov W, #%0000 ; bits 0-3 are outputs
Mov !Ra, W ; make Ra0-Ra3 outputs
Mov M, #$0f ; access TRIS mode
Mov W, #%0000_0000 ; all bits output
MOv !Rb, W ; set Port B pins to output
Mov M, #$0f ; access TRIS mode
Mov !Rc, w ; set Port C pins to output
; configure RTCC rollover interrupt
Mov w, #$9f
Mov !option, w ;enable RTCC rollover interrupt
Mov w, #$c0
Mov rtcc, w ;initialize RTCC value to 192
; de-glitch initial state
Mov w, #%1001
Mov Ra, w ;set register A output to Ra0,Ra3 = 1 Ra1,Ra2=0
Mov w, #%0000_0000
Mov Rb, w ;set register B output to digital LOW
Mov w, #%0000_0000
Mov Rc, w ;set register C output to digital LOW
MAIN
Loop
JMP LOOP
A couple of point to help get you going.....
1. Once you set the mode to $0F (TRIS), it will stay that way until you change it, so there is no need to repeat the mode statement it to configure the second and third port.
2. To de-glitch the initial state, you ought to set the output registers to their intended values before you make the ports an output. If you don't, then you may get a glitch for the duration between making a port an output, and then setting its value. If you first set the value, and then enable them as outputs, they will come up in their intended state.
3. The same holds for RTCC. You should set its value before you enable it. The reason is there is a (small) chance that on power up the RTCC had an arbitrary large value, say 254 or 255, then as soon as you enable the RTCC, it will quickly overflow and jump into the interrupt routine at 0 right away, before it has had a chance to complete the initialization.
These are probably not catastrophic, but just a better way of doing things.
Cheers,
Peter (pjv)
Post Edited (pjv) : 2/8/2006 6:09:07 PM GMT
I have been trying to write the next stage. The problem is that in order to use an accounting method of interupts polled to toggle my bits I am forced to use comparison statements of multibyte counter variables. I can control the bursts no problem but the wait time in between bursts can approach 4ms which equates to some 300+ cycles and if using two transmitters 600+. My wait/burst ratio is huge. 4.0ms/75us. It would be nice to use the intertupts to trigger the bursts but it has to be conditional because there are more times NOT to trigger the bursts than to do so. I was using a retw table to write the pin HI/LO states based on interupt count and by controlling a program pointer to the state to be written.
Now another way to do this would be to set the interrupt cycles at 4.0ms (RTCC hook) or some multiple instead of 12.5us and have the interrupt rountine toggle the transmitters on interrupt. Simply do the inverse. But then, in a way, I would be back where I started becuase I would have to hard code the burst because I would be using the interrupt cycles for the wait.
Is it possible to program more than one interrupt for the SX?
Post Edited (BebopALot) : 2/9/2006 6:28:21 PM GMT