saving RCREG to word


Closed Thread
Results 1 to 8 of 8
  1. #1

    Question saving RCREG to word

    Hello,

    I would appreciate your help and need a fresh pair of eyes on the issue I have.
    I currently have a byte that is saved every time the UART interrupts with RCREG data ready. This only allows me at 4800bps 2ms between received bytes.

    The main section of the code takes two consecutive bytes and merges them into a word in basic. Then drops through to send out a 1 ~ 2ms pulse width proportional to servo position.
    The servo movement is a bit coarse which tells me that in the time I am sitting in the pauseus timing the pulse width, that I am dropping received UART bytes. This is because the part of the code that merges the bytes never runs since it iterrupts every 2ms in the middle of a pausus command.

    If I handle the byte to word merging in the interrupt it will give me about 4ms of time to take care of servicing the servo (2ms max needed).
    I would like to handle the merging of the two consecutive bytes in the interrupt assembly section to minimize PBP overhead. How can I do this with the least amount of clock cycles? see below snippet.







    ' Assembly language UART INTERRUPT handler
    Asm
    myint

    ; Uncomment the following if the device has less than 2k of code space
    ; movwf wsave ; Save W
    ; swapf STATUS, W ; Swap STATUS to W (swap avoids changing STATUS)
    ; clrf STATUS ; Clear STATUS
    ; movwf ssave ; Save swapped STATUS
    ; movf PCLATH, W ; Move PCLATH to W
    ; movwf psave ; Save PCLATH

    ; Save the FSR value for later
    movf FSR, W ; Move FSR to W
    movwf fsave ; Save FSR


    ; Read and store the character from the USART
    movf RCREG, W ; Read the received character
    movwf _tempbyte ; contains new UART received byte
    incf _Btcounter,F ; passed to main to track 2 consecutive bytes





    ; Restore FSR, PCLATH, STATUS and W registers
    finished
    movf fsave, W ; retrieve FSR value
    movwf FSR ; Restore it to FSR
    movf psave, W ; Retrieve PCLATH value
    movwf PCLATH ; Restore it to PCLATH
    swapf ssave, W ; Retrieve the swapped STATUS value (swap to avoid changing STATUS)
    movwf STATUS ; Restore it to STATUS
    swapf wsave, F ; Swap the stored W value
    swapf wsave, W ; Restore it to W (swap to avoid changing STATUS)
    retfie ; Return from the interrupt



    EndAsm

  2. #2
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    It's more like 6ms.

    There's the 2-byte buffer, and you can receive all but the last bit of the 3rd byte before it overflows. But in order to get that time, you'll have to disable the RCIE bit. Otherwise, since you are using ASM interrupts, it'll trigger the handler and interrupt the Pulsout timing on every byte received.

    But anyway, the servo pulses should only be sent every 20ms (50hz). If you have continuous data coming in, and you're sending a pulse every time you get a new word ... the servo's not going to like it.
    <br>
    DT

  3. #3


    Did you find this post helpful? Yes | No

    Default

    Darrel,

    thanks for confirming the ~ 3bytes buffer. I guess I need to change the part of the code that is in main and move it to the interrupt.

    Please tell me if this is possible or if I completely missed it. I want to create a 4 word buffer, each word holds a manchester encoded servo position. Every interrupt will pack a byte into the high portion of the word and the next interrupt packs the lower byte of the word. It does this for the remaining 3 words. In main, the code looks at the byte number index and determines which servo to update out of the 4 servos.

    The idea is to keep the bytes streaming in up to date even when in the pauseus pulse output portion of the code.

    Can I in the inline assembly specify moving an 8bit register into the "high" or "low" byte of a variable? Like movf servo1.L, RCREG and movf servo1.H,RCREG ?

    Thanks!

  4. #4
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Macgman2000 View Post
    ... Can I in the inline assembly specify moving an 8bit register into the "high" or "low" byte of a variable? Like movf servo1.L, RCREG and movf servo1.H ...
    No problem,

    Let's say you have a WORD variable in BANK0 ... (It should be in BANK0).

    TempWord VAR WORD BANK0

    in ASM, the LowByte comes first, so that's at the address of the variable itself.
    &nbsp; &nbsp; movwf &nbsp; &nbsp; _TempWord

    The HighByte is 1 address more
    &nbsp; &nbsp; movwf &nbsp; &nbsp; _TempWord + 1
    DT

  5. #5


    Did you find this post helpful? Yes | No

    Default Driving 8 servos

    Not sure I understand what you are doing but I found for an RC aircraft/UAV that 256 servo positions gives plenty of resolution and very smooth flight. By pulling the servo data down to a byte variable I have heaps of time to send 8 channels of servo data every frame time for very smooth servo operation.

    I have one PIC16F88 decoding the incoming radio PPM stream and building a fast packet of 8 single byte servo positions (plus start and checksum characters) at 115600 bps using Debug.

    The radio decoder measures the width of the 8 incoming channel pulses. It has the 4 - 12 mSec gap at the end of the frame in which to send a fast packet. At 115600 bps this takes about 2100 uSecs to send. This is fast enough to complete before the 16F88 has to find the next incoming data frame.

    This fast packet is massaged by a PIC16F887 where height hold, GPS and stability corrections are applied and a new past packet is built and sent to several 'servopods' that drive 1, 2 or 4 servos. The servopod reads the incoming packet and uses the new data if the checksum is good. Otherwise it uses last known good data for that channel.

    It all runs under PBP and needs no assembler accept for setting the WDT.

    Code:
    Data @0,$0D, $0A, "P4 Servo ver 1.05  BDT 21/03/2006",$0D, $0A
    data @40, 0, 0 'error counter
    '****************************************************************
    '*  Name    : P4_Servo_V105.BAS                                 *
    '*  Author  : Brian Taylor                                      *
    '*  Notice  : Copyright (c) 2006 Brian Taylor                   *
    '*          : All Rights Reserved                               *
    '*  Date    : 21/03/2006                                        *
    '*  Version : 1.05                                              *
    '*  Notes   :                                                   *
    '*          :                                                   *
    '****************************************************************
    '  This is P4 - 16F88 - the servo driver
    '  test code to debug the hardware
    '
    'Background.
    '  A 'standard' JR, Futaba, HS, etc RC system uses on a nominal 50 Hz
    '  refresh rate to the servos.  This gives a nominal 20 mSec frame time.
    '  Servos centre at 1.5 mSec and range from 1 to 2 mSec at the end stops. 
    '  Bitter experience shows digital servos burn out outside 1-2 mS values. 
    '  8 channels all at maximum, highly unlikely, takes 8 x 2 mSec leaving 
    '  4 mSec for sync, etc. 8 channels all at minimum width, also highly 
    '  unlikely, takes 8 mS leaving 12 mSec for sync, processing, etc.
    '  An 'average' frame has 8 channels at 1.5 mSec leaving 8 mSec for playtime.
    '  This code gets a 'fast packet' from the leveller PIC in about 2.1 mSec
    '  and drives all 8 servos regardless of whether they exist in hardware.
    '
    DEFINE LOADER_USED 1
    DEFINE OSC 20
    define no_clrwdt 1
    define loader_used 1     
    ' Set Debugin pin port
    DEFINE DEBUGIN_REG PORTB 
    DEFINE DEBUG_BAUD 115200   '76800 
    ' Set Debugin pin bit
    DEFINE DEBUGIN_BIT 7 
    ' Set Debugin mode: 0 = true, 1 = inverted
    DEFINE DEBUGIN_MODE 1
    
    '@ Device pic16F88, HS_OSC, BOD_OFF, PWRT_ON, WDT_ON, PROTECT_OFF
    
    '************************** Hardware assignment *************************
    'Port A     all digital
    Svo8        var   porta.0     'p 17 digital drive to servo 8 digital      out
    Svo7        var   porta.1     'p 18                  servo 7 digital      out
    Svo6        var   porta.2     'p 1  digital drive to servo 6 digital      out
    Svo5        var   porta.3     'p 2  digital drive to servo 5 digital      out
    Svo4        var   porta.4     'p 3  digital drive to servo 4 digital      out
    
    TRISA = %11100000
    ANSEL = %00000000
    CMCON = %00000111
    
    'Port B
    Svo3        var   portb.0     'pin 6  servo 3 drive                       out
    Svo2        var   portb.1     'pin 7  servo 2                             out
    RxD         var   portb.2     'pin 8  BootLoader input                    in
    Svo1        var   portb.3     'pin 9  Servo 1 drive                       out
    P4LED       var   portb.4     'pin 10 Diagnostic LED                      out
    TxD         var   portb.5     'pin 11 BootLoader output - diagnostic out  out
    P3_P4       var   portb.6     'p 12 Data in from P3                       in
    P2_P4       var   portb.7     'p 13 Servo packet data from P2             in
    TRISB = %11000100
    
    '****************************** Software assignment **************************
    A           var   byte
    B           var   byte
    C           var   byte
    W           var   word
    InCtr       var   byte
    Ch          var   byte[8]  ' the current channel data
    LastCh      var   byte[8]  ' last clean channel data
    FailCh      var   byte[8]  ' failsafe values invoked after N bad packets
    Delta       var   byte     ' maximum allowable servo step
    CheckSum    var   byte
    ErrorCtr    var   word  ' counts checksum errors in servo data from P2
    
    StepLimit   con   8    ' max allowed servo change per frame
                           ' damps out violent spikes
                           
    '--------------------------------- Initialise ------------------------
    Initialise:
    
    ShowRevision:
       serout txd, 2, [$0D, $0A] 
       for a = 0 to 79
          read a,b
          serout txd, 2, [b]
          clearwdt
       next a
       serout txd, 2, [$0D, $0A] 
    
    '   WDTCON = %00001001 ' invoke s/w WDT, 58 mSec timeout, 110 mSec recovery
       WDTCON = %00001010      ' longer WDT activate period 
       OPTION_REG = %10001010  ' No wpu, prescaler assigned to WDT & /4
                               ' OPTION_REG xxxx00 gives 15 mS, 10 gives 64 mS 
       INTCON = %00000000      ' disable all interrupts
       ANSEL =  %00000000      ' all digital
       CMCON  = %00000111      ' Comparators OFF to allow inputs on pins
       ADCON0 = %00000000
       ADCON1 = %00000000
    
    SetInitialServoPosition:
       Ch[0] = 0
       Ch[1] = 125
       Ch[2] = 125
       Ch[3] = 125
       Ch[4] = 125
       Ch[5] = 125
       Ch[6] = 125
       Ch[7] = 125
      
    high p4led        ' fires if WDT is invoked during preflight ground check.
    
    Start:
    
    GetServoData:
       debugin 90, failsafe, [a, ch[0], ch[1], ch[2], ch[3], ch[4], ch[5], _
          ch[6], ch[7], checksum]
       'A = throw away sync byte - often corrupted
       c = 0 ' checksum comparison
       for b = 0 to 7    ' build local checksum
          c = c + ch[b]
       next b
       if checksum = c then 
          goto goodpacket
       endif
       
    
    Failsafe:   ' Use last clean packet if internal processor to processor
                ' error occurs
       high p4led
       for a = 0 to 7
          ch[a] = lastch[a]
       next a
       
    GoodPacket:
    
    DriveServos:
       ' PULSOUT gives 2 uS steps at 20 MHz.  
       ' The servos need 1000 to 2000 uS at 50 Hz
       ' MUST MUST MUST define initial states as Pulsout is a toggle.
       svo1 = 0
       svo2 = 0
       svo3 = 0
       svo4 = 0
       svo5 = 0
       svo6 = 0
       svo7 = 0
       svo8 = 0
       
       clearwdt
       
       w = 500 + 2*ch[0]         ' W is in 2 uS steps = 1000 to 2000 uS
          pulsout svo1, w
       w = 500 + 2*ch[1]   
          pulsout svo2, w
       w = 500 + 2*ch[2]   
          pulsout svo3, w
       w = 500 + 2*ch[3]   
          pulsout svo4, w
       w = 500 + 2*ch[4]   
          pulsout svo5, w
       w = 500 + 2*ch[5]   
          pulsout svo6, w
       w = 500 + 2*ch[6]   
          pulsout svo7, w
       w = 500 + 2*ch[7]   
          pulsout svo8, w
    
    SaveLastValues:
       for a = 0 to 7
          lastch[a] = ch[a]
       next a
    
       low p4led
       clearwdt
    goto start  'getservodata
    HTH
    BrianT
    Last edited by BrianT; - 15th September 2008 at 12:14. Reason: clarity & layout

  6. #6


    Did you find this post helpful? Yes | No

    Default

    Darrel, thanks for the explanation. it makes sense.

    Brian, I approached the RX code a bit differently. For example I use a manchester decoder that tests 01 or 10 transition if there is a 11 or 00 bit it throws out the packet. So I don't have a checksum. I also have framing error and over run detection enabled for the UART. I am streaming out data at 4800bps.

    A modification since I am using a 900Mhz FSK radio, it does not need to have a balanced data stream so I can forgo the manchester. Instead I will send a word, high byte is true data and low byte is inverted data. The decoder then looks for identical payload once inverted between high and low byte, if not throw it out. All I am really controlling is 4 servos and 2 hardware PWM outputs which takes very little overhead since it is hardware unlike servos each 1 ~ 2ms.

    I noticed you used pulseout instead of portb.0=1 pauseus (4*pos+500) portb.0=0. Does the pulseout save in code execution time?

  7. #7


    Did you find this post helpful? Yes | No

    Default No optimisation done since it worked.

    Hi Magman,
    I did not optimise the code since I had plenty of time in the way I did it. It may turn out that your pauseus approach may save space and time. If I needed code space or clock cycles I would have checked that method out.

    I reckon a single checksum across all channels uses less time and code than the 100% redundancy approach you are taking with the true/inverted signalling but I agree yours is a safe and simple approach. If I get a bad packet or a bad channel within a packet (out of range or delta too big) I use the last good value for that channel. Given that real data does not jump much from frame to frame this method seems to fly quite well.

    My uplinks are 36 and 2400 MHz using the transmitter in PPM.

    What are you building. Is it an aircraft?

    Cheers
    BrianT
    Last edited by BrianT; - 15th September 2008 at 12:05. Reason: grammar

  8. #8


    Did you find this post helpful? Yes | No

    Default

    Looking over your code closely, I realized something. Do you pause in the TX output for 16 ~ 20ms before starting up your next frame?

    I am not doing that, it may be why I am seeing the results I am seeing. using a continuous back to back output from the TX @ 4800bps I am able to get 4 servo + 2 hardware PWM control. BTW I figured out why my servo is a bit coarse. in your code you multiply with a 2 constant. I am not moving in 2us increments. I am doing the following: 2* (4*byte + 500), So for every crank on the potentiometer I am moving in chunks of 8us, so I am not loosing packets, its my scaling factor....ggeeeezzz.


    yes, it is an aircraft. Actually VTOL.
    Last edited by Macgman2000; - 15th September 2008 at 14:56.

Similar Threads

  1. Read/Write Problem
    By Tobias in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 10th February 2010, 02:51
  2. Minimizing code space
    By Tobias in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 30th May 2009, 08:25
  3. SEROUT WORD variable problem
    By Tobias in forum mel PIC BASIC Pro
    Replies: 3
    Last Post: - 19th April 2009, 12:20
  4. DS2760 Thermocouple Kit from Parallax in PicBasicPro
    By seanharmon in forum mel PIC BASIC Pro
    Replies: 3
    Last Post: - 9th July 2008, 00:19
  5. calculation problem
    By nicolelawsc in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 31st March 2006, 16:23

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts