ADC register injection being ignored (PIC 16f690 - MPLAB V8)

Find out how to setup your programmer's software and how to solve many common problems.

Moderator: phalanx

Post Reply
Ozwurld
Posts: 13
Joined: Sat Apr 26, 2014 9:06 am

ADC register injection being ignored (PIC 16f690 - MPLAB V8)

Post by Ozwurld » Fri May 02, 2014 12:46 pm

Hello all,

Firstly i am a complete newbie at all this and i'm doing my best to try to understand this awesome micros functionalities.



I am busy trying to learn how to work with ADC's. I am building a solar lantern and would to monitor the amount of voltage left in my battery when the lantern is in use so that i can turn on a green LED when the battery still has enough energy else turn on a Red LED when the battery energy is low....



My ADC code doesnt seem to be working right in the simulator someone please have a looksy at my code...

Code: Select all

;**********************************************************************
;   This file is a basic code template for assembly code generation   *
;   on the PIC16F690. This file contains the basic code               *
;   building blocks to build upon.                                    *  
;                                                                     *
;   Refer to the MPASM User's Guide for additional information on     *
;   features of the assembler (Document DS33014).                     *
;                                                                     *
;   Refer to the respective PIC data sheet for additional             *
;   information on the instruction set.                               *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Filename:	    ADC - Battery Voltage Monitor.asm                                           *
;    Date:                                                            *
;    File Version:                                                    *
;                                                                     *
;    Author: Phindulo Owen Mulaudzi (603854)                                                          *
;    Company:                                                         *
;                                                                     * 
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files Required: P16F690.INC                                      *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes:                                                           *
;                                                                     *
;**********************************************************************


	list		p=16f690		; list directive to define processor
	#include	<P16F690.inc>		; processor specific variable definitions
	
	errorlevel -203
    errorlevel -205
    errorlevel -302

	__CONFIG    _CP_OFF & _CPD_OFF & _BOR_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _MCLRE_ON & _FCMEN_OFF & _IESO_OFF


; '__CONFIG' directive is used to embed configuration data within .asm file.
; The labels following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.




;***** VARIABLE DEFINITIONS
w_temp		EQU	0x7D			; variable used for context saving
status_temp	EQU	0x7E			; variable used for context saving
pclath_temp	EQU	0x7F			; variable used for context saving

;**********************************************************************
cblock 0x20
	d1
	d2
	RESULTHI
	RESULTLO
endc

;**********************************************************************
	ORG		0x000			; processor reset vector
  	goto		main			; go to beginning of program


	ORG		0x004			; interrupt vector location
	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
	movf		PCLATH,w		; move pclath register into W register
	movwf		pclath_temp		; save off contents of PCLATH register


; isr code can go here or be located as a call subroutine elsewhere

	movf		pclath_temp,w		; retrieve copy of PCLATH register
	movwf		PCLATH			; restore pre-isr PCLATH register contents	
	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


main

;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
						;STARTING ADC CONVERSION PROCEDURE
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;1. Configure Port:
;• Disable pin output driver (See TRIS register)
;• Configure pin as analog
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
banksel	TRISC;
bsf		TRISC,0 ;disable output driver by making pin an input

banksel	ANSEL;
bcf		ANSEL,4 ;set RCO/AN4 as analogue input

banksel	ANSELH;
clrf	ANSELH

banksel	ADRESH
clrf	ADRESH ;init

banksel	ADRESL
clrf	ADRESL ;init

;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;2. Configure the ADC module:
;• Select ADC conversion clock
;• Configure voltage reference
;• Select ADC input channel
;• Select result format
;• Turn on ADC module
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
banksel	ADCON1;
bcf		ADCON1,ADCS0;
bsf		ADCON1,ADCS1;
bsf		ADCON1,ADCS2 ;select Fosc/4 : 110

banksel	ADCON0;
bcf		ADCON0,VCFG ;use VDD pin as reference voltage

banksel	ADCON0;
bcf		ADCON0,CHS0;
bcf		ADCON0,CHS1;
bsf		ADCON0,CHS2;
bcf		ADCON0,CHS3; ;select pin RC0/AN4 : 0100

banksel	ADCON0;
bcf		ADCON0,ADFM;	Left justify A/D conversion

