PDA

View Full Version : ASM code



Bill Legge
- 27th February 2010, 06:39
Help please.

The PIC is an 18F8772 on a Futulec board (so hopefully the wiring is correct).
I'm trying to use assembler to make the MCU produce two pulse streams for a set number of pulses:

1. I use TIMER0 and TIMER1 for the inter-pulse delays.
2. A simple 'count down' for the pulse duration.
3. A counter that holds the numer of pulses to be generated, this is decremented - and when the counter hits zero - the routine should end.

The code works OK - BUT! keeps 're-running.' i.e it puts out the required number of pulses, pauses for a bit and then does it all over again.

Debugging with an ICD2 shows all the SFRs changing properly and the code ending after the requisite number of pulses - but when running normally it just keeps looping.

The last few lines of ASM code is


Main_loop: ; Check if X_steps_lb is zero tstfsz X_steps_lb ; Test, skip next if equal
goto Main_loop ; More steps to do, so loop
bcf INTCON,7 ; Disable all high priority interrupts
bcf INTCON,6 ; Disable all low priority interrupts
bcf T0CON,7 ; Timer0 off
bcf T1CON,0 ; Timer1 off
end

I've not posted all the code because I don't think anyone would trawl through it.

The CONFIG settings are:


; Configuration bits
CONFIG OSC = HSPLL ; Run at 4X speed
CONFIG CP0=OFF ; Disable code protect
CONFIG PWRT = OFF ; Powerup off so DEBUG works
CONFIG WDT=OFF ; WDT off
CONFIG LVP = OFF ; LVP off
CONFIG WAIT = OFF ; External bus data wait disabled

The re-set on MLCR is OK. The IDE is MPLAB. Anyone got any ideas?

Regards Bill Legge

mackrackit
- 27th February 2010, 07:23
Main_loop: ; Check if X_steps_lb is zero tstfsz X_steps_lb ; Test, skip next if equal
goto Main_loop ; More steps to do, so loop
bcf INTCON,7 ; Disable all high priority interrupts
bcf INTCON,6 ; Disable all low priority interrupts
bcf T0CON,7 ; Timer0 off
bcf T1CON,0 ; Timer1 off
END_LOOP:
GOTO END_LOOP
end

Once it hits END_LOOP it will stay there forever, This is sorta what PBP's END does.. I think//

Bill Legge
- 27th February 2010, 08:21
Dave,

Thanks - I've just tried that and it works fine - the first time in 2 days that I have managed to get the code to output the correct number of pulses.

However, I presume that when I incorporate the .asm code inside PBP the loop will prevent the .asm from ever finishing?

ASM
; lots of my asm code goes here
End_loop:
goto End_loop
ENDASM

Any other ideas please? What on earth is making the PIC ignore all the 'end stuff' instructions?

Regards Bill Legge

mackrackit
- 27th February 2010, 08:38
ASM
; lots of my asm code goes here
ENDASM

END ' THE PBP TYPE

When you jump out of the ASM routine and go back to PBP the END command should do what you want.

Bill Legge
- 27th February 2010, 08:55
Dave,

Thanks for your support and interest.

Having got it to work using the 'end-loop' process you suggested, I had a further play-around with the interrupts - and made it work!

I added the code:


bcf RCON,7 ; Clear IPEN=0, disable priority interrupts

And now all is OK.

If anyone is interested in the code I'm happy to put it up here. The routine uses ASM to:

1. Drive 2 stepper motors at the same time.
2. Main purpose is to get diagonal moves on an XY plotter
3. The asm code is passed parameters by PBP:
a. X steps to be done
b. Y steps to be done
c. X inter-pulse delay
d. Y inter-pulse delay
4. Code has yet to be 'polished' and oly works with byte size parameters.
Next is changing to accept WORD size parameters.

Once again - thanks for your help.

Regards Bill Legge

Archangel
- 27th February 2010, 20:15
bcf RCON,7 ; Clear IPEN=0, disable priority interrupts

If anyone is interested in the code I'm happy to put it up here. The routine uses ASM to:

1. Drive 2 stepper motors at the same time.
2. Main purpose is to get diagonal moves on an XY plotter
3. The asm code is passed parameters by PBP:
a. X steps to be done
b. Y steps to be done
c. X inter-pulse delay
d. Y inter-pulse delay
4. Code has yet to be 'polished' and only works with byte size parameters.
Next is changing to accept WORD size parameters.

Hi Bill,
I would like to see it,
Thank You.
JS

Darrel Taylor
- 27th February 2010, 20:27
I added the code:


bcf RCON,7 ; Clear IPEN=0, disable priority interrupts

And now all is OK.
I have my doubts about that.

IPEN defaults to 0 on Power-Up/Reset.
So unless you have another RCON statement in your program that already changed it to 1, that statement will have no effect.
<br>

Bill Legge
- 28th February 2010, 00:14
Darryl & Joe

Thanks for your comment - yes I do have code that sets RCON,7 (IPEN)
to enable priority levels on interrupts.

I've made an XY plotter/scanner using stepper motors and cheap Chinese linear bearings (about $10 each!). Only got the 'movement/plot bit' done so far and will add the scan later (Paralax Line Scan module).

I went to assembler so that I could drive X and Y motors at the same time to get diagonal moves. This bit of the code works like:

