1
\$\begingroup\$

How can I get my code to work correctly when I include ADC conversion in it?

I have a working code that displays two digits on 2 LED displays using a p16f1829. However, a problem arises when I try to include a code block that collects the results of an ADC conversion to display on the LED display (see below).

A2D:
; Start the ADC
        NOP                         ; Requried ADC delay of 8uS => (1/(Fosc/4)) = (1/(500KHz/4)) = 8uS
        BANKSEL     ADCON0          ; Selects memory bank containing ADCON0 register 
        BSF         ADCON0, GO      ; Start the ADC
        BTFSC       ADCON0, GO      ; This bit will be cleared when the conversion is complete
        GOTO        $-1             ; Keep checking the above line until GO bit is clear

; Grab Results and write to the LEDs
        SWAPF       ADRESH, w       ; Get the top 4 MSbs (remember that the ADC result is LEFT justified!)
        MOVWF       L0
        RETURN

To be more precise, it seems to occur at the very point where I am trying to grab the corresponding value from the lookup table (see below):

enter image description here

The result in W-reg after that instruction should be 0x7D. However, it exits the Lookup table without returning the expected value.

enter image description here

The original working code without the ADC block is below:

    LIST        p=16f1829   ;list directive to define processor
    #INCLUDE    <p16f1829.inc>  ;processor specific variable definitions

    __CONFIG _CONFIG1, (_FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF);
    __CONFIG _CONFIG2, (_WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _LVP_OFF);

;-------------------------------------------------------------------------

; UDATA_SHR declares a section of shared (all across the banks) uninitialised data
INT_VAR     UDATA_SHR   ; INT_VAR is the section name in ACCESS RAM
TempC       RES     1   ;
L0          RES     1   ;
w_temp      RES     1   ; variable used for context saving
pclath_temp     RES 1   ; variable used for context saving
status_temp RES     1   ; variable used for context saving

;-------------------------------------------------------------------------

LEDtrisA    EQU     TRISA
LEDtrisC    EQU     TRISC
LEDlatA     EQU     LATA
LEDlatC     EQU     LATC

;-------------------------------------------------------------------------

RESET_VECTOR    CODE    0x0000
        GOTO    START   ; When using debug header, ICD2 may not stop
                        ; on instruction 0 during reset.

;-------------------------------------------------------------------------

INT_VECTOR      CODE    0x0004  ; Interrupt vector location
    
ISR             ; Relocatable Interrupt Service Routine
;   Context saving for ISR
    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   ; Saves value in register PCLATH
    MOVWF   pclath_temp

;-------------------------------------------------------------------------

;   If the interrupt came from the timer, execute the TMR0 interrupt 
;   service routine. 

    BANKSEL     TMR0
    MOVLW       .96
    MOVWF       TMR0
    BTFSC       INTCON, TMR0IF  
    CALL        Service_TMR0    
    BRA         UpdateDisplay   ; Refresh the display

UpdateDisplay
    BANKSEL     LATA        ; Selects memory bank containing LATA register 
    MOVF        LEDlatA, w  ; display status -> w register
    ANDLW       0x0f        ; Separate the lower half byte
    MOVWF       TempC       ; Save display status in TempC
    BSF         TempC, 4    ; Beginning status of LSD display
    RRF         TempC, F    ; Set the status of the next display
    BTFSS       STATUS, C   ; C = 1?
    BCF         TempC, 3    ; If not, turn off the LSD display
    BTFSC       TempC, 0

    BRA         UpdateMsd   ; If it is turned on, display the MSD
                            ; digit of the number
UpdateLsd
    BCF         TempC, 3    
    BSF         TempC, 1                
    BTFSS       STATUS, Z   ; If it is, skip
    MOVF        L0, w       ; Third LSD digit -> w
    ANDLW       0x0f        ;   /
    BRA         DisplayOut  ; Show it on the display

UpdateMsd
    SWAPF   L0, w       ; MSD figure - >
    ANDLW   0x0f        ;   /
    BTFSC   STATUS, Z   ; MSD = 0?
    MOVLW   0x0a        ; If it is, skip

DisplayOut
    CALL    LedTable    ; Take the mask for a digit
    MOVWF   LEDlatC     ; Set the mask on port B
    MOVF    TempC, W    ; Turn on displays
    MOVWF   LEDlatA
    BRA ISR_END

LedTable
    ADDWF   PCL, F
    RETLW   B'00111111' ; mask for digit 0
    RETLW   B'00000110' ; mask for digit 1
    RETLW   B'01011011' ; mask for digit 2
    RETLW   B'01001111' ; mask for digit 3
    RETLW   B'01100110' ; mask for digit 4
    RETLW   B'01101101' ; mask for digit 5
    RETLW   B'01111101' ; mask for digit 6
    RETLW   B'00000111' ; mask for digit 7
    RETLW   B'01111111' ; mask for digit 8
    RETLW   B'01101111' ; mask for digit 9
    RETLW   B'00000000' ; no digit ......

