Announcement

Collapse
No announcement yet.

How would I call a Picbasic Pro subroutine using ASM

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

  • 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.

  • #2
    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

    Comment


    • #3
      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
      '*******************************************************************************

      Comment


      • #4
        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.

        Comment


        • #5
          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

          Comment


          • #6
            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.

            Comment

            Working...
            X