Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Here's a puzzler!

Status
Not open for further replies.

AGCB

Member
This is a simple A/D program w/ an ad interrupt. But the only way it will work is with the 1 second delay ( in the main loop section). If I put any other delay code in, even if it's the same time value, it will not work. It doesn't seem to have anything to do w/ the time.
Code:
	list		p=18f1220
	#include	<p18f1220.inc>
	
;config options at end of program
	config		osc = intio2, fscm = off, ieso = off	;1h
	config		pwrt = on, bor = on, borv = 27		;2L
	config		wdtps = 1, wdt = off			;2h
	config		mclre = off			 	;3h
	config		stvr = off, lvp = off, debug = off	;4L
				;default code protection off	;5L, 5h
				;default write protection off	;6L, 6h
				;default table read protection off ;7L, 7h
	radix		hex
;-----------------------------------------------------------------------------

;----------cpu equates (memory map)-------------------------------------------
	cblock	0x000	

	endc
;-------------------------------------------------------------------------------
	org	0x0000
	goto	start
	org	0x0008		;comment out if no interrupts
	goto	isr_high	;   isr_high is compatabilty mode also
	
start	movlw	0x60		;internal osc 4.0 MHz
	movwf	osccon
	bcf	adcon0,ADON	;turn off AD
	setf	adcon1		;digital I/O
	
	bcf	intcon,gie
	
	clrf	trisa
	clrf	trisb		;all outputs
	bsf	trisb,4		;AN6 ad input
	clrf	latb		;
	clrf	portb		;all pins low
	clrf	porta
	movlb	0x00		;work in bank 0 GPRs
;----END OF BASIC INIT---------------------------------------------

;init usart----------------------------------
	movlw	.51		;4800 baud
	movwf	SPBRG
	movlw	b'00100100'	;8 bit, txen, async, high speed
	movwf	txsta
	bsf	rcsta,spen	;enable serial port and pins RX/TX

;---interrupt set up-----------------------------------------	
	bsf	intcon,gie	
	bsf	intcon,peie	
	bcf	pir1,adif
	bsf	pie1,adie
	
;---A/D set up ----------------------------------------------
	movlw	b'00011000'	;internal Vref, channel 6 (AN6/Rb4) ,      ad off
	movwf	adcon0
	movlw	b'00111111'	;analog input(0) on AN6/Rb4 (set tris bit also)
	movwf	adcon1		;  all pins digital I/O except AN6
	movlw	b'00100011'	;left justify (8 bit mode), 8 Tad, Frc  (a/d rc clock)
	movwf	adcon2

;================ Main loop==================================
meas	clrf	adresh		
	movlw	.6		;20 us delay (acuisition time 
	rcall	us_delay_lo	
	bsf	adcon0,adon	;turn on a/d	
	bsf	adcon0,1	;set GO/NOT DONE bit  start conversion
	
	movlw	.1		;for some reason it won't work w/o this delay
	rcall	adj_delay_sec	;
circle	bra	circle		;wait for interrupt

;=================Sub routines here=========================

;=================ISERV here================================
;------------SAVING context, W ,status and bsr registers 

;       ! CONTEXT SAVING IS AUTOMATIC for isr_high when intcon,peie
;             is enabled (or) when priority interrupts are disabled
;-------------------------------------------	
isr_high 		;auto context save

;(Insert user code here )
	bcf	pir1,adif
	movff	adresh,txreg	
test1	btfss	txsta,trmt
	bra	test1
	retfie	fast	;return from interrupt using using auto context saving
;---------------------------------------------	
isr_low
	cblock
	w_temp
	status_temp
	bsr_temp
	endc

	MOVWF W_TEMP 			;Copy W to TEMP register
	movff	status,status_temp
	movff	bsr,bsr_temp

;(Insert user code here )


;-------------Restore context--

	movff	bsr_temp,bsr
	movf	w_temp,w
	movff	status_temp,status
	retfie

;=================DELAYS here===============================

;                DO NOT allow interrupts while in timing loops
;                     bcf	intcon,gie   ;disable interrupts
;                     bsf	intcon,gie   ;enable  interrupts

;COMBO of sec and mS delays--------------------------

;-------------Adjustable delay-----1-255 seconds (4 1/4 min)
;                   ;enter with number of seconds in wreg before CALL
			;i.e.    movlw   d'xx'
	cblock
	bc1
	bc2
	bc3
	dc1
	dc2
	dc3
	secs
	endc
	
adj_delay_sec
	bcf	intcon,gie	;disable global interrupts   			
	movwf	secs			
repet	call	delay_ms
	decfsz	secs		;1 loop per number entered with in wreg
	goto	repet		;
	bsf	intcon,gie	;enable global interrupts
	return
	
delay_ms
	movlw	d'100'		;
        banksel bc3             ; Each loop here takes 1 SECOND  
        movwf   bc3             ;
dly2    movlw   .13             ; 
        movwf   bc2             ; 
        clrf    bc1             ; 
dly1    decfsz  bc1,f           ;
        goto    dly1		;
        decfsz  bc2,f           ; 
        goto    dly1		;            
        decfsz  bc3,f           ; 
        goto    dly2
        return
	
;------Adjustable delay-----10-2550ms(2.55 seconds)------------
                   ; delay = W x 10ms
			; enter with multiplier in WREG before CALL
				;i.e.  movlw   d'xx'

adj_delay_ms	
	bcf	intcon,gie	;disable global interrupts   ; delay W x 10ms
        banksel dc3                ; Wx10.015ms
        movwf   dc3             
dly2a    movlw   .13             ; repeat inner loop 13 times
        movwf   dc2             ; -> 13x(767+3)-1 = 10009 cycles
        clrf    dc1             ; inner loop = 256x3-1 = 767 cycles
dly1a    decfsz  dc1,f           
        goto    dly1a
        decfsz  dc2,f           ; end middle loop
        goto    dly1            
        decfsz  dc3,f           ; end outer loop
        goto    dly2a
	bsf	intcon,gie	;enable global interrupts

        return
        
;---uS_delay_lo-----7 - 771 uS ( in steps of 3-----


	;enter with << 1/3 (desired delay minus 3) >> in W (1 - 255) decimal
	;round to nearest whole number

	;I.E.  desired = 66uS   Enter w/ (66 minus 3)/3 in W = 21	

	cblock
	cy
	endc
us_delay_lo
	bcf	intcon,gie
	movwf	cy	;1 cycle
cy1	decfsz	cy	;1 cycle, 2 if result is 0
	goto	cy1	;2 cycles
	bsf	intcon,gie
	return		;2 cycles
			;call insruction adds 2 more!!        

        END
It does not seem that it should need any delay at this point since the interrupt should work in the circle loop. I can not see anything in that delay routine that is different from the other routines.

Can you solve my puzzle?
 
Caveat, I've been drinking.
You have 5 'return' statements, and yet only 1 'call' statement, and that one doesn't count since it's commented out.
(I used the 'find' feature of Notepad to suss that).
 
I don't think the number of "return" statements from subroutines makes a difference per se. My draft code typically has many more subroutines than are actually called.

As for the problem, can you also post the code that doesn't work? NB: I am assuming the posted code worked with the single delay call. If you are using MPLab, can/have you simulate it?

John
 
I don't think the number of "return" statements from subroutines makes a difference per se.
Good point, well put. However, there seems to be no 'Call'ing of the subroutines to begin with.
I've never used the 18F series, and was going to question the CBlock starting at 0x00, after a quick Google, I deceided not to.

That said, I still stand behind what I typed earlier; 'Been drinking'. Seasons greetings all. :)
 
As for the problem, can you also post the code that doesn't work? NB: I am assuming the posted code worked with the single delay call. John

John
If you just comment out the 1 second delay call it doesn't work anymore. Aaron
 
Caveat, I've been drinking.
You have 5 'return' statements, and yet only 1 'call' statement, and that one doesn't count since it's commented out.
(I used the 'find' feature of Notepad to suss that).

There are 2 calls (RCALL) in the main program, one for each of the delays. The other call is in the adj_delay_sec routine. That's what I count.
 
You should poll the done bit anyway i think... just a suggestion.

like :
Code:
;================ Main loop==================================
meas	clrf	adresh
	movlw	.6		;20 us delay (acuisition time
	rcall	us_delay_lo
	bsf	adcon0,adon	;turn on a/d
	bsf	adcon0,1	;set GO/NOT DONE bit  start conversion
meas2
	btfsc   adcon0,1
        goto    meas2
;	movlw	.1		;for some reason it won't work w/o this delay
	rcall	adj_delay_sec	;
circle	bra	circle		;wait for interrupt
 
Last edited:
ok, how about clearing the interrupt flag after enabling the interrup

Code:
	bcf	pir1,adif
	bsf	pie1,adie
; should be

	bsf	pie1,adie
	bcf	pir1,adif

If that does not fix it its still best to do it that way...
 
Do not use the MOVFF instruction to modify
any of the interrupt control registers while
any interrupt is enabled. Doing so may
cause erratic microcontroller behavior

I think your doing that
 
I took that to mean registers like INTCON and PIE1. The isr_low context save is right out of the datasheet and they used MOVFF twice.
 
AGCB Works in ISIS even without a delay...BUT the acquisition delay has to be after you turn on the ADC and before you set the GO/DONE bit

The main problem is you are setting your interrupt FAR to early.... remove the 1 second delay and set the GIE just before the end loop

the reason the delays make no difference to your code is you disable the interrupts while the delay is on

Code:
	list		p=18f1220
	#include	<p18f1220.inc>
 
;config options at end of program
	config		osc = intio2, fscm = off, ieso = off	;1h
	config		pwrt = on, bor = on, borv = 27		;2L
	config		wdtps = 1, wdt = off			;2h
	config		mclre = off			 	;3h
	config		stvr = off, lvp = off, debug = off	;4L
				;default code protection off	;5L, 5h
				;default write protection off	;6L, 6h
				;default table read protection off ;7L, 7h
	radix		hex
;-----------------------------------------------------------------------------
 
;----------cpu equates (memory map)-------------------------------------------
	cblock	0x000	
 
	endc
;-------------------------------------------------------------------------------
	org	0x0000
	goto	start
	org	0x0008		;comment out if no interrupts
	goto	isr_high	;   isr_high is compatabilty mode also
 
start	movlw	0x60		;internal osc 4.0 MHz
	movwf	OSCCON
	bcf	ADCON0,ADON	;turn off AD
	setf	ADCON1		;digital I/O
 
	bcf	INTCON,GIE
 
	clrf	TRISA
	clrf	TRISB		;all outputs
	bsf	TRISB,4		;AN6 ad input
	clrf	LATB		;
	clrf	PORTB		;all pins low
	clrf	PORTA
	movlb	0x00		;work in bank 0 GPRs
;----END OF BASIC INIT---------------------------------------------
 
;init usart----------------------------------
	movlw	.51		;4800 baud
	movwf	SPBRG
	movlw	b'00100100'	;8 bit, txen, async, high speed
	movwf	TXSTA
	bsf	RCSTA,SPEN	;enable serial port and pins RX/TX
 
;---interrupt set up-----------------------------------------	
	bsf	INTCON,PEIE	
	bcf	PIR1,ADIF
	bsf	PIE1,ADIE
 
;---A/D set up ----------------------------------------------
	movlw	b'00011000'	;internal Vref, channel 6 (AN6/Rb4) ,      ad off
	movwf	ADCON0
	movlw	b'00111111'	;analog input(0) on AN6/Rb4 (set tris bit also)
	movwf	ADCON1		;  all pins digital I/O except AN6
	movlw	b'00100011'	;left justify (8 bit mode), 8 Tad, Frc  (a/d rc clock)
	movwf	ADCON2
 
;================ Main loop==================================
meas	clrf	ADRESH	
	bsf	ADCON0,ADON	;turn on a/d	
	movlw	.6		;20 us delay (acuisition time 
	rcall	us_delay_lo	
		
	bsf	ADCON0,1	;set GO/NOT DONE bit  start conversion
 	bsf	INTCON,GIE
	;movlw	.1		;for some reason it won't work w/o this delay
	;rcall	adj_delay_sec	;
circle	bra	circle		;wait for interrupt
 
;=================Sub routines here=========================
 
;=================ISERV here================================
;------------SAVING context, W ,status and bsr registers 
 
;       ! CONTEXT SAVING IS AUTOMATIC for isr_high when intcon,peie
;             is enabled (or) when priority interrupts are disabled
;-------------------------------------------	
isr_high 		;auto context save
 
;(Insert user code here )
	bcf	PIR1,ADIF
	movff	ADRESH,TXREG	
test1	btfss	TXSTA,TRMT
	bra	test1
	retfie	FAST	;return from interrupt using using auto context saving
;---------------------------------------------	
isr_low
	cblock
	w_temp
	status_temp
	bsr_temp
	endc
 
	MOVWF 	w_temp			;Copy W to TEMP register
	movff	STATUS,status_temp
	movff	BSR,bsr_temp
 
;(Insert user code here )
 
 
;-------------Restore context--
 
	movff	bsr_temp,BSR
	movf	w_temp,w
	movff	status_temp,STATUS
	retfie
 
;=================DELAYS here===============================
 
;                DO NOT allow interrupts while in timing loops
;                     bcf	intcon,gie   ;disable interrupts
;                     bsf	intcon,gie   ;enable  interrupts
 
;COMBO of sec and mS delays--------------------------
 
;-------------Adjustable delay-----1-255 seconds (4 1/4 min)
;                   ;enter with number of seconds in wreg before CALL
			;i.e.    movlw   d'xx'
	cblock
	bc1
	bc2
	bc3
	dc1
	dc2
	dc3
	secs
	endc
 
adj_delay_sec
	bcf	INTCON,GIE	;disable global interrupts   			
	movwf	secs			
repet	call	delay_ms
	decfsz	secs		;1 loop per number entered with in wreg
	goto	repet		;
	bsf	INTCON,GIE	;enable global interrupts
	return
 
delay_ms
	movlw	d'100'		;
        banksel bc3             ; Each loop here takes 1 SECOND  
        movwf   bc3             ;
dly2    movlw   .13             ; 
        movwf   bc2             ; 
        clrf    bc1             ; 
dly1    decfsz  bc1,f           ;
        goto    dly1		;
        decfsz  bc2,f           ; 
        goto    dly1		;            
        decfsz  bc3,f           ; 
        goto    dly2
        return
 
;------Adjustable delay-----10-2550ms(2.55 seconds)------------
                   ; delay = W x 10ms
			; enter with multiplier in WREG before CALL
				;i.e.  movlw   d'xx'
 
adj_delay_ms	
	bcf	INTCON,GIE	;disable global interrupts   ; delay W x 10ms
        banksel dc3                ; Wx10.015ms
        movwf   dc3             
dly2a    movlw   .13             ; repeat inner loop 13 times
        movwf   dc2             ; -> 13x(767+3)-1 = 10009 cycles
        clrf    dc1             ; inner loop = 256x3-1 = 767 cycles
dly1a    decfsz  dc1,f           
        goto    dly1a
        decfsz  dc2,f           ; end middle loop
        goto    dly1            
        decfsz  dc3,f           ; end outer loop
        goto    dly2a
	bsf	INTCON,GIE	;enable global interrupts
 
        return
 
;---uS_delay_lo-----7 - 771 uS ( in steps of 3-----
 
 
	;enter with << 1/3 (desired delay minus 3) >> in W (1 - 255) decimal
	;round to nearest whole number
 
	;I.E.  desired = 66uS   Enter w/ (66 minus 3)/3 in W = 21	
 
	cblock
	cy
	endc
us_delay_lo
	bcf	INTCON,GIE
	movwf	cy	;1 cycle
cy1	decfsz	cy	;1 cycle, 2 if result is 0
	goto	cy1	;2 cycles
	bsf	INTCON,GIE
	return		;2 cycles
			;call insruction adds 2 more!!        
 
        END
I had to change ALL the definitions to uppercase as this is how my assembler is set up
 
The main problem is you are setting your interrupt FAR to early.... remove the 1 second delay and set the GIE just before the end loop

the reason the delays make no difference to your code is you disable the interrupts while the delay is on



I've made those corrections and it still works only with that one particular delay routine in place. I tried almost everything I know of. I'm satisfied to leave it that way because it works but there's a fly in the soup somewhere! thanks Aaron
 
Status
Not open for further replies.
Back
Top