;-------------------------------------------------------------------------

ISR_END
;   Restore contents before returning from interrupt    
    MOVF    pclath_temp,w   ; PCLATH is given its original content
    MOVWF   PCLATH
    MOVF    status_temp,w   ; STATUS is given its original content
    MOVWF   STATUS
    SWAPF   w_temp,f        ; W is given its original content
    SWAPF   w_temp,w

    BSF     INTCON,GIE  ; Global interrupt enabled
    RETFIE              ; Return from interrupt routine

;-------------------------------------------------------------------------

MAIN_PROG   CODE

START

;-------------------------------------------------------------------------

    ERRORLEVEL -302     ; Disable warning accessing register not in bank 0
    BANKSEL OSCTUNE     ; Configure OPTION_REG and TMR0
    MOVLW   0x00        ; Set oscillator to factory calibrated frequency
    MOVWF   OSCTUNE     ;
    BANKSEL STATUS
    ERRORLEVEL +302     ; Enable warning accessing register not in bank 0

CLEAR_RAM                   ; code sequence initialises all GPR's to 0x00   
    MOVLW       0x70        ; initialise pointer
    MOVWF       FSR0        ; to RAM
    CLRF        FSR0H

NEXT
    CLRF        INDF0       ; Clear INDF0 register
    INCF        FSR0L, F    ; Inc pointer
    BTFSS       FSR0L, 7    ; All done?
    GOTO        NEXT        ; No, clear NEXT

CONTINUE                    ; Yes, CONTINUE
    NOP

;-------------------------------------------------------------------------
; MAIN BODY OF PROGRAM
;-------------------------------------------------------------------------

; Setup main init
        BANKSEL     OSCCON      ; Selects memory bank containing OSCCON register 
        MOVLW       b'01011000'     ; Set CPU clock speed of 500KHz -> correlates to (1/(500K/4)) for each instruction
        MOVWF       OSCCON          ; OSCCON <- 0x38

; Setup pins as digital I/O 
    BANKSEL     ANSELA      ; Selects memory bank containing ANSELA register 
    CLRF        ANSELA      ; All pins are digital
    CLRF        ANSELC

; Configure the input & output pins 
    BANKSEL     TRISA           ; Selects memory bank containing TRISA register 
    MOVLW       b'11111100'     ; RA0 and RA1 are configured as outputs and
                                ; used for 7-segment display multiplexing
                                ; RA2 is input push-button for initialization
    MOVWF       TRISA
    CLRF        LEDtrisC    ; Port C is output


    BANKSEL     LATA        ; Selects memory bank containing LATA register 
    CLRF        LEDlatA     ; Set all outputs to "0"
    CLRF        LEDlatC ;
    BSF         LEDlatA, 1  ; Turn on MSD display 

; Setup Timer0 as the delay
    BANKSEL OPTION_REG
    MOVLW   b'10000100'     ; TMR0 is incremented each 32us (Fclk=8MHz)
    MOVWF   OPTION_REG  ; ps = 32

    BANKSEL     TMR0        ; Selects memory bank containing TMR0 register
    BSF         INTCON, GIE     ; Global interrupt enabled
    BSF         INTCON, TMR0IE  ; Timer TMR0 interrupt enabled

    MOVLW       0x79
    MOVWF       L0

MAINLOOP
    BRA         MAINLOOP    ; Continue forever

; TIMER 0 Interrupt routine clears the TMR0 interrupt flag.
Service_TMR0:
    BANKSEL     INTCON
    BCF         INTCON, TMR0IF  ; MUST ALWAYS clear this in software or else stuck in the ISR forever
    RETURN          

;-------------------------------------------------------------------------
; END OF PROGRAM
;-------------------------------------------------------------------------

    END         ; End of program   

I have tried all sorts and have currently a mental block on how to proceed. Any insights that anyone can provide will be very much appreciated.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ This is the exact same question as on StackOverflow. \$\endgroup\$ – the busybee Jan 8 at 7:31
  • \$\begingroup\$ That's correct. Is that not allowed? Because, I read somewhere on this forum that it's often useful to post embedded systems related questions on both sides, as you get different experts from different fields on both sites who are able to provide alternative insights. \$\endgroup\$ – aLoHa Jan 9 at 0:49
  • \$\begingroup\$ I don't know. I just wanted to send visitors to the other question, in case there is an answer. \$\endgroup\$ – the busybee Jan 9 at 18:40
  • \$\begingroup\$ Ok, understood. Good point. \$\endgroup\$ – aLoHa Jan 9 at 22:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.