Announcement

Collapse
No announcement yet.

How would I call a Picbasic Pro subroutine using ASM

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • khufumen
    replied
    Perfect!

    Thank you. This is what I was looking for. "The get_pitch_roll_yaw" subroutine takes less than 1 ms to run so there should be no problem. I've been impressed with the 64MHz speed of the 18F87K22. The interrupt has no effect on any of the other code such as SEROUT2, HSEROUT running at 115200 baud or other i2c calls.

    Leave a comment:


  • richard
    replied
    i2cread p_i2c_sda, p_i2c_scl, addr_gyro_read, $1D, [gyro_x_reading.highbyte, gyro_x_reading.lowbyte, gyro_y_reading.highbyte, gyro_y_reading.lowbyte, gyro_z_reading.highbyte, gyro_z_reading.lowbyte]
    should have interrupts disabled for this command to be reliable

    Leave a comment:


  • richard
    replied
    a few thoughts\

    get_intrpt_time:
    ' The TICK variable is incremented every 10 ms. Since the TICK variable is a
    ' byte this means that we have 2560 ms before the TICK variable overflows.
    ' This means that I have to run this subroutine within a 2.56 second window.
    PIE1 = 0 ' Mask the interrupt while we're messing with TICK
    intrpt_seconds = intrpt_seconds + (tick/100)
    tick = tick // 100 ' Retain the left-over ticks
    PIE1 = $01 ' Interrupt on again
    Return ' Return to the main program
    could be better done with a flag

    movlw 0B1h ; Prepare to set TMR1 high register
    movwf TMR1H ; Set TMR1H to $B1
    movlw 0ECh ; Prepare to set TMR1 low register
    movwf TMR1L ; Set TMR1L to $EC
    incf _TICK,F ; INCREMENT TICK COUNT
    bcf PIR1, 0 ; Clear interrupt flag
    if tick was set to 100 and decremented every int then the flag.1 bit could be set every time TICK hits 0




    main:
    gosub get_intrpt_time

    gosub get_pitch_roll_yaw

    goto main




    Code:
    main:
       if flag ==1 then  
        gosub get_pitch_roll_yaw   
        flag.0 = 0
      endif 
      if flag ==2 then  
        gosub get_intrpt_time  
       flag.1 = 0
      endif  
        
    goto main

    would run code enery 10ms { if possible} if flag was set in isr

    add new var
    flag var byte bank0

    add this to isr
    bsf _flag,1
    not sure what chip ,used so added bank switching just in case , it won't hurt to leave it in even if its not required
    Code:
    Asm
    myint 
       ; Save the state of critical registers
       movwf   wsave      ; Save W
       swapf   STATUS, W  ; Swap STATUS to W (swap avoids changing STATUS)
       clrf    STATUS     ; Clear STATUS
       movwf   ssave      ; Save swapped STATUS
    
       ; a 64MHz oscillator with an 8 prescaler and 4 clocks per instruction
       ; produces 2,000,000 counts per second. Timer1 can hold a maximum of 65536
       ; counts. Thus Timer1 overflows 30.5 times in a second. This means that Timer1
       ; will overflow in 32.8 milliseconds if it starts from 0. We want Timer1 to
       ; overflow every 10 milliseconds. To do this Timer1 needs to be set at 65536 - 19988
       ; which comes to 45,548 whenever there is a reset. This translates to Timer1 
       ; highbyte being set to $B1 and Timer1 lowbyte being set to $EC
    
       movlw   0B1h       ; Prepare to set TMR1 high register
       CHK?RP TMR1
       movwf   TMR1H      ; Set TMR1H to $B1
       movlw   0ECh       ; Prepare to set TMR1 low register
       movwf   TMR1L      ; Set TMR1L to $EC 
       bcf     PIR1, 0    ; Clear interrupt flag
       RST?RP
       incf    _TICK,F    ; INCREMENT TICK COUNT
       bsf _flag,1 
       
       
       
          
       ; CODE NEEDS TO GO HERE TO RUN SUBROUTINE "get_pitch_roll_yaw"
       
       
       ; Retrieve critical registers     
       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 interrupt
    EndAsm

    without knowing how long all this takes to execute the task may be impossible anyway
    Code:
    get_pitch_roll_yaw:
    
        ' read the gyroscope. There should always be data available in the gyro' registers
        ' but we enter a loop just in case
        gyro_ready = false
        Do while gyro_ready = false
            gosub read_gyro_register_ready
        loop
    
        ' get readings
        i2cread p_i2c_sda, p_i2c_scl, addr_gyro_read, $1D, [gyro_x_reading.highbyte, gyro_x_reading.lowbyte, gyro_y_reading.highbyte, gyro_y_reading.lowbyte, gyro_z_reading.highbyte, gyro_z_reading.lowbyte]
        
        'set bits for indicating negative direction values. Gyro data is in twos compliment
        gosub calculate_directions
        
        ' subtract out offsets
        gosub subtract_offsets
    
        ' convert xyz values to angles and add to overall angles
        gosub update_x_angle
        gosub update_y_angle
        gosub update_z_angle
    
    return
    Last edited by richard; 10-21-2016, 06:17 AM.

    Leave a comment:


  • khufumen
    replied
    My code for reading gyro sensor

    Below is a portion of the code for reading the gyro.
    In the interrupt handler you can see where I want the subroutine called "get_pitch_roll_yaw" to run every 10 ms.
    It currently runs in my main loop.

    Any help in getting the ASM to run the "get_pitch_roll_yaw" subroutine would be greatly appreciated.


    Code:
    ' Test Program for InvenSense ITG-3200 Gyro
    
    ' define oscillator to be 64Mhz
    DEFINE OSC 64 
    OSCCON = %11110000
    OSCTUNE.6 = 1
    
    ' make sure all pins are digital
    CVRCON = 0
    ADCON0 = 0 
    ANCON0 = 0
    ANCON1 = 0
    ANCON2 = 0
    PADCFG1 = 0
    MEMCON.7 = 1 
    
    
    Define  INTHAND myint ' define interrupt handler
    
    ' define ports
    p_i2c_scl                   var  PORTJ.6 '[pin 41]
    p_i2c_sda                   var  PORTJ.7 '[pin 42]
    p_tx_to_pc                  var  PORTH.5 '[pin 21]
    
    ' define constants
    false                       con  0
    true                        con  1 
    Baud384NoIvn                CON  6           ' 38.4K baud rate without inversion (used for communication between pics)
    addr_gyro_write             con  %11010010   ' write to gyro
    addr_gyro_read              con  %11010011   ' read from gyro
    gyro_sensitivity            con  14375       ' actually 14.375 mV/degree/second
    
    
    ' define variables
    wsave                       VAR BYTE bankA system   ' Saves WREG
    ssave                       VAR BYTE bankA system   ' Saves STATUS
    TICK                        VAR  BYTE bankA         ' make sure that the variables are in bank 0 if they are to be used in the interrupt handler
    intrpt_seconds              VAR long                ' Elapsed seconds  
    intrpt_seconds_hold         VAR long                ' Elapsed seconds for comparison
    
    gyro_x_reading              var word
    gyro_y_reading              var word
    gyro_z_reading              var word
    
    x_gyro_neg                  var bit
    y_gyro_neg                  var bit
    z_gyro_neg                  var bit
    
    x_gyro_offset               var byte
    y_gyro_offset               var byte
    z_gyro_offset               var byte
    
    x_gyro_offset_neg           var bit
    y_gyro_offset_neg           var bit
    z_gyro_offset_neg           var bit
    
    x_gyro_sum                  var long
    y_gyro_sum                  var long
    z_gyro_sum                  var long
    
    x_gyro_sum_neg              var bit
    y_gyro_sum_neg              var bit
    z_gyro_sum_neg              var bit
    
    x_angle                     var long ' all angles are in milliDegrees
    y_angle                     var long ' all angles are in milliDegrees
    z_angle                     var long ' all angles are in milliDegrees
    
    x_angle_neg                 var bit
    y_angle_neg                 var bit
    z_angle_neg                 var bit
    
    
    gyro_sample_rate            var byte
    gyro_number_of_samples      var byte
    gyro_low_pass_filter        var byte
    
    gyro_ready                  var bit
    got_gyro_data               var bit
    
    gyro_register_byte          var byte
    
    tempByte                    var byte
    tempWord                    var word
    tempLong                    var long
    sample_time                 var long  '(micro seconds) The time it takes between samples
    counter                     var byte
    timer0                      VAR WORD
    i                           var byte
    
           
    intrpt_seconds = 0  ' Clear time
    intrpt_seconds_hold = 0
    T1CON =  %00110000  ' Turn off Timer1, prescaler = 8, time based on instruction cycle
    INTCON = %11000000  ' Enable global interrupts, peripheral interrupts
    PIE1 = $00          ' Disable TMR1 overflow interrupt until we enter main loop
    TICK = 0
    
    GoTo jumpInterrupt ' jump over the interrupt handler and sub
    
    ' Assembly language interrupt handler
    Asm
    myint 
       ; Save the state of critical registers
       movwf   wsave      ; Save W
       swapf   STATUS, W  ; Swap STATUS to W (swap avoids changing STATUS)
       clrf    STATUS     ; Clear STATUS
       movwf   ssave      ; Save swapped STATUS
    
       ; a 64MHz oscillator with an 8 prescaler and 4 clocks per instruction
       ; produces 2,000,000 counts per second. Timer1 can hold a maximum of 65536
       ; counts. Thus Timer1 overflows 30.5 times in a second. This means that Timer1
       ; will overflow in 32.8 milliseconds if it starts from 0. We want Timer1 to
       ; overflow every 10 milliseconds. To do this Timer1 needs to be set at 65536 - 19988
       ; which comes to 45,548 whenever there is a reset. This translates to Timer1 
       ; highbyte being set to $B1 and Timer1 lowbyte being set to $EC
    
       movlw   0B1h       ; Prepare to set TMR1 high register
       movwf   TMR1H      ; Set TMR1H to $B1
       movlw   0ECh       ; Prepare to set TMR1 low register
       movwf   TMR1L      ; Set TMR1L to $EC 
       incf    _TICK,F    ; INCREMENT TICK COUNT
       bcf     PIR1, 0    ; Clear interrupt flag
       
       ; CODE NEEDS TO GO HERE TO RUN SUBROUTINE "get_pitch_roll_yaw"
       
       
       ; Retrieve critical registers     
       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 interrupt
    EndAsm
    
    ' PicBasic subroutine to update seconds variable
    get_intrpt_time:
       ' The TICK variable is incremented every 10 ms. Since the TICK variable is a
       ' byte this means that we have 2560 ms before the TICK variable overflows. 
       ' This means that I have to run this subroutine within a 2.56 second window.
       PIE1 = 0 ' Mask the interrupt while we're messing with TICK                               
       intrpt_seconds = intrpt_seconds + (tick/100) 
       tick = tick // 100 ' Retain the left-over ticks
       PIE1 = $01  ' Interrupt on again
    Return   ' Return to the main program      
    
    jumpInterrupt:
     
    
    x_angle = 0
    y_angle = 0
    z_angle = 0
    x_angle_neg = 0
    y_angle_neg = 0
    z_angle_neg = 0
    
    
    
    T1CON =  %00110001  ' Start Timer1
    PIE1 = $01  ' Start interrupts
    
    ' enter main loop of program
    main:
        gosub get_intrpt_time
          
        gosub get_pitch_roll_yaw
        
    goto main
    '*******************************************************************************
    ' This routine reads the gyroscope, subtracts out the x,y,z offsets and adds the
    ' x,y,z angle values to their perspective summation values.
    get_pitch_roll_yaw:
    
        ' read the gyroscope. There should always be data available in the gyro' registers
        ' but we enter a loop just in case
        gyro_ready = false
        Do while gyro_ready = false
            gosub read_gyro_register_ready
        loop
    
        ' get readings
        i2cread p_i2c_sda, p_i2c_scl, addr_gyro_read, $1D, [gyro_x_reading.highbyte, gyro_x_reading.lowbyte, gyro_y_reading.highbyte, gyro_y_reading.lowbyte, gyro_z_reading.highbyte, gyro_z_reading.lowbyte]
        
        'set bits for indicating negative direction values. Gyro data is in twos compliment
        gosub calculate_directions
        
        ' subtract out offsets
        gosub subtract_offsets
    
        ' convert xyz values to angles and add to overall angles
        gosub update_x_angle
        gosub update_y_angle
        gosub update_z_angle
    
    return
    '*******************************************************************************

    Leave a comment:


  • richard
    replied
    Originally posted by khufumen View Post
    I would like to read an i2c sensor and process its data every 10ms. I am familiar with the timer interrupts and can see how data can be saved to variables using ASM . However, I am not familiar with any code that uses ASM to run a PICbasic pro subroutine. I don't even know if it's possible. I'm using an 18F87K22 PIC. Any help would be greatly appreciated. Thanks.
    its quite feasible , post some code that demonstrates what you are trying to do

    Leave a comment:


  • khufumen
    started a topic How would I call a Picbasic Pro subroutine using ASM

    How would I call a Picbasic Pro subroutine using ASM

    I would like to read an i2c sensor and process its data every 10ms. I am familiar with the timer interrupts and can see how data can be saved to variables using ASM . However, I am not familiar with any code that uses ASM to run a PICbasic pro subroutine. I don't even know if it's possible. I'm using an 18F87K22 PIC. Any help would be greatly appreciated. Thanks.
Working...
X