Shop OBEX P1 Docs P2 Docs Learn Events
Using a Variable for an Interrupt Rate? — Parallax Forums

Using a Variable for an Interrupt Rate?

gtslabsgtslabs Posts: 40
edited 2007-08-10 14:33 in General Discussion
I have the following code that is supposed to output a variable frequency square wave from 1 to 1000 Hz by 1 Hz as accurate as possible.· I am using the SX28 50Mhz just for this purpose and I am sending it a WORD that represents the frequency.· I want to use the Interrupt function if possible but I found that the it wont accept a variable for the "rate" parameter.

The code looks for RA.1 pin to be high meaing a new frequency is available from the host. It should read in the new frequency word and set the interrupt rate to it.

How can I make this work?
Thanks
Steve

DEVICE          SX28, OSChs1, TURBO, STACKX, OPTIONX
FREQ            50_000_000
 
OutPin          PIN  RA.3 OUTPUT     'Square Wave output Pin
Sio             VAR     RA.0         ' pull-up via 4.7K
SioReady        VAR     RA.1         ' Pulled High if data ready from extrnal source
 
sData           VAR     Word         ' Serial Input must be 1-1000

 
Baud            CON     "T2400"
 
INTERRUPT sData ' 1000 = 1000 uSec

'Variable not working with Interrupt
 
'Typical Ranges needed
'Frequency = 1Hz  Period = 1 Seconds
'Frequency = 10Hz  Period = 0.1 Seconds
'Frequency = 100Hz  Period = 0.01 Seconds
'Frequency = 500Hz  Period = 0.02 Seconds
'Frequency = 1000Hz  Period = 0.001 Seconds
 
outpin = NOT Outpin  'Toggle the output 50% Duty
 
  RETURNINT
 
 
Program Start
Start:
 
If SioReady = 1 then
    SERIN Sio, Baud, sData_LSB, 1000, No_Char     ' wait for byte
    SERIN Sio, Baud, sData_MSB, 1000, No_Char     ' wait for byte
endif  

No_Char:
  If sData=0 then Start 'If no data received then keep looking.
 
sData = 1000 ' Use for testing purposes only while not connect to host.