banksel	ADCON0
bsf		ADCON0,ADON;	Enable ADC
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;3. Configure ADC interrupt (optional):
;• Clear ADC interrupt flag 
;• Enable ADC interrupt
;• Enable peripheral interrupt
;• Enable global interrupt
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
banksel	PIR1;
bcf		PIR1,ADIF ;clear ADC interrupt flag

banksel	PIE1;
bsf		PIE1,ADIE ; enable ADC interrupt

banksel	INTCON
bsf		INTCON,PEIE; enable peripheral interrupt

banksel	INTCON;
bcf		INTCON,GIE; enable global interrupt

;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;4. Wait the required acquisition time.
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
banksel	OSCCON;
bcf		OSCCON,IRCF0;
bsf		OSCCON,IRCF1;
bsf		OSCCON,IRCF2; ;set internal oscillator to 4MHz, uhmmm 1 instruction = 250us??

; Delay = 0.001 seconds = 1,000uS
movlw	0xC7;
movwf	d1;
movlw	0x02;
movwf	d2;

Delay_1us:
decfsz	d1, f;
goto	$+2;
decfsz	d2, f;
goto	Delay_1us;

;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;5. Start conversion by setting the GO/DONEbit.
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
banksel	ADCON0;
bsf		ADCON0,1
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;6. Wait for ADC conversion to complete by one of the following:
;• Polling the GO/DONEbit
;• Waiting for the ADC interrupt (interrupts enabled)
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
banksel	PIR1;
btfss	PIR1, ADIF;
goto	$-1;	//wait for ADC to complete
banksel	PIR1;
bcf		PIR1, ADIF;
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;7. Read ADC Result
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
banksel ADRESH ;
movf ADRESH,W ;Read upper 2 bits

movwf RESULTHI ;store in GPR space

banksel ADRESL ;
movf ADRESL,W ;Read lower 8 bits
movwf RESULTLO ;Store in GPR space
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;8. Clear the ADC interrupt flag (required if interrupt is enabled).
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
banksel	PIR1;
bcf		PIR1, ADIF; clear ADC flag

banksel	ADCON0
bcf		ADCON0,ADON;	Disable ADC

goto $




	ORG	0x2100				; data EEPROM location
	DE	1,2,3,4				; define first four EEPROM locations as 1, 2, 3, and 4




	END                       ; directive 'end of program'


Last edited by Ozwurld on Fri May 02, 2014 4:49 pm, edited 2 times in total.

Dave Mueller
Posts: 198
Joined: Sat Apr 30, 2011 8:09 pm

Re: ADC register injection being ignored (PIC 16f690 - MPLAB

Post by Dave Mueller » Fri May 02, 2014 2:50 pm

Sorry I can't help with the ASM code, but you might want to give us an idea of what isn't working. Value not what you'd expect, always 0, always 1023, led blinks etc. What happens if you use a pot between Vdd and Ground, and the wiper to the ADC pin? Does the value change?

Ozwurld
Posts: 13
Joined: Sat Apr 26, 2014 9:06 am

Re: ADC register injection being ignored (PIC 16f690 - MPLAB

Post by Ozwurld » Fri May 02, 2014 5:57 pm

Dave Mueller wrote:Sorry I can't help with the ASM code, but you might want to give us an idea of what isn't working. Value not what you'd expect, always 0, always 1023, led blinks etc. What happens if you use a pot between Vdd and Ground, and the wiper to the ADC pin? Does the value change?
Thanks for the reply, i am using the simulator with Vdd as my reference voltage. I used a .txt file in [debugger>>stimulus>>new-workbook] with just one line that read 5. im using this as my synchronus stimulus. And according to my knowledge a 5 should be read as 0b1 i.e a high but the value in ADRESH register never changes....

I hope this is clear, i am happy to give more details if required.

edit:

->After a bit of exploring the MPLAB sim i managed to find [Debugger>>Stimulus>>new workbook>>Registerinjection(tab)]
The register injection tab allows me to create a .txt stimulus so what i did is:

i created a text file with one line that reads 255 in decimal, i am assuming this should count as a high i.e 5V. However when i look at the values in ADRESH and ADRESL they dont seem to make sense.

I found a formula that states:

Value of [ADRESH / ADRESL] = (Measured Value/Vref)*256 and based on this; the values in ADRESH and ADRESH dont seem valied as the formula doesnt give me a measured value of 5V which should correspond to the 255 in the text file.

>>>Please advice..., i have attached the picture of the ADESH and ADESL values that i got

Thanks.

[img]
http://i1307.photobucket.com/albums/s58 ... 4e6dda.png
[/img]

User avatar
phalanx
Non-SFE Guru
Posts: 1992
Joined: Sun Nov 30, 2003 8:57 am
Location: Candia, NH

Re: ADC register injection being ignored (PIC 16f690 - MPLAB

Post by phalanx » Mon May 05, 2014 9:46 am

Register injection with the simulator is not something I'm well versed in but I have found some problems with your code.

You never clear the interrupt flag for the A/D in your ISR. After you run the RETFIE instruction to return to your normal program flow, you would immediately jump back to the ISR since the flag isn't cleared.

Code: Select all

	ORG		0x004			; interrupt vector location
	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
	movf		PCLATH,w		; move pclath register into W register
	movwf		pclath_temp		; save off contents of PCLATH register

; isr code can go here or be located as a call subroutine elsewhere

	movf		pclath_temp,w		; retrieve copy of PCLATH register
	movwf		PCLATH			; restore pre-isr PCLATH register contents	
	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
ADCON1 [ADCS2:ADCS0] = 0b110 is Fosc/64, not Fosc/4 if that matters to you.

Code: Select all

banksel	ADCON1;
bcf		ADCON1,ADCS0;
bsf		ADCON1,ADCS1;
bsf		ADCON1,ADCS2 ;select Fosc/4 : 110
You shouldn't be adjusting the execution speed mid program unless you know what you're doing. You should do this first before initializing everything else. For 8-bit PICs, the instruction clock is Fosc/4 so at 4MHz your instruction time would be 1uS.

Code: Select all

banksel	OSCCON;
bcf		OSCCON,IRCF0;
bsf		OSCCON,IRCF1;
bsf		OSCCON,IRCF2; ;set internal oscillator to 4MHz, uhmmm 1 instruction = 250us??
If you are using 250us as your instruction clock from above, your delay routine will be hosed up and will likely be finishing in 1/250th of the time you expect. MPLAB has a "stopwatch" feature that will let you time how many instructions have passed for a loop. Use it to verify your delay. Keep in mind that you need to set your clock frequency in the project properties so the calculations made by the stopwatch are correct.

Code: Select all

; Delay = 0.001 seconds = 1,000uS
movlw	0xC7;
movwf	d1;
movlw	0x02;
movwf	d2;

Delay_1us:
decfsz	d1, f;
goto	$+2;
decfsz	d2, f;
goto	Delay_1us;
You shouldn't be trying to check the completion of the conversion by both polling and interrupts. Pick one or the other. I would disable all interrupts and concentrate on polling until you are comfortable with the operation of the A/D.

Code: Select all

;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;6. Wait for ADC conversion to complete by one of the following:
;• Polling the GO/DONEbit
;• Waiting for the ADC interrupt (interrupts enabled)
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
banksel	PIR1;
btfss	PIR1, ADIF;
goto	$-1;	//wait for ADC to complete
banksel	PIR1;
bcf		PIR1, ADIF;
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Since you set up the A/D data to be left justified, when you read ADRESH you are getting the upper 8 bits of the conversion and ADRESL will contain the lower 2 bits (stored in the MSBs of ADRESL).

Code: Select all

;7. Read ADC Result
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
banksel ADRESH ;
movf ADRESH,W ;Read upper 2 bits

movwf RESULTHI ;store in GPR space

banksel ADRESL ;
movf ADRESL,W ;Read lower 8 bits
movwf RESULTLO ;Store in GPR space
While this wouldn't hurt anything being executed here, it needs to be at the end of your ISR for proper functionality.

Code: Select all

;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;8. Clear the ADC interrupt flag (required if interrupt is enabled).
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
banksel	PIR1;
bcf		PIR1, ADIF; clear ADC flag

-Bill

Ozwurld
Posts: 13
Joined: Sat Apr 26, 2014 9:06 am

Re: ADC register injection being ignored (PIC 16f690 - MPLAB

Post by Ozwurld » Wed May 07, 2014 2:16 am

Thanks you very much Bill :)

all is well now..

Post Reply