Author Topic: moving alarm clock to PIC but display won't update  (Read 1713 times)

0 Members and 1 Guest are viewing this topic.

Offline blewisjr

  • Frequent Contributor
  • **
  • Posts: 301
moving alarm clock to PIC but display won't update
« on: May 25, 2013, 05:21:19 pm »
Hello Again

So I am in the process of updating my alarm clock project to a PIC because 1. I like the chips better and 2. I have quite a few chips on hand and I want to make multiples.  I am trying to get the project back to the point where it was with the AVR but I ran into a hiccup.  I am so close to getting to where I was at only 2 more steps to take but I can not get this display to update for the life of me.  From all of my debugging endeavors everything is working like it should be through the simulator but when I run it on the chip I get 1 segment on 1 display to light up and it is the wrong segment.

I will admit it is probably from the fact that I converted the code to assembler when previously it was in C.  This is not complicated at all it technically should work.

A few pieces of info needed to understand the look up table.  The segments are hooked up to the port not by pin order of the display but by pin order of the uC.  So this means segment A which is the top segment on the display goes to pin 0.  So A..G = 0..6.

This also means that for display selection Display 1's cathode / transistor combo goes to pin 0.  So 1..4 = 0..3
Here is the code maybe a PIC expert can see my mistake.  But like I said according to the simulator all of the latches are at the values they are suppose to be at the particular point in the program.

There is also some toggle code in the ISR to ensure it was not actually overlapping but everything is more then good.

CODE:
Code: [Select]
    #include <p16f1782.inc>

    ; configuration fuses
    __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
    __CONFIG _CONFIG2, (_WRT_OFF & _VCAPEN_OFF & _PLLEN_OFF & _STVREN_ON & _LVP_OFF)

    ; use decimal as default radix
    radix dec

; =============================================================================
; Code Vectors
; =============================================================================

; executed on chip reset
Reset_Vec: code 0x0000
    goto Start                                  ; move PC to Start section in Program code block

; executed on interrupt
Interrupt_Vec: code 0x0004
    btfsc INTCON, 5                             ; check if timer0 overfow interrupt is enabled
    bra chk_ovf_flag                            ; goto timer0 overflow flag check
    retfie                                      ; not an interrupt we are interested in exit

chk_ovf_flag:
    btfsc INTCON, 2                             ; check if interrupt is a timer overflow skip otherwise
    goto TMR0_Ovf                               ; execute timer overflow isr
    retfie                                      ; not an interrupt we are interested in exit

; =============================================================================
; Interrupt Service Code Block
; =============================================================================

Interrupt_Service: code

; Timer0 overflow interrupt service routine
TMR0_Ovf:
    bcf     INTCON, 2                           ; clear timer0 overflow interrupt flag
    banksel LATB                                ; bank2
    bsf     LATB, 4
    btfsc   LATB, 0                             ; if digit 1 is set it was just updated
    bra     update_dig2                         ; update digit 2

    btfsc   LATB, 1                             ; if digit 2 is set it was just updated
    bra     update_dig3                         ; update digit 3

    btfsc   LATB, 2                             ; if digit 3 is set it was just updated
    bra     update_dig4                         ; update digit 4

    btfsc   LATB, 3                             ; if digit 4 is set it was just updated
    bra     update_dig1                         ; update digit 1

    bra     update_dig1                         ; otherwise we need to update digit 1 (first update only)

update_dig1:
    bcf     LATB, 3                             ; in bank2 clear RB4 so we can update digit 1
    bsf     LATB, 0                             ; set RB0 so we can update digit 1
    movlw   1                                   ; grab digit 1 from table
    call    Digit_tbl
    movwf   LATA                                ; in bank2 load digit to display
    bcf     LATB, 4
    retfie

update_dig2:
    bcf     LATB, 0                             ; in bank2 clear RB0 so we can update digit 2
    bsf     LATB, 1                             ; set RB1 so we can update digit 2
    movlw   2                                   ; grab digit 2 from table
    call    Digit_tbl
    movwf   LATA                                ; in bank2 load digit to display
    bcf     LATB, 4
    retfie

update_dig3:
    bcf     LATB, 1                             ; in bank2 clear RB1 so we can update digit 3
    bsf     LATB, 2                             ; set RB2 so we can update digit 3
    movlw   0                                   ; grab digit 0 from table
    call    Digit_tbl
    movwf   LATA                                ; in bank2 load digit to display
    bcf     LATB, 4
    retfie

update_dig4:
    bcf     LATB, 2                             ; in bank2 clear RB2 so we can update digit 4
    bsf     LATB, 3                             ; set RB3 so we can update digit 4
    movlw   0                                   ; grab digit 0 from table
    call    Digit_tbl
    movwf   LATA                                ; in bank2 load digit to display
    bcf     LATB, 4
    retfie

