Shop OBEX P1 Docs P2 Docs Learn Events
40.00 KHz — Parallax Forums

40.00 KHz

BebopALotBebopALot Posts: 79
edited 2006-02-09 18:11 in General Discussion
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

Comments

  • BeanBean Posts: 8,129
    edited 2006-02-03 19:15
    BBAL,
    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."
    ·
  • BebopALotBebopALot Posts: 79
    edited 2006-02-03 21:38
    Some good advice, both. The pick of 5.120 MHz interestingly was to power my "Frankenstein creation", an amalgam of high speed async. binary counters, Johnson counters and gates to produce this signal, until I listened to some good sense from you folks and got it all in one package - the SX! I had already ordered the crystal and I was going to divide down its frequency through a 14 stage binary counter to 80 KHz and power a Johnson flopping about but then I'd miss all the fun with the SX. The only trade off to increasing from 5.120 to 10.24 or anbother mult. MHz to reduce fluctuations would be increased heat and possibly skips in instructions. But one member already mentioned that could be minimized be using lower voltage 3.3v for the Sx. But I think before I do that I should measure the frequency with a good counter as suggested. I do have a digital o-scope and I think those are a little less reliable then your CRT type. I'll go on Ebay and look at some counters.
  • pjvpjv Posts: 1,903
    edited 2006-02-04 01:42
    Hi Bebop;

    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)
  • BebopALotBebopALot Posts: 79
    edited 2006-02-04 02:00
    Here goes (generates 3 waves then restarts):

    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
  • pjvpjv Posts: 1,903
    edited 2006-02-04 02:51
    Hi Bebop;

    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
  • PJMontyPJMonty Posts: 983
    edited 2006-02-04 03:49
    I would just use the RTCC and generate the clock in the interrupt. What's the point of having a jitter free interrupt (a very rare thing indeed) if you're going to throw it away and just do hard coded delay loops in the main body of the code? I don't think you can generate a single RTCC event that is long enough, but just use a shorter one and keep track in the interrupt of how many times the interrupt has occurred and toggle the bit as needed.
      Thanks, PeterM
  • BebopALotBebopALot Posts: 79
    edited 2006-02-04 06:24
    So PJV - to make sure I understand correctly - what I was doing was changing the I/O status of the PIN via TRIS not directly setting the logic level of the PIN - right? I knew something was wrong! Using the above code the only way I could generate a readable voltage and a 40KHz signal was by connecting a 1k resistor to the RA0. Hello! If I "wiggled" the port output register bit instead I wouldn't need that resistor. But I do think its interesting that in my ignorance I was toggling the TRIS for "logic" functions instead of the port output reigster and made a nice wave. I got so turned around on this that I made a seperate post asking why I needed a 1k resistor to make the thing work right. Egad!

    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
  • pjvpjv Posts: 1,903
    edited 2006-02-05 05:30
    Hi Bebop;

    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
  • BebopALotBebopALot Posts: 79
    edited 2006-02-05 23:43
    Hi Pjv, thanks for catching back up. I am boning up on the syntax and code - thanks for answering my questions. There is ample documentation on the site and surprisingly, the SX28 datasheet has a very nice register mode summary. My insistence on syntax was to pin down the code to reconcile some different ways within the literature I have seen things done, and I consider myself now to be correctly programmed : ).

    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
  • PJMontyPJMonty Posts: 983
    edited 2006-02-07 11:05
    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
  • BeanBean Posts: 8,129
    edited 2006-02-07 15:17
    This is dead easy with SX/B.
    DEVICE SX28, OSCXT2, TURBO, OPTIONX, STACKX
    FREQ 5_120_000
     
    OutPin  VAR RC.4
     
    INTERRUPT NOCODE
      OutPin = ~OutPin     ' Toggle state of output pin
    RETURNINT 64           ' Repeat every 64 clocks ([url=mailto:80KHz@5.12MHz]80KHz @ 5.12MHz[/url])
     
    PROGRAM Start NOSTARTUP
     
    Start:
      OUTPUT OutPin       ' Set pin as output
      OPTION = $88        ' Setup RTCC interrupts with no pre-scaler
    END
    
    

    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."
    ·
  • BebopALotBebopALot Posts: 79
    edited 2006-02-08 17:13
    "Doggone" : )

    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
  • pjvpjv Posts: 1,903
    edited 2006-02-08 18:06
    Hi Bebop;

    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
  • BebopALotBebopALot Posts: 79
    edited 2006-02-09 18:11
    Thaks PJV, I fixed that part of my code.

    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
Sign In or Register to comment.