Comments

  • JonnyMacJonnyMac Posts: 9,274
    edited 2007-08-05 14:44
    The RATE parameter of INTERRUPT is a compiler directive; it is used at compilation, not run time. You can manipulate the ISR rate by changing the RETURNINT value -- but it's only eight bits (the RTC roles over from 255 to 0 and triggers the interrupt). Also, when your running an interrupt you can't use SERIN unless the interrupt timing has been accounted for with the EffectiveHz parameter (see the help file under FREQ directive).
  • gtslabsgtslabs Posts: 40
    edited 2007-08-06 15:39
    After researching this more what it looks like I need is the PWMPAL. But at $30 it is too expensive. I called tech support and they sdaid it just uses the SX28 chip which I have.· It appears that is uses something similar to the TIMER PWM function on the SX48. Tech support said that the 28 was the same as the 48 except for the number of I/O pins and that that function should work on the SX28 even though the documentaion says it is only for the 48/52.
  • JonnyMacJonnyMac Posts: 9,274
    edited 2007-08-06 16:06
    The counter/timers exist only on the SX48/52 -- the Tech Support person you spoke with misspoke. When in doubt, consult the SX documentation.

    The program that's attached is from my July Nuts & Volts article; it shows how to do PWM control (for motors) using a serial command. What's important is that I'm using the ISR to receive the serial command and do the PWM. It will take some work on your part but you could modify this program to get to get to your goal.
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-08-07 16:03
    I would approach this problem by calling a subroutine at a 1Hz or sub-multiple of 1Hz frequency from within an interrupt. The first thing I would have the ISR do is check the status of a ‘toggle’ flag. If it is set then toggle the output pin and clear the toggle flag. The ISR would then call a subroutine that handles the logic for determining when the toggle flag should be set again. If the interrupt were set to occur every 250ms then toggling the output on every other call would generate a 1Hz square wave.

    The reason I would use and first check a toggle flag in the ISR is to provide consistent timing for the actual output switching without needing to worry about maintaining consistent timing in my logic subroutine. If you perform your logic and then toggle your output during the same interrupt, your logic timing must be consistent. If you set a flag and toggle your output first thing on the next interrupt, you get consistent timing without a lot of programming hassle.

    That is how I would approach it.

    - Sparks
  • gtslabsgtslabs Posts: 40
    edited 2007-08-07 19:44
    Thanks for everyones help.
    I finally got my head around how the interrupts work. I used some examples to get to this point:
     -------------------------------------------------------------------------
    ' Device Settings
    ' -------------------------------------------------------------------------
    DEVICE          SX28, OSChs1, TURBO, STACKX, OPTIONX
    FREQ            50_000_000
    ID  "ISR LED"
    ' -------------------------------------------------------------------------
    ' IO Pins
    ' -------------------------------------------------------------------------
    IrLed  VAR RB.0   ' IR LED control
    counter Var Word
    ' -------------------------------------------------------------------------
      INTERRUPT NOPRESERVE 100_000
    ' -------------------------------------------------------------------------
    INC counter
    IF counter = 500 THEN
        IrLed = NOT IrLed
        counter = 0
       ENDIF
    RETURNINT 
    ' =========================================================================
      PROGRAM Start
    ' =========================================================================
    Start:
      LOW IrLed     ' make output, off
    Main:
      
      GOTO Main
    

    But I am having problems with truncation introducing error.
    I read http://forums.parallax.com/attachment.php?attachmentid=47571
    and saw what he did to get the accuracy up but he was limited to 382 hz on the low end.


    I am getting the recirpical of the frequency and using that for the counter word. But the problem is like this.
    If I want 962 Hz then I take 1/(2*962*0.00001) toget the counter of 51.98 but it is truncated to 51 which is actually 980.4 hz. This is a -1.88% error.
    So I was working on how to get the remainder of 0.98 into a do nothing loop to make the frequency closer.


    I was going to use shiftin to get the new frequency because of the serin interrupt issues.

    I orderd the SX48 proto board so I can play with the timer1 pwm function. But there again I will still have the same error.

    Steve
  • JonnyMacJonnyMac Posts: 9,274
    edited 2007-08-08 18:08
    Just for fun (and for possible inclusion in my book on SX/B programming...) I wrote the attached program. It runs the ISR at 80 kHz which is pretty close to serial bit timing for 9600 baud and lower; by using a "clean" value for the ISR you can get precise control of your PWM output, especially if you set the phase parameters directly. In addition to the SX program I've attached a BS2 demonstrator. I checked the output on the scope and at 25 Hz, anyway, it's dead on. Odd frequency values may be off a little due to integer division -- unless you set the phase parameters manually.

    Correction: After looking at the code after a break I found that the PWM VP was adding an extra cycle to each phase -- that's been fixed.

    Post Edited (JonnyMac) : 8/8/2007 10:10:40 PM GMT
  • gtslabsgtslabs Posts: 40
    edited 2007-08-09 18:09
    Thanks Jon, that is what I needed! Very Nice work.
    I tried sending it a Frequency value of 1 and I get back ~ 5Hz.
    I have not tried the upper limit yet.
    Can you confirm that?
  • JonnyMacJonnyMac Posts: 9,274
    edited 2007-08-09 19:44
    There appears to be an error with the division when freq is set to 1 Hz. I have attached ports RB and RC to leds and am debugging by displaying the frequency (always correct) and the phaseLo value (not correct for 1 Hz). It's odd, because in a separate test program I performed the same math and the result is correct.... I'm going to take a break and look at it with fresh eyes later.
  • JonnyMacJonnyMac Posts: 9,274
    edited 2007-08-10 14:33
    Well... I'm still stumped; the problem makes no sense to me. You can patch the program like this:

    Freq_To_Phase:
      IF frPwm = 1 THEN
        phaseLo = 51_200
        phaseHi = 51_200
      ELSE
        phaseLo = 51_200 / frPwm
        phaseHi = phaseLo
      ENDIF
    



    Note that I changed the ISR rate to allow for faster, more accurate baud rates -- this changes the phase timing resolution from 12.5 uS to 9.766 uS; this makes the pwm frequency range from 0.78 Hz to 51.2K Hz. You'll get the best control by sending the phase values directly as is allowed in the protocol.

    Post Edited (JonnyMac) : 8/10/2007 3:53:58 PM GMT
Sign In or Register to comment.