; =============================================================================
; Program Code Block
; =============================================================================

Program: code

; performs program setup logic
Start:
    movlw       b'01101000'                         ; set cpu frequency 4 MHZ (1 microsecond / instruction)
                                                    ; 0------- PLL is disabled
                                                    ; -1101--- 4 MHZ clock
                                                    ; -----0--
                                                    ; ------00 clock selection determined by fuse settings
    banksel     OSCCON                              ; bank1
    movwf       OSCCON
    clrf        TRISA                               ; in bank1 set PORTA as output
    clrf        TRISB                               ; in bank1 set PORTB as output
    movlw       b'11010011'                         ; setup timer internal clock 1:16 prescale
                                                    ; gives us an overflow once every 4ms
                                                    ; 11------ not used on timer0
                                                    ; --0----- internal clock count
                                                    ; ---1---- not using T0CKI
                                                    ; ----0--- use prescale
                                                    ; -----011 1:16 prescale
    movwf       OPTION_REG
    movlw       b'10100000'                         ; enable global interrupt and timer0 overflow interrupt
                                                    ; 1------- global interrupt enable
                                                    ; -0------
                                                    ; --1----- timer0 overflow interrupt enable
                                                    ; ---0----
                                                    ; ----0---
                                                    ; -----000 interrupt flags
    movwf       INTCON
    banksel     TMR0                                ; bank0
    clrf        TMR0                                ; clear timer
    banksel     LATA                                ; bank2
    clrf        LATA                                ; make sure PORTA data latch is clear
    clrf        LATB                                ; make sure PORTB data latch is clear

; main program loop
loop:
    bra loop                                        ; loop forever

; =============================================================================
; 7 Segment Display Digit Lookup Table
; =============================================================================

; We need to ensure our table does not rollover the page boundary
; so we will specify where the data will be located in memory.
Display_Digit_Lookup: code 0x200

; Index into the table with wreg returns value at index in wreg
Digit_tbl:
    addwf   PCL, f
    retlw   b'00111111'                             ; digit 0
    retlw   b'00000110'                             ; digit 1
    retlw   b'01011011'                             ; digit 2
    retlw   b'01001111'                             ; digit 3
    retlw   b'01100110'                             ; digit 4
    retlw   b'01101101'                             ; digit 5
    retlw   b'01111101'                             ; digit 6
    retlw   b'00000111'                             ; digit 7
    retlw   b'01111111'                             ; digit 8
    retlw   b'01101111'                             ; digit 9

    end                                             ; end of code
 

Offline Mr Smiley

  • Frequent Contributor
  • **
  • Posts: 324
  • Country: gb
Re: moving alarm clock to PIC but display won't update
« Reply #1 on: May 25, 2013, 06:28:43 pm »
Hi,

Have you considered the RMW problem ( Read-Modify-Write).

When i started playing with multiplexed 7-segs, i got the same problem, single digit showing ghosted numbers.

I was stumped and through curiosity, used a buffer register and it solved the problem strait away

i.e.

bsf sLATB
movf sLATB,w
movwf LATB.

Now i don't know if RMW happens on the 16F1782, so i could be completely wrong, but it was the cause when i did multiplexing.

Mr Smiley
 :)
There is enough on this planet to sustain mans needs. There will never be enough on this planet to sustain mans greed.
 

Offline blewisjr

  • Frequent Contributor
  • **
  • Posts: 301
Re: moving alarm clock to PIC but display won't update
« Reply #2 on: May 25, 2013, 06:59:21 pm »
Well I made some mods to the code.  I moved the segment pins to portC as port A has an input only pin.  Then I made sure I disabled analog input on B.  Still having the same issue.  I will try out a buffer register for the transistor switching on portb.

EDIT:

Same results running the transistor switches through a buffer register.

I have to be missing something somewhere because everything is working perfect according to the simulator maybe the chip is bad...
« Last Edit: May 25, 2013, 07:27:49 pm by blewisjr »
 

Offline blewisjr

  • Frequent Contributor
  • **
  • Posts: 301
Re: moving alarm clock to PIC but display won't update
« Reply #3 on: May 25, 2013, 09:08:42 pm »
Sorry for the double post but I think the solution and how I came to it is important enough for someone searching later down the road.

Everything was working great for the simulator no hitches at all.  What I found odd was that on the actual hardware everything was bonked up and not working like it was in the simulator.  So I decided to debug with the debugger going through the actual in circuit scenario.

I set a break point on the return from the interrupt on the 1st digit and noticed immediately what the problem was.  There was no value in LATC.  This is not good  :palm:

