moving alarm clock to PIC but display won't update - Page 1
Forum section: electronics / general

author: blewisjr
author_rank: Frequent Contributor
timestamp: May 25, 2013, 05:21:19 pm
content: Hello AgainSo 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..3Here 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:#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 radixradix dec; =============================================================================; Code Vectors; =============================================================================; executed on chip resetReset_Vec: code 0x0000goto Start ; move PC to Start section in Program code block; executed on interruptInterrupt_Vec: code 0x0004btfsc INTCON, 5 ; check if timer0 overfow interrupt is enabledbra chk_ovf_flag ; goto timer0 overflow flag checkretfie ; not an interrupt we are interested in exitchk_ovf_flag:btfsc INTCON, 2 ; check if interrupt is a timer overflow skip otherwisegoto TMR0_Ovf ; execute timer overflow isrretfie ; not an interrupt we are interested in exit; =============================================================================; Interrupt Service Code Block; =============================================================================Interrupt_Service: code; Timer0 overflow interrupt service routineTMR0_Ovf:bcf INTCON, 2 ; clear timer0 overflow interrupt flagbanksel LATB ; bank2bsf LATB, 4btfsc LATB, 0 ; if digit 1 is set it was just updatedbra update_dig2 ; update digit 2btfsc LATB, 1 ; if digit 2 is set it was just updatedbra update_dig3 ; update digit 3btfsc LATB, 2 ; if digit 3 is set it was just updatedbra update_dig4 ; update digit 4btfsc LATB, 3 ; if digit 4 is set it was just updatedbra update_dig1 ; update digit 1bra 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 1bsf LATB, 0 ; set RB0 so we can update digit 1movlw 1 ; grab digit 1 from tablecall Digit_tblmovwf LATA ; in bank2 load digit to displaybcf LATB, 4retfieupdate_dig2:bcf LATB, 0 ; in bank2 clear RB0 so we can update digit 2bsf LATB, 1 ; set RB1 so we can update digit 2movlw 2 ; grab digit 2 from tablecall Digit_tblmovwf LATA ; in bank2 load digit to displaybcf LATB, 4retfieupdate_dig3:bcf LATB, 1 ; in bank2 clear RB1 so we can update digit 3bsf LATB, 2 ; set RB2 so we can update digit 3movlw 0 ; grab digit 0 from tablecall Digit_tblmovwf LATA ; in bank2 load digit to displaybcf LATB, 4retfieupdate_dig4:bcf LATB, 2 ; in bank2 clear RB2 so we can update digit 4bsf LATB, 3 ; set RB3 so we can update digit 4movlw 0 ; grab digit 0 from tablecall Digit_tblmovwf LATA ; in bank2 load digit to displaybcf LATB, 4retfie; =============================================================================; Program Code Block; =============================================================================Program: code; performs program setup logicStart: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 settingsbanksel OSCCON ; bank1movwf OSCCONclrf TRISA ; in bank1 set PORTA as outputclrf TRISB ; in bank1 set PORTB as outputmovlw 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 prescalemovwf OPTION_REGmovlw b'10100000' ; enable global interrupt and timer0 overflow interrupt; 1------- global interrupt enable; -0------; --1----- timer0 overflow interrupt enable; ---0----; ----0---; -----000 interrupt flagsmovwf INTCONbanksel TMR0 ; bank0clrf TMR0 ; clear timerbanksel LATA ; bank2clrf LATA ; make sure PORTA data latch is clearclrf LATB ; make sure PORTB data latch is clear; main program looploop: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 wregDigit_tbl:addwf PCL, fretlw b'00111111' ; digit 0retlw b'00000110' ; digit 1retlw b'01011011' ; digit 2retlw b'01001111' ; digit 3retlw b'01100110' ; digit 4retlw b'01101101' ; digit 5retlw b'01111101' ; digit 6retlw b'00000111' ; digit 7retlw b'01111111' ; digit 8retlw b'01101111' ; digit 9end ; end of code

author: Mr Smiley
author_rank: Frequent Contributor
timestamp: May 25, 2013, 06:28:43 pm
content: 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 awayi.e.bsf sLATBmovf sLATB,wmovwf 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

author: blewisjr
author_rank: Frequent Contributor
timestamp: May 25, 2013, 06:59:21 pm
content: 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...

author: blewisjr
author_rank: Frequent Contributor
timestamp: May 25, 2013, 09:08:42 pm
content: 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 goodSo 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 - 0x07FFEDIT: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.

author: Mr Smiley
author_rank: Frequent Contributor
timestamp: May 26, 2013, 01:34:05 am
content: 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 0So 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 0x101The simple solution to this is to do the followingmovlw HIGH Digit_tblmovwf PCLATHthe '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 digit1Tables are a nightmare if there bigger than 0xff or cross a boundary, for that you have to use your own 16bit calculated jumpsSorry i missed that.Mr Smiley

author: blewisjr
author_rank: Frequent Contributor
timestamp: May 26, 2013, 09:51:17 am
content: Quote from: Mr Smiley on May 26, 2013, 01:34:05 amOh 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.