1. In PBP set the X_steps (Nx) and Y_steps (Ny)
2. In PBP work out the periods of the pulses (Px znd Py) so that the time to make the X/Y moves are the same T(move) = Nx.Px = Ny.Py
3. Send the variables to the ASM code
4. Use Timer0 to interrupt (high priority) for Px
5. Use Timer1 to interrupt for Py
6. Decrament Nx whenever an X pulse is sent and halt at zero
7. Stop and return to PBP

It's the 'stopping' that took me two days to sort out and the guilty party was the IPEN bit - and an inexperienced asm programmer!

Happy to post the code - sorry - I've used TABS and it looks terrible at the moment:


;************************************************* *****************************
; *
; Filename: WL_Scanner_01 *
; Date: February 2010 *
; *
;************************************************* *****************************

;************************************************* *****************************
; *
; Function: Drive two stepper motors with timers/interrupts *
; Files Required: P18F8722.INC *
; *
;************************************************* *****************************

LIST P=18F8722 ; Directive to define processor
#include <P18F8722.INC> ; Drocessor specific variable definitions

;************************************************* *****************************
; Configuration bits
CONFIG OSC = HSPLL ; Run at 4X speed
CONFIG CP0=OFF ; Disable code protect
CONFIG PWRT = OFF ; Power up timer off so DEBUG works
CONFIG WDT=OFF ; WDT off
CONFIG LVP = OFF ; LVP off
CONFIG WAIT = OFF ; External bus data wait disabled
;************************************************* *****************************
; Variable definitions in data memory
WREG_TEMP equ 0x010 ; Variable used for context saving
STATUS_TEMP equ 0x011 ; Variable used for context saving
BSR_TEMP equ 0x012 ; Variable used for context saving
Count_pulse equ 0x013 ; Loop delay in 5 uS pulse to motor driver
X_delay_lb equ 0x014 ; Inter-pulse delay for X axis, high byte
X_delay_hb equ 0x015 ; Inter-pulse delay for X axis, low byte
Y_delay_lb equ 0x016 ; Inter-pulse delay for Y axis, high byte
Y_delay_hb equ 0x017 ; Inter-pulse delay for Y axis, low byte
X_steps_lb equ 0x018 ; Number of steps to do on X axis
X_steps_hb equ 0x019 ; Y steps not needed as Tx.Dx=Ty.Dy

;************************************************* *****************************
; Reset vector in program memory
ORG 0x0000
goto Main_ASM ; Go to start of main code
;************************************************* *****************************
; High priority interrupt vector in program memory
ORG 0x0008
goto High_int ; Go to high priority interrupt routine
;************************************************* *****************************
; Low priority interrupt vector and routine in program memory, when Timer1
; overflows send out stepper drive pulse for Y axis on PORTD.3
ORG 0x0018
movff STATUS,STATUS_TEMP ; save STATUS register
movff WREG,WREG_TEMP ; save working register
movff BSR,BSR_TEMP ; save BSR register

bcf INTCON,7 ; Disable all interrupts
bsf PORTD,3 ; High PORTD.3
call Pulse_out ; Delay for 10 microseconds
bcf PORTD,3 ; High PORTD.3
bcf PIR1,0 ; Clear Timer1 interrupt flag
movff Y_delay_hb,TMR1H ; Load Timer1 with Y_delay
movff Y_delay_lb,TMR1L ; Load timer1 with Y_delay

movff BSR_TEMP,BSR ; restore BSR register
movff WREG_TEMP,WREG ; restore working register
movff STATUS_TEMP,STATUS ; restore STATUS register

bsf INTCON,7 ; Enable interrupts
retfie

;************************************************* *****************************
; High priority interrupt routine, when Timer0 overflows, send out stepper
; drive pulse for X axis on PORTD.0
High_int:
bcf INTCON,7 ; Disable interrupte
bsf PORTD,0 ; High PORTD.0
call Pulse_out ; Send 5uS pulse on PORTB.0
bcf PORTD,0 ; Low PORTD.0
bcf INTCON,2 ; Clear Timer0 interrupt flag
movff X_delay_hb,TMR0H ; Load timer0 with X_delay
movff X_delay_lb,TMR0L ; Load timer0 with X_delay

decf X_steps_lb ; Decrement X_steps
bsf INTCON,7 ; Enable interrupts
retfie 1

;************************************************* *****************************
; *
; SUBROUTINES *
; *
;************************************************* *****************************

Pulse_out: ; Delay = 3.n + 7 [0.1 microseconds]
movlw 0xff ; Load w with n
movwf Count_pulse ; Load Count with n
Pulse_loop:
decfsz Count_pulse ; Decrament the file Count
goto Pulse_loop ; Loop if not zero
return

;************************************************* *****************************
; *
; MAIN ASM *
; *
;************************************************* *****************************

Main_ASM:
clrf TRISA ; PORTA is output
clrf TRISB ; PORTB is output
clrf TRISC ; PORTC is output
clrf TRISD ; PORTD is output
clrf TRISE ; PORTE is output
clrf TRISF ; PORTF is output
clrf TRISG ; PORTG is output
clrf TRISH ; PORTH is output
clrf TRISJ ; PORTJ is output

clrf PORTA ; Clear PORTA
clrf PORTB ; Clear PORTB
clrf PORTC ; Clear PORTC
clrf PORTD ; Clear PORTD
clrf PORTE ; Clear PORTE
clrf PORTF ; Clear PORTF
clrf PORTG ; Clear PORTG
clrf PORTH ; Clear PORTH
clrf PORTJ ; Clear PORTJ

movlw 0x0f
movwf ADCON1 ; PORTA is digital I/O
movlw 0x07
movwf CMCON ; Comparator off

; Set up interrupt conditions for Timer0 and Timer1
bsf RCON,7 ; Enable priority levels on interrupts,IPEN=1
bsf INTCON,7 ; Enable all high priority interrupts
bsf INTCON,6 ; Enable all low priority interrupts
bcf INTCON,3 ; Disable PORTB interrupts
bsf INTCON2,2 ; Make Timer0 overflow high priority
bcf IPR1,0 ; Make Timer1 overflow low priority
bsf INTCON,5 ; Enable Timer0 overflow flag
bsf PIE1,0 ; Enable Timer1 overflow flag

; Set up Timer0 conditions
bcf T0CON,6 ; Timer0 uses 16 bits
bcf T0CON,5 ; Timer0 uses internal osc
bcf T0CON,4 ; Timer0 count on rising edge og osc
bsf T0CON,3 ; Timer0 pre-scaler not assigned
clrf TMR0L ; Zero the clock
clrf TMR0H ; Zero the clock
bsf T0CON,7 ; Timer0 on

; Set up Timer1 conditions
bsf T1CON,7 ; Timer1 uses 16 bits
bcf T1CON,1 ; Timer1 uses internal osc
clrf TMR1L ; Zero the clock
clrf TMR1H ; Zero the clock
bsf T1CON,0 ; Timer1 on

; Temp code to simmulate PBP input for the delays
movlw 0x00
movwf X_delay_lb
movlw 0x00
movwf X_delay_hb
movlw 0x00
movwf Y_delay_lb
movlw 0x00
movwf Y_delay_hb
movlw 0xff
movwf X_steps_lb
movlw 0xff
movwf X_steps_hb
; End of Temp code

; Check if X_steps_lb=0 (decremented in high priority interrupt)
; If so, check X_steps_hb and if zero, end
; If not, decrement X_steps_hb, set X_steps_lb and go again
Main_loop:
movff X_steps_hb,PORTC
;comf PORTC,1 ; LEDS active low so invert
movff X_steps_lb,PORTD
;comf PORTD,1
tstfsz X_steps_lb ; Test, skip next if zero
goto Main_loop ; More steps to do, so loop
tstfsz X_steps_hb ; Test, skip next if zero
goto Re_load_lb
goto All_done

Re_load_lb:
decf X_steps_hb,1 ; Decrement hb and then carry to lb
setf X_steps_lb ; Decremented hb, so load ff to lb
goto Main_loop

All_done:
bcf RCON,7 ; Clear IPEN=0, disable priority interrupts
end ; IPEN must be cleared or asm keeps running

Regards Bill Legge

Bill Legge
- 28th February 2010, 03:33
And some more help please.

I'm now having difficulty in putting the asm code into a PBP program:

1. Running on a PIC18F8722.
2. Low and high priority interrupts are used BUT IN THE ASM CODE ONLY.
3. The action to be taken on interrupt is only in the ASM code.

So far I have:

1. Deleted the asm configs and done them in PBP
2. Listed the variables like:


WREG_TEMP var byte $20 System ; Variable used for context saving
STATUS_TEMP var byte Bank0 System ; Variable used for context saving
BSR_TEMP var byte Bank0 System ; Variable used for context saving
Count_pulse var byte Bank0 System ; Pulse duration = 3.n + 7
X_delay_lb var byte Bank0 System ; Subtracted from $ffff to get X delay
X_delay_hb var byte Bank0 System ; ..result loaded into Timer0_High and Timer0_Low
Y_delay_lb var byte Bank0 System ; Subtracted from $ffff to get Y delay
Y_delay_hb var byte Bank0 System ; ..result loaded into Timer1_High and Timer1_Low
X_steps_lb var byte Bank0 System ; Y steps not needed because different X/Y pulse
X_steps_hb var byte Bank0 System ; ..frequencies make Nx.Dx = Ny.Dy

I have deleted (Should I have kept them?) these bits of the original ASM code:


LIST P=18F8722 ; Directive to define processor
#include <P18F8722.INC> ; Drocessor specific variable definitions

Should I use the instructions (although my interrupts occur in ASM only):

DEFINE INTLHAND Label
DEFINE INTHAND Label

I have had a good read of the PBP handbook and DT's interrupt code and examples - but am still missing something?

Regards Bill legge

Charles Linquis
- 28th February 2010, 06:10
Bill,

I don't have time to give you a complete answer right now, but I believe you are making this too hard.

If you use DT-Ints, you don't need to worry about saving/restoring the registers, or any ORGs. All of that is taken care of for you.
All I can do right now is give you a snippet of some code that I have handy.

This code has only high priority INTs, but low-priority INTS are done the same way.



Go to Darrel's page and read about using his structure. It will really help you a lot.

You will notice that the code snippet below has both PBP and ASM ints.

MasterClock is defined as a BankA SYSTEM var so that PBP can access it.
All the vars (including the ASM vars) are declared in PBP.





'---------------------------------- End of basic assignment section ---------------------------------


INCLUDE "DT_INTS-18.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ; Include if using PBP interrupts

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR0_INT, SystemTimer, ASM, yes
INT_Handler RX1_INT, _GetCharPort1, PBP, yes
INT_Handler RX2_INT, _GetCharPort2, PBP, yes
INT_Handler INT2_INT, _GetXData, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

Goto OverInt

'---[INT - interrupt handlers]-----------------------------------------------

ASM
SystemTimer
movff 0x0B,TMR0H ; 10 msec with /16 prescaler
movff 0xDC,TMR0L

infsnz MasterClock
incf MasterClock + 1

INT_RETURN
ENDASM


If no one else posts a better response, I'll send you more information tomorrow.

Bill Legge
- 28th February 2010, 08:25
Charles,

Thanks, I will have a go at doing the work with DT's interrupts - I'm pretty sure that you are correct.

I wanted to use my own ASM to:

1. Learn more about ASM
2. Learn more about MPLAB and debugging.
3. Learn how to glue ASM into PBP.

The most useful things learnt over the last few days were:

1. Debugging ASM with interrupts in it.
2. After a quickish look at DT's interrupt code I think I may now be able to follow it.

I'd much appreciate your input on getting the code on this thread to run in PBP. Despite playing with 'org' and so on, I keep getting lots of:


overwrite previous address contents error

Regards Bill Legge

mackrackit
- 28th February 2010, 09:06
I'd much appreciate your input on getting the code on this thread to run in PBP. Despite playing with 'org' and so on, I keep getting lots of:


overwrite previous address contents error

Regards Bill Legge
You must be trying to set the configuration fuses more than once.
In the PBP part of the code?
In the ASM part?
In the *.inc file?
http://www.picbasic.co.uk/forum/showthread.php?t=543

Charles Linquis
- 28th February 2010, 19:09
Again -

I think you would be FAR better off if you would just use Darrel's code as a starting point. Since you have two priorities, you need to put the following in your DEFINE block.

DEFINE USE_LOWPRIORITY 1


Then use Darrel's INCLUDE files as needed.

INCLUDE "DT_INTS-18.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ; Include if using PBP interrupts
INCLUDE "ReEnterPBP-18LP.bas" ; Include if using Low Pr. PBP INTS



Then define your variables in PBP. If you have enough space, you can define all of them as BankA SYSTEM. If you don't, make certain that you define all the ones that you want to pass between PBP and ASM as bankA System

The variables will be case-sensitive.


Set up all timer prescalers, clock sources and triggering edges first.


Now put in Darrel's interrupt control block -
Change the labels as necessary.




ASM

INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR0_INT, SystemTimer, ASM, yes
INT_Handler RX1_INT, _GetCharPort1, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor

INT_LIST_L macro ; IntSource, Label, Type, ResetFlag?
INT_Handler PIC_YOUR_INT, StepperControl, ASM,no
endm
INT_CREATE_L ; Creates the Low Priority interrupt processor

ENDASM


Goto OverInt
------------------------------------------
ASM

(Put all your ASM ISR code here)

@ INT_RETURN
ENDASM
-------------------------------------------
[Put all your PBP ISR code here]


@ INT_RETURN

---------------------------------------------

Overint:

(Clear INT flags)


@ INT_ENABLE (name of INT)
@ INT_ENABLE (name of other INT)
@ INT_ENABLE (name of other INT)

NothingLoop:


Goto NothingLoop ; do nothing until you get an int.



Hopefully, I haven't forgotten something. !

Doing things this way will not only likely get you to a running program much faster, it will make it easier for others to give you the help you need. After all, this IS a PBP forum, not an ASM forum.

Bruce
- 1st March 2010, 01:21
Hi Bill,

I like to encourage everyone to learn assembly, and how to handle interrupts. Where would we be here if DT never learned assembly or interrupts...;o)

Here's a simple modified version of what you had. Look at the changes I made VS your original. I could point to every single change,
but it wouldn't help you learn much.


;************************************************* *****************************

LIST P=18F8722 ; Directive to define processor
#include "P18F8722.inc" ; Drocessor specific variable definitions

;************************************************* *****************************
; Configuration bits
CONFIG OSC = HSPLL ; Run at 4X speed
CONFIG CP0=OFF ; Disable code protect
CONFIG PWRT = OFF ; Power up timer off so DEBUG works
CONFIG WDT=OFF ; WDT off
CONFIG LVP = OFF ; LVP off
CONFIG WAIT = OFF ; External bus data wait disabled
;************************************************* *****************************
; Variable definitions in data memory
CBLOCK 0x0000 ; all in ACCESS RAM
Count_pulse ; Loop delay in 5 uS pulse to motor driver
X_delay : 2 ; Inter-pulse delay for X axis, 2 bytes
Y_delay : 2 ; Inter-pulse delay for Y axis, 2 bytes
X_steps : 2 ; Number of steps to do on X axis, 2 bytes
ENDC

;************************************************* *****************************
; Reset vector in program memory
ORG 0x0000
goto Main_ASM ; Go to start of main code
;************************************************* *****************************
; All interrupts vector to here, Priorities disabled
ORG 0x0008
bra Tmr_ints ; Go to interrupt routine
;************************************************* *****************************
;************************************************* *****************************
; Higher priority for Timer0 overflows, send out stepper
; drive pulse for X axis on PORTD.0
Tmr_ints
btfss INTCON,TMR0IF ; did Timer0 interrupt?
bra LowPri ; no. branch to Timer1 int
bsf PORTD,0 ; yes. High PORTD.0
call Pulse_out ; Send 5uS pulse on PORTB.0
bcf PORTD,0 ; Low PORTD.0 (Timer1 interrupts around here)
bcf INTCON,TMR0IF ; Clear Timer0 interrupt flag
movff X_delay+1,TMR0H ; Load timer0 with X_delay high byte
movff X_delay,TMR0L ; Load timer0 with X_delay low byte
movf X_steps,W ; load WREG for compare after subtraction
decf X_steps,F ; Decrement X_steps low byte
cpfslt X_steps ; if X_steps < WREG then jump over next decrement
decf X_steps+1 ; else, decrement high byte

; Lower priority for Timer1 overflows, send out stepper
; drive pulse for Y axis on PORTD.3
LowPri
btfss PIR1,TMR1IF ; Timer1 int pending?
bra IntExit ; no. exit
bsf PORTD,3 ; High PORTD.3
call Pulse_out ; Delay for 10 microseconds
bcf PORTD,3 ; High PORTD.3
bcf PIR1,TMR1IF ; Clear Timer1 interrupt flag
movff Y_delay+1,TMR1H ; Load Timer1 with Y_delay high byte
movff Y_delay,TMR1L ; Load timer1 with Y_delay low byte
IntExit
retfie FAST ; return & restore WREG, STATUS, BSR

;************************************************* ***************************** *
; SUBROUTINES * *
;************************************************* *****************************

Pulse_out ; Delay = 3.n + 7 [0.1 microseconds]
movlw 0xff ; Load w with n
movwf Count_pulse ; Load Count with n
Pulse_loop
decfsz Count_pulse ; Decrament the file Count
goto Pulse_loop ; Loop if not zero
return

;************************************************* ***************************** *
; MAIN ASM * *
;************************************************* *****************************

Main_ASM
clrf TRISA ; PORTA is output
clrf TRISB ; PORTB is output
clrf TRISC ; PORTC is output
clrf TRISD ; PORTD is output
clrf TRISE ; PORTE is output
clrf TRISF ; PORTF is output
clrf TRISG ; PORTG is output
clrf TRISH ; PORTH is output
clrf TRISJ ; PORTJ is output

clrf PORTA ; Clear PORTA
clrf PORTB ; Clear PORTB
clrf PORTC ; Clear PORTC
clrf PORTD ; Clear PORTD
clrf PORTE ; Clear PORTE
clrf PORTF ; Clear PORTF
clrf PORTG ; Clear PORTG
clrf PORTH ; Clear PORTH
clrf PORTJ ; Clear PORTJ

movlw 0x0f
movwf ADCON1 ; PORTA is digital I/O
movlw 0x07
movwf CMCON ; Comparator off

; Set up interrupt conditions for Timer0 and Timer1
bcf RCON,7 ; disable priority levels on interrupts,IPEN=0
bsf INTCON,7 ; Enable all interrupts
bsf INTCON,6 ; Enable all peripheral interrupts
bcf INTCON,3 ; Disable PORTB interrupts
bcf INTCON2,2 ; Make Timer0 overflow low priority
bcf IPR1,0 ; Make Timer1 overflow low priority
bsf INTCON,5 ; Enable Timer0 overflow int
bsf PIE1,0 ; Enable Timer1 overflow int

; Set up Timer0 conditions
bcf T0CON,6 ; Timer0 uses 16 bits
bcf T0CON,5 ; Timer0 uses internal osc
bcf T0CON,4 ; Timer0 count on rising edge og osc
bsf T0CON,3 ; Timer0 pre-scaler not assigned
clrf TMR0H ; Zero the clock
clrf TMR0L ; Zero the clock
bsf T0CON,7 ; Timer0 on

; Set up Timer1 conditions
bsf T1CON,7 ; Timer1 uses 16 bits
bcf T1CON,1 ; Timer1 uses internal osc
clrf TMR1H ; Zero the clock
clrf TMR1L ; Zero the clock
bsf T1CON,0 ; Timer1 on

; Temp code to simmulate PBP input for the delays
clrf X_delay ; this handles the low byte
clrf X_delay+1 ; this handles the high byte
clrf Y_delay
clrf Y_delay+1
clrf X_steps
clrf X_steps+1
; End of Temp code

; Check if X_steps_lb=0 (decremented in high priority interrupt)
; If so, check X_steps_hb and if zero, end
; If not, decrement X_steps_hb, set X_steps_lb and go again
Main_loop
movff X_steps+1,PORTC ; high byte to portc
;btg PORTC,1 ; toggle RC1 (note: comf only works with whole 8-bit registers)
movff X_steps,PORTD ; low byte to portd
;btg PORTD,1 ; toggle RD1
tstfsz X_steps ; Test, skip next if zero
goto Main_loop ; More steps to do, so loop
tstfsz X_steps+1 ; Test, skip next if zero
bra Re_load_lb
goto All_done

Re_load_lb
decf X_steps+1,F ; Decrement hb and then carry to lb
setf X_steps ; Decremented hb, so load ff to lb
goto Main_loop

All_done
bcf INTCON,7 ; Clear GIE, disable ALL interrupts
clrwdt
sleep
goto $-2
end

I think you're much better off putting both interrupts in the same handler, and just checking for which one caused the interrupt VS having a high pri interrupt your low pri, so you can use the auto restore for W, STATUS & BSR.