So now we arrive to the actual issue.  Well if there is no value going to LATC that means there is no value in WREG which means my lookup table was never executing on the hardware.  In my code I tried to place the Digit_tbl in a specific memory location.  To be precise the code section is placed at 0x200.  At first glance it looks fine but in reality there is no location 0x200.  There is only one memory page for program memory and it rolls over at 0x0800.  So I changed the code to 0x0200 and it still did not work.  Change it to 0x0100 and it still does not work.  For some reason I can't place the lookup table code where I want instead If I let the linker place the code block everything works fine.

So in general a rule of thumb is when using relocatable mode assembler on the PIC try and let the linker do it's job and only specify the reset and interrupt vector addresses.  My goal with placing the code block myself was to avoid rolling over the single page boundary due to the linker placing it in a bad spot.  Turns out this was not the case anyway.

If anyone has any info on why placing the code blocks at 0x0200 and 0x0100 did not work please feel to chime in because the data sheet states I have from 0x0000 - 0x07FF

EDIT:

My mistake turns out by using PCL there is a boundary of 0x0100 that it can access without messing around with PCLATH.  So by ensuring the lookup table is at 0x0080 I can make sure the linker does not accidentally push it over said boundary and the code will continue to work fine.
« Last Edit: May 25, 2013, 09:28:38 pm by blewisjr »
 

Offline Mr Smiley

  • Frequent Contributor
  • **
  • Posts: 324
  • Country: gb
Re: moving alarm clock to PIC but display won't update
« Reply #4 on: May 26, 2013, 01:34:05 am »
Hi,

Lookup tables, as you know must be within 00-FF, if you have a lookup table starting at 0x10 and your lookup offset is ADDLW, 0xFF you will find you jump to address 0x00. This is because any overflow from PCL is not carried over to PCLATH. For extended tables you have to set PCLATH yourself.

By default PCLATH is set to 0

So for a simple table like yours place it before the start of the main program.

You can specify where in memory you place it, starting, as you wanted on a 0x100 boundary, but calling it will result in your offset jump being set to 0x00 for digit0 (basically resetting your pic ) and 0x01 for digit1 etc, not the expected 0x100 or 0x101

The simple solution to this  is to do the following

movlw  HIGH Digit_tbl
movwf  PCLATH

the 'HIGH' puts the high address of the lookup table into w, using 'LOW' puts the low address of the lookup table into w. The Addwf puts the offset into PCL and you have already set PCLATH to 0x100 so your addwf jump will now go to 0x100 for digit0 and 0x101 for digit1

Tables are a nightmare if there bigger than 0xff or cross a boundary, for that you have to use your own 16bit calculated jumps

Sorry i missed that.

Mr Smiley  :)
There is enough on this planet to sustain mans needs. There will never be enough on this planet to sustain mans greed.
 

Offline blewisjr

  • Frequent Contributor
  • **
  • Posts: 301
Re: moving alarm clock to PIC but display won't update
« Reply #5 on: May 26, 2013, 09:51:17 am »
Hi,

Lookup tables, as you know must be within 00-FF, if you have a lookup table starting at 0x10 and your lookup offset is ADDLW, 0xFF you will find you jump to address 0x00. This is because any overflow from PCL is not carried over to PCLATH. For extended tables you have to set PCLATH yourself.

By default PCLATH is set to 0

So for a simple table like yours place it before the start of the main program.

You can specify where in memory you place it, starting, as you wanted on a 0x100 boundary, but calling it will result in your offset jump being set to 0x00 for digit0 (basically resetting your pic ) and 0x01 for digit1 etc, not the expected 0x100 or 0x101

The simple solution to this  is to do the following

movlw  HIGH Digit_tbl
movwf  PCLATH

the 'HIGH' puts the high address of the lookup table into w, using 'LOW' puts the low address of the lookup table into w. The Addwf puts the offset into PCL and you have already set PCLATH to 0x100 so your addwf jump will now go to 0x100 for digit0 and 0x101 for digit1

Tables are a nightmare if there bigger than 0xff or cross a boundary, for that you have to use your own 16bit calculated jumps

Sorry i missed that.

Mr Smiley  :)

Oh it is a non issue just me not really paying attention there.  It actually turns out on the enhanced-mid range pic there is actually a instruction to do this called brw.  Basically you place a brw where you would normally do your addwf PCL, f and it adds W to the program counter without the PCL page limitation.  So if I place it at 0x0100 and use brw everything works.  Instead at the moment I have it at 0x0080.  Ultimately I would like to place it after the interrupt vector but to place it there in an absolute way is risky as I don't want the vector to run into the table.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf