Announcement

Collapse
No announcement yet.

How do you know . . . ?

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

  • How do you know . . . ?

    Hello !
    I am trying to convert some asm programs into include files for use in PBP, and as I am ASM_Illiterate still I try.

    Question 1. How do you know, without simply compiling and error correction, when to EndAsm and ASM again so as not to overrun . . . pages?

    Here is one from Roman Black
    Code:
    '*  Name    : ZERO-ERROR ONE SECOND TIMER.BAS                   *
    '*  Author  : from Roman Black                                  *
    '*  Notice  : Copyright (c) 2012 [                  ]           *
    '*          : All Rights Reserved                               *
    '*  Date    : 4/18/2012                                         *
    '*  Version : 1.0                                               *
    '*  Notes   :                                                   *
    '*          :                                                   *
    
    ; ZERO-ERROR ONE SECOND TIMER
    ; (Roman Black 2001, public domain, use it as you like)
    ; 
    ; INTERRUPT VERSION
    ;
    ; for PIC 16F84 at 4 MHz (or most PICs)
    ; (this code has been assembled with MPLAB and hardware tested)
    ; (for best viewing set TABS=5 in MPLAB editor)
    ;
    ; Note! See text: www.RomanBlack.com/one_sec.htm
    ;
    ; Generates an event every second (or other period) from any PIC
    ; with any clock frequency.
    ;
    ; This version uses the timer0 overflow interrupt.
    ; Code can be adapted for different clock speeds, period lengths
    ; and accuracy levels.
    
    asm
    
    ; processor defined ;
       ifdef __16F84A	
        include <p16f84.inc>
          ifdef __16F648
          include <p16f648.inc>
           ifdef __16f690
             include <p16f690.inc>
           endif
        endif
       endif
    
    
    ; MPLAB stuff here
    
    	LIST b=5, n=97, t=ON, st=OFF
    	; absolute listing tabs=5, lines=97, trim long lines=ON, symbol table=OFF
    
    	;__CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
    	; config for 16F84; code protect OFF, watchdog OFF, powerup timer ON,
    	; oscillator is XT ready for 4 MHz crystal or resonator.
    
    ;
    ; Variables here
    
    	CBLOCK 0x20			; start of ram in 16F84
    
    		bres_hi			; hi byte of our 24bit variable
    		bres_mid			; mid byte
    		bres_lo			; lo byte
    						; (we only need 3 bytes for this system)
    
    		status_temp		; used for interrupt servicing
    		w_temp			; used for interrupt servicing
    
    	ENDC
    
    
    
    ; Code here
    
    	org 0x000 			; Set program memory base at reset vector 0x000
    reset
    	goto setup			; set up ints and port stuff
    
    	org 0x004				; Interrupt vector, int handler code comes next.
    
    
    
    ;  INTERRUPT HANDLER     (runs this code each timer0 interrupt)
    
    ;
    ;------------------
    int_handler				;
    ;------------------
    
    	
    						; first we preserve w and status register
    
    	movwf w_temp      		; save off current W register contents
    	movf	STATUS,w          	; move status register into W register
    	movwf status_temp       	; save off contents of STATUS register
    
    	;-------------------------------------------------
    	; Note! we get here every 256 instructions, we
    	; can now do our special one second timing system.				
    
    	; This consists of three main steps;
    	; * subtract 256 counts from our 24bit variable
    	; * test if we reached the setpoint
    	; * if so, add 1,000,000 counts to 24bit variable and generate event.
    	
    						; * optimised 24 bit subtract here 
    						; This is done with the minimum instructions.
    						; We subtract 256 from the 24bit variable
    						; by just decrementing the mid byte.
    
    	tstf bres_mid			; first test for mid==0
    	skpnz				; nz = no underflow needed
    	decf bres_hi,f			; z, so is underflow, so dec the msb
    
    	decfsz bres_mid,f		; dec the mid byte (subtract 256)
    
    						; now the full 24bit optimised subtract is done!
    						; this is about 4 times faster than a "proper"
    						; 24bit subtract.
    
    	goto int_exit			; nz, so definitely not one second yet.
    						; in most cases the entire int takes
    						; only 16 instructions.
    	
    						; * test if we have reached one second.
    						; only gets here when mid==0, it MAY be one second.
    						; only gets to here 1 in every 256 times.
    						; (this is our best optimised test)
    						; it gets here when bres_mid ==0.
    
    	tstf bres_hi			; test hi for zero too
    	skpz					; z = both hi and mid are zero, is one second!
    	goto int_exit			; nz, so not one second yet.
    
    	
    	; Only gets to here if we have reached one second.
    
    	; now we can generate our one second event, like add
    	; one second to our clock or whatever.
    	; (in this example we toggle a led)
    
    	; The other thing we need to do is add 1,000,000 counts
    	; to our 24bit variable and start all over again.
    	
    						; Add the 1,000,000 counts first.
    						; One second = 1,000,000 = 0F 42 40 (in hex)
    
    						; As we know hi==0 and mid==0 this makes it very fast.
    						; This is an optimised 24bit add, because we can
    						; just load the top two bytes and only need to do
    						; a real add on the bottom byte. This is much quicker
    						; than a "proper" 24bit add.
    
    	movlw 0x0F			; get msb value 
    	movwf bres_hi			; load in msb
    
    	movlw 0x42			; get mid value
    	movwf bres_mid			; load in mid
    
    	movlw 0x40			; lsb value to add
    	addwf bres_lo,f		; add it to the remainder already in lsb
    	skpnc				; nc = no overflow, so mid is still ok
    
    	incf bres_mid,f		; c, so lsb overflowed, so inc mid
    						; this is optimised and relies on mid being known
    						; and that mid won't overflow from one inc.
    
    						; that's it! Our optimised 24bit add is done,
    						; this is roughly twice as quick as a "proper"
    						; 24bit add.
    	;-------------------------
    						; now we do the "event" that we do every one second.
    
    						; Note! for this example we toggle a led, which
    						; will give a flashing led which is on for a second
    						; and off for a second.
    						; Add your own code here for your one second event.
    
    						; Note! My led is on porta,3
    						; your led may be on a different pin.
    	movlw b'00001000'		; mask for bit 3
    	xorwf PORTA,f			; toggle PORTA,bit3 (toggle the led)
    						
    	;-------------------------------------------------
    	; now our one second event is all done, we can exit the
    	; interrupt handler.
    	;-------------------------------------------------
    						; finally we restore w and status registers.
    						; also clears TMRO int flag now we are finished.
    int_exit
    	BCF INTCON,T0IF		; reset the tmr0 interrupt flag
    
    	movf status_temp,w     	; retrieve copy of STATUS register
    	movwf STATUS            	; restore pre-isr STATUS register contents
    	swapf w_temp,f
    	swapf w_temp,w          	; restore pre-isr W register contents
    	retfie				; return from interrupt
    ;------------------------------------------------------------------------------
    
    ;endasm
    ;asm
    
    ;  SETUP     (runs this only once at startup)
    
    ;
    ;------------------
    setup					; goto label
    ;------------------
    
    	;-------------------------------------------------
    	; Note! 16F84 version.
    	; Note! here we set up peripherals and port directions.
    	; this will need to be changed for different PICs.
    	;-------------------------------------------------
    
    						; OPTION setup
    	movlw b'10001000'		;
    		;  x-------		; 7, 0=enable, 1=disable, portb pullups
    		;  -x------		; 6, 1=/, int edge select bit
    		;  --x-----		; 5, timer0 source, 0=internal clock, 1=ext pin.
    		;  ---x----		; 4, timer0 ext edge, 1=\
    		;  ----x---		; 3, prescaler assign, 1=wdt, 0=timer0
    		;  -----x--		; 2,1,0, timer0 prescaler rate select
    		;  ------x-		;   000=2, 001=4, 010=8, 011=16, etc.
    		;  -------x		; 
    						; Note! We set the prescaler to the wdt, so timer0
    						; has NO prescaler and will overflow every 256 
    						; instructions and make an interrupt.
    						;
    	banksel OPTION_REG		; go proper reg bank
    	movwf OPTION_REG		; load data into OPTION_REG
    	banksel 0				; back to normal bank 0
    	;-------------------------------------------------
    						; PORTB pins direction setup
    						; 1=input, 0=output
    	clrf PORTB			;
    						;
    	movlw b'00000000'		; all 8 portb are outputs
    						;
    	banksel TRISB			; go proper reg bank
    	movwf TRISB			; send mask to portb
    	banksel 0				; back to normal reg bank
    	;-------------------------------------------------
    						; PORTA pins direction setup
    						; 1=input, 0=output
    	clrf PORTA			;
    						;
    	movlw b'00000000'		; all 5 porta are outputs,
    						; (with 16F84 porta only has lower 5 bits)
    						;
    	banksel TRISB			; go proper reg bank
    	movwf TRISA			; send mask to porta
    	banksel 0				; back to normal reg bank
    	;-------------------------------------------------
    						; INTCON setup
    						;
    						; for this code example, we enable the timer0
    						; overflow interrupt.
    						;
    						; enable interrupts last
    						; interrupt setup
    	movlw b'10100000'		; GIE=on TOIE=on (timer0 overflow int)
    	movwf INTCON			; set up.
    
    	;-------------------------------------------------
    	; Note! Now the hardware is set up we need to load the
    	; first count for one second into our 24bit bres variable.
    	;-------------------------------------------------
    						; Note! This example uses 4 MHz clock, which is
    						; 1,000,000 counts per second.
    						;
    						; We require a 1 second period, so we must load
    						; 1,000,000 counts each time.
    						; 1,000,000 = 0F 42 40 (in hex)
    						;
    						; We also need to add 256 counts for the first time,
    						; so we just add 1 to the mid byte.
    						; Check mid overflow if needed.
    
    						; here we load the 24bit variable.
    	movlw 0x0F			; get msb value 
    	movwf bres_hi			; put in hi
    
    	movlw 0x42 +1			; get mid value (note we added 1 to it)
    	movwf bres_mid			; put in mid
    
    	movlw 0x40			; get lsb value
    	movwf bres_lo			; put in mid
    
    						; now setup is complete, we can start execution.
    	;-------------------------------------------------
    	goto main				; start main program
    
    ;------------------------------------------------------------------------------
    endasm
    and here is my test code
    oops too long next post

  • #2
    Code:
    '****************************************************************
    '*  Name    : RomanTimerTest.bas                                *
    '*  Author  :                                                           *
    '*  Notice  : Copyright (c) 2012 [                  ]           *
    '*          : All Rights Reserved                               *
    '*  Date    : 4/18/2012                                         *
    '*  Version : 1.0                                               *
    '*  Notes   :                                                   *
    '*          :                                                   *
    '****************************************************************
    include "zero-error one second timer.bas"
    
    ;******************************************************************************
    ;  MAIN     (main program loop)
    ;******************************************************************************
    ;
    ;------------------
    main:						; goto label
    ;------------------
    
    	;-------------------------------------------------
    	; Note! This example uses the timer0 overflow interrupt.
    	; This will interrupt our main program every 256 instructions
    	; and do the one second timer system.
    	;-------------------------------------------------
    main_loop					; 
    						; Note! here you have your main program code,
    						; or calls to the main program pieces.
    						; The interrupt does all the one second timer stuff.
    	; stuff
    	; stuff
    	; stuff
    	; stuff
    
    	;-------------------------------------------------
    	goto main_loop			; keep running the main code.
    
    ;------------------------------------------------------------------------------
    
    
    ;==============================================================================
    	end				; no code after this point.
    ;==============================================================================
    and his original is available www.RomanBlack.com/one_sec.htm
    http://www.romanblack.com/one_sec.asm

    I added the asm / endasm and killed about 20 errors. Is there some other way to know where the banks are besides compiling and . . . .
    Last edited by Joe S.; 04-21-2012, 11:13 PM.

    Comment


    • #3
      Well, first I think you have to understand what "Zero Error" means to Roman.

      Over time, if you are using it in a clock, it will keep accurate time.
      But because of the way it uses the 24-bit counter to keep track of the timer ticks, each second is not exactly one second.

      It's been several years since I looked at it, so I don't remember how far off each second is, but it wasn't good enough for my purposes at that time.
      It may work for your application, but that's up to you, as long as you are aware of the issues.

      Now for converting it to PBP.
      Make sure you have the latest version of PBP3 (3.0.5.x currently).
      The ASM buffer sizes were increased in 3.0.3.x, so you have to ENDASM/ASM less often.

      But there are bigger problems when converting that code.
      • There are variables being declared at the ASM level. You'll have to declare those variables in PBP instead.
      • The Interrupt Vector and intial GOTO are being set manully with org's, you'll need to chage that to DEFINE INTHAND and remove the org's.
      • The code is written for a chip with 2K or less program memory. If you use a bigger chip, it will not be saving/restoring context properly.
      • It's trying to load the Microchip .inc files, which are already being included by PBP. That will cause many duplicate symbol errors.

      I recall a program by fratello that uses Romans routine with DT_INTS.
      It'll probably be easier to start there.
      http://www.picbasic.co.uk/forum/showthread.php?t=14232

      Read the whole thread because he was having problems too, I think he eventually solved them.
      PBP3 Manual : Microchip Datasheets - 10F, 12F, 16F, 18F
      Never download a PIC datasheet from anywhere but microchip.com

      Comment


      • #4
        Hi Darrel,
        As for this code, I wasn't so much trying to use it as learn how to convert it so it's accuracy really doesn't matter much to me, Thanks for the info re: the other things you mentioned, I will slash and burn some more based on your statements , right now I am still using ver 2.6 even though I bought ver 3.?? because I see a new shop computer in the future and don't want to waste an install permission on the old one, and the MRS. just might kick me off of hers. I do want to include Roman's LiniStepper software into an integrated controller for a 3d printer, so this subject is of importance to me.
        Thanks again !

        Comment

        Working...
        X