Bill Legge
- 1st March 2010, 03:44
Bruce,

Wow, what a lot of effort on your part - thanks very much. I will now re-fire up MPLAB and give it a detailed run.

I do take note of CL's comments about this being a PICBASIC site but most entheuastic PBP users will want to experiment with ASM - for fun and speed?

I know that every minuit I've spent on ASM in MPLAB had added greatly to my ability to write software in PBP.

Perhaps there is space for an 'ASM' sub-section in this forum? I can understand that most newcomers will not be interested in this lower level stuff but it seems essential to make the most of PBP.

We are in the middle of a heatwave here in West Australia - almost no rain for 3 months - too hot to do much outside so plenty of key-board time.

Thanks again for your input.

Regards Bill Legge

Charles Linquis
- 1st March 2010, 03:59
My goal was not to discourage ASM use (I use a lot of it myself), but only to point out that DT_INTs would make things easier for you. And since a lot of people on this forum are familiar with their use, a lot more people would be able to help you if you chose that route.

Bill Legge
- 1st March 2010, 07:01
Charles & Bruce,

Thanks for your help.

Bruce: the code you provided works well and I've tested it in MPLAB with a variety of inputs and it's all OK.
I have 'glued it into PBP and still can't get it to compile. The things I changed between the ASM_only and PBP_ASM are:

1. Deleted the .asm CONFIGS because they come from my programmer.
2. Deleted the .asm variable definitions in data memory, defined them in PBP, watched out for caes sensitivity and changed the .asm definitions to have a leading underscore (e.g. _X_steps).

Bill Legge
- 1st March 2010, 07:17
SORRY, I HIT THE WRONG BUTTON BEFORE I HAD COMPLETED THE POST
PLEASE READ ON..........

Charles & Bruce,

Thanks for your help.

Bruce: the code you provided works well and I've tested it in MPLAB with a variety of inputs and it's all OK.
I have 'glued' it into PBP and still can't get it to compile. The things I changed between the 'ASM only' and 'PBP_ASM' are:

1. Deleted the .asm CONFIGS because they come from my programmer.
2. Deleted the .asm variable definitions in data memory, defined them in PBP, watched out for caes sensitivity and changed the .asm definitions to have a leading underscore (e.g. _X_steps).
3. Took out the .asm PORT and TRIS lines because it's done in PBP.
4. Took out the temp code to load the variables because they should come from PBP.
5. Deleted the last 3 lines of code - not needed I presume?

My, failed attempt to get the PBP to run looks like:



' File...... 8722 Scan_ASM_Test
' Purpose... Drive two steppers to achieve diagonal moves
' ************************************************** ***************************
' * *
' * INCLUDE & DEFINES *
' * *
' ************************************************** ***************************
clear
define OSC 40 ' Use HSPLL during compilation

' ************************************************** ***************************
' * *
' * VARIABLES *
' * *
' ************************************************** ***************************
X_steps var word ' Steps to move, not reusable
Count_pulse var WORD Bank0 System ' Pulse duration = 3.n + 7
X_delay var WORD Bank0 System
Y_delay var WORD Bank0 System

goto Start ' Skip over ASM code

' ************************************************** ***************************
' * *
' * ASSEMBLER CODE *
' * *
' ************************************************** ***************************
Run_ASM:
ASM
LIST P=18F8722 ; Directive to define processor
#include "P18F8722.inc" ; Drocessor specific variable definitions
; Reset vector in program memory
ORG 0x0000
goto Main_ASM ; Go to start of main code

;************************************************* *****************************
; All interrupts vector to here in program memory, Priorities disabled
; This is high priority only so wsave etc is automatic
ORG 0x0008
bra Tmr_ints ; Go to interrupt routine

;************************************************* *****************************
; Higher priority for Timer0 overflows, send out stepper
; drive pulse for X axis on PORTD.0
Tmr_ints
btfss INTCON,TMR0IF ; did Timer0 interrupt?
bra LowPri ; no. branch to Timer1 int
bsf PORTD,0 ; yes. High PORTD.0
call Pulse_out ; Call delay routine
bcf PORTD,0 ; Low PORTD.0
bcf INTCON,TMR0IF ; Clear Timer0 interrupt flag
movff _X_delay+1,TMR0H ; Load timer0 with _X_delay high byte
movff _X_delay,TMR0L ; Load timer0 with _X_delay low byte
decf _X_steps,F ; Decrement X_steps low byte

; Lower priority for Timer1 overflows, send out stepper
; drive pulse for Y axis on PORTD.3
LowPri
btfss PIR1,TMR1IF ; Timer1 int pending?
bra IntExit ; no. exit
bsf PORTD,3 ; High PORTD.3
call Pulse_out ; Call delay routine
bcf PORTD,3 ; High PORTD.3
bcf PIR1,TMR1IF ; Clear Timer1 interrupt flag
movff _Y_delay+1,TMR1H ; Load Timer1 with Y_delay high byte
movff _Y_delay,TMR1L ; Load timer1 with Y_delay low byte
IntExit
retfie FAST ; return & restore WREG, STATUS, BSR

;************************************************* ***************************** *
; SUBROUTINES * *
;************************************************* *****************************
Pulse_out ; Delay = 3.n + 7 [0.1 microseconds]
movlw 0xff ; Load w with n
movwf _Count_pulse ; Load Count with n
Pulse_loop
decfsz _Count_pulse ; Decrament the file Count
goto Pulse_loop ; Loop if not zero
return

;************************************************* ***************************** *
; MAIN ASM * *
;************************************************* *****************************
Main_ASM

; Set up interrupt conditions for Timer0 and Timer1
bcf RCON,7 ; Disable priority levels on interrupts,IPEN=0
bsf INTCON,7 ; Enable all interrupts
bsf INTCON,6 ; Enable all peripheral interrupts
bcf INTCON,3 ; Disable PORTB interrupts
bcf INTCON2,2 ; Make Timer0 overflow low priority
bcf IPR1,0 ; Make Timer1 overflow low priority
bsf INTCON,5 ; Enable Timer0 overflow int
bsf PIE1,0 ; Enable Timer1 overflow int

; Set up Timer0 conditions
bcf T0CON,6 ; Timer0 uses 16 bits
bcf T0CON,5 ; Timer0 uses internal osc
bcf T0CON,4 ; Timer0 count on rising edge og osc
bsf T0CON,3 ; Timer0 pre-scaler not assigned
clrf TMR0H ; Zero the clock
clrf TMR0L ; Zero the clock
bsf T0CON,7 ; Timer0 on

; Set up Timer1 conditions
bsf T1CON,7 ; Timer1 uses 16 bits
bcf T1CON,1 ; Timer1 uses internal osc
clrf TMR1H ; Zero the clock
clrf TMR1L ; Zero the clock
bsf T1CON,0 ; Timer1 on

; Temp code to simulate PBP input for the delays
; Removed - should come from PBP

; Check if X_steps_lb=0 (decremented in high priority interrupt)
; If so, check X_steps_hb and if zero, end
; If not, decrement X_steps_hb, set X_steps_lb and go again
Main_loop
movff _X_steps+1,PORTJ ; Steps hi to PORTJ
movff _X_steps,PORTB ; Steps lo to PORTB

tstfsz _X_steps ; Test steps lo, skip next if zero
goto Main_loop ; More steps to do, so loop
tstfsz _X_steps+1 ; Test steps hi, skip next if zero
bra Re_load_lb
goto All_done

Re_load_lb
decf _X_steps+1,F ; Decrement hb and then carry to lb
setf _X_steps ; Decremented hb, so load ff to lb
goto Main_loop

All_done
bcf INTCON,7 ; Clear GIE, disable ALL interrupts
clrwdt

ENDASM
RETURN

' ************************************************** ***************************
' * *
' * INITIALISE *
' * *
' ************************************************** ***************************
Start:
ADCON1 = %00001101 ' A0, A1 analog, rest digital
CMCON = %00000111 ' Comparators off, this frees up PORTF
TRISA = %00000000
TRISB = %00000000
TRISC = %00000000
TRISD = %00000000 ' D.0 is X drive. D.3 is Y drive
TRISE = %00000000 ' LEDs to display X_steps lo byte
TRISF = %00000000
TRISG = %00000000
TRISH = %00000000
TRISJ = %00000000 ' LEDs to display X_steps hi byte

' ************************************************** ***************************
' * *
' * MAIN *
' * *
' ************************************************** ***************************

Main:
X_delay = $FFFF
Y_delay = $FFFF
X_steps = $FFFF
Count_pulse = $FFFF

gosub Run_ASM
pause 100
goto Main

end

You used a .asm technique of defining a data address like:
_X_delay : 2 ; Reserve two bytes in data memory
If I have a variable in PBP like
X_delay VAR WORD
Will the WORD from PBP find it's way to the .asm?

Charles L: I'm still going to do it using DT's interrupts

Regards Bill Legge

Bruce
- 1st March 2010, 16:59
Hi Bill,

Use DEFINE INTHAND and PBP will place a goto at 0x0008 to your int handler. If you have
room in the access bank, it's a good idea to stick your variables there. Then you don't need
to mess with banking in your .asm routines.



' File...... 8722 Scan_ASM_Test
' Purpose... Drive two steppers to achieve diagonal moves
' ************************************************** ***************************
' * *
' * INCLUDE & DEFINES *
' * *
' ************************************************** ***************************
clear
define OSC 40 ' Use HSPLL during compilation
DEFINE INTHAND Tmr_ints

' ************************************************** ***************************
' * *
' * VARIABLES *
' * *
' ************************************************** ***************************
X_steps var word BankA System ' Steps to move, not reusable
Count_pulse var WORD BankA System ' Pulse duration = 3.n + 7
X_delay var WORD BankA System
Y_delay var WORD BankA System

goto Start ' Skip over ASM code

' ************************************************** ***************************
' * *
' * ASSEMBLER CODE *
' * *
' ************************************************** ***************************
ASM
;************************************************* *****************************
; Higher priority for Timer0 overflows, send out stepper
; drive pulse for X axis on PORTD.0
Tmr_ints
btfss INTCON,TMR0IF ; did Timer0 interrupt?
bra LowPri ; no. branch to Timer1 int
bsf PORTD,0 ; yes. High PORTD.0
call Pulse_out ; Call delay routine
bcf PORTD,0 ; Low PORTD.0
bcf INTCON,TMR0IF ; Clear Timer0 interrupt flag
movff X_delay+1,TMR0H ; Load timer0 with _X_delay high byte
movff X_delay,TMR0L ; Load timer0 with _X_delay low byte
decf X_steps,F ; Decrement X_steps low byte

; Lower priority for Timer1 overflows, send out stepper
; drive pulse for Y axis on PORTD.3
LowPri
btfss PIR1,TMR1IF ; Timer1 int pending?
bra IntExit ; no. exit
bsf PORTD,3 ; High PORTD.3
call Pulse_out ; Call delay routine
bcf PORTD,3 ; High PORTD.3
bcf PIR1,TMR1IF ; Clear Timer1 interrupt flag
movff Y_delay+1,TMR1H ; Load Timer1 with Y_delay high byte
movff Y_delay,TMR1L ; Load timer1 with Y_delay low byte
IntExit
retfie FAST ; return & restore WREG, STATUS, BSR

;************************************************* ***************************** *
; SUBROUTINES * *
;************************************************* *****************************
Pulse_out ; Delay = 3.n + 7 [0.1 microseconds]
movlw 0xff ; Load w with n
movwf Count_pulse ; Load Count with n
Pulse_loop
decfsz Count_pulse ; Decrament the file Count
goto Pulse_loop ; Loop if not zero
return

ENDASM
;************************************************* ***************************** *
; MAIN ASM * *
;************************************************* *****************************
ASM
_Main_ASM

; Set up interrupt conditions for Timer0 and Timer1
bcf RCON,7 ; Disable priority levels on interrupts,IPEN=0
bsf INTCON,7 ; Enable all interrupts
bsf INTCON,6 ; Enable all peripheral interrupts
bcf INTCON,3 ; Disable PORTB interrupts
bcf INTCON2,2 ; Make Timer0 overflow low priority
bcf IPR1,0 ; Make Timer1 overflow low priority
bsf INTCON,5 ; Enable Timer0 overflow int
bsf PIE1,0 ; Enable Timer1 overflow int

; Set up Timer0 conditions
bcf T0CON,6 ; Timer0 uses 16 bits
bcf T0CON,5 ; Timer0 uses internal osc
bcf T0CON,4 ; Timer0 count on rising edge og osc
bsf T0CON,3 ; Timer0 pre-scaler not assigned
clrf TMR0H ; Zero the clock
clrf TMR0L ; Zero the clock
bsf T0CON,7 ; Timer0 on

; Set up Timer1 conditions
bsf T1CON,7 ; Timer1 uses 16 bits
bcf T1CON,1 ; Timer1 uses internal osc
clrf TMR1H ; Zero the clock
clrf TMR1L ; Zero the clock
bsf T1CON,0 ; Timer1 on

; Temp code to simulate PBP input for the delays
; Removed - should come from PBP

; Check if X_steps_lb=0 (decremented in high priority interrupt)
; If so, check X_steps_hb and if zero, end
; If not, decrement X_steps_hb, set X_steps_lb and go again
Main_loop
movff X_steps+1,PORTJ ; Steps hi to PORTJ
movff X_steps,PORTB ; Steps lo to PORTB

tstfsz X_steps ; Test steps lo, skip next if zero
goto Main_loop ; More steps to do, so loop
tstfsz X_steps+1 ; Test steps hi, skip next if zero
bra Re_load_lb
goto All_done

Re_load_lb
decf X_steps+1,F ; Decrement hb and then carry to lb
setf X_steps ; Decremented hb, so load ff to lb
goto Main_loop

All_done
bcf INTCON,7 ; Clear GIE, disable ALL interrupts
clrwdt
return
ENDASM

' ************************************************** ***************************
' * *
' * INITIALISE *
' * *
' ************************************************** ***************************
Start:
ADCON1 = %00001101 ' A0, A1 analog, rest digital
CMCON = %00000111 ' Comparators off, this frees up PORTF
TRISA = %00000000
TRISB = %00000000
TRISC = %00000000
TRISD = %00000000 ' D.0 is X drive. D.3 is Y drive
TRISE = %00000000 ' LEDs to display X_steps lo byte
TRISF = %00000000
TRISG = %00000000
TRISH = %00000000
TRISJ = %00000000 ' LEDs to display X_steps hi byte

' ************************************************** ***************************
' * *
' * MAIN *
' * *
' ************************************************** ***************************

Main:
X_delay = $FFFF
Y_delay = $FFFF
X_steps = $FFFF
Count_pulse = $FFFF
CALL Main_ASM
pause 100
goto Main

end

You used a .asm technique of defining a data address like:
_X_delay : 2 ; Reserve two bytes in data memory
If I have a variable in PBP like
X_delay VAR WORD
Will the WORD from PBP find it's way to the .asm?
Yes.

You can also learn a lot about assembly by looking at code in MPLAB after you compile with
PBP.

Bill Legge
- 1st March 2010, 23:30
Bruce,

That all works just great - thank you.

I notice that you:

1. Put an underscore (_) infront of the label that PBP jumps to (_Main_ASM).
2. Not in front of the 'identifier' names of the variable shared between PBP and ASM.

I thought the shared variables needed to:

1. Be declared in PBP.
2. Have an underscore when used in ASM.

Page 194 in the BPB handbook? I'm obviously wrong because the code works?

Regards Bill Legge

Bruce
- 1st March 2010, 23:55
Hi Bill,

Variables declared as SYSTEM types don't have the underscore. See the section on RAM Usage in your manual.

Look at the CALL command for the example with the underscore preceeding the label name.