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.

Suspect a defect 16F877A

Status
Not open for further replies.

hantto

Member
Hello!

I've been programing a 877A, and it throws me errors (like printing the LCD full with only the fist letter from a table). It seems like it doesn't like to modify the program counter. I noticed that if I moved tables (yes I have taken into account the 256 word boundary) or other subroutines around a little in the code, they would magically start working, or stop working.

I see no error in my code, and I have been looking at for some time now. Then I discovered the read-modify-write way the PIC uses. I looked through my code and inserted delays in places where there might have been some issues. That didn't help. I have used most of the routines in this code before, so it's confirmed that they work.

Then I wrote this little program to test a routine on another page:
Code:
		LIST      P=16F877A, F=INHX8M
		include "P16F877A.inc"
 		__CONFIG 0x2942

		ERRORLEVEL	0,	-302	;Suppress bank selection messages
		ERRORLEVEL	0,	-207	;Suppress "label found after column 1"

#define	Sup5V		PortA,	4	;5v supply controll
#define	ButBL		PortC,	1	;Port C1 = Button backlight
#define	LCDBL		PortC,	2	;Port C2 = LCD backlight


		cblock	0x20
				delay			;Delay
				delaya		;Delay
				delayb		;Delay
		endc


		org		0x00			;Program memory Page 0
		clrf		Status		;For bootloader compatibility
		clrf		PCLath
		goto		Init

Init		clrf		PortA
		clrf		PortC
		bsf		Status,	rp0	;Bank 1
		movlw		b'11101011'		;PortA
		movwf		TrisA
		movlw		b'10000001'		;PortC
		movwf		TrisC
		bcf		Status,	rp0	;Bank 0

Main		bsf		LCDBL			;LCD backlight ON
		call		Delay250

		bsf		pclath,	4	;Select page 2
		bcf		pclath,	3
		call		Flash_Buttons

		bcf		LCDBL			;LCD backlight OFF
		call		Delay250

		bsf		pclath,	4	;Select page 2
		bcf		pclath,	3
		call		Flash_Buttons

		goto		Main

Delay250	movlw	d'250'			;delay 250mS
		movwf	delay
d1		movlw	0xE7
		movwf	delaya
		movlw	0x04
		movwf	delayb
Delay_0		decfsz	delaya, f
		goto	$+2
		decfsz	delayb, f
		goto	Delay_0
		decfsz	delay	,f
		goto	d1
		return


		org		0x1000		;Program memory Page 2

Flash_Buttons		btfss	LCDBL		;test if LCD backlight on
		bcf		ButBL
		btfsc		LCDBL
		bsf		ButBL
		return

		end

And it didn't work, I looked at the example in the datasheet. This is so simple it should work?

So I'm reaching the conclusion that the PIC must be defect.

Yes, I ran it off a regulated 5v supply (7805) with adequate decoupling (a 10µF and a 100nF).

Or am I missing something? (again)
 
You appear to be setting page 2, but never setting back to page 0?. You also don't appear to be disabling the analogue inputs?.

The chances of a PIC being faulty in such a way are so low as to not bother considering!.
 
Nigel Goodwin said:
You appear to be setting page 2, but never setting back to page 0?. You also don't appear to be disabling the analogue inputs?.

The chances of a PIC being faulty in such a way are so low as to not bother considering!.

I had set up the A2D in my original code, still no difference.

And about setting to page 0, the stack is 13-bit long, there is no need. The datasheet says:
The guy who wrote the datasheet said:
If a return from a CALL instruction
(or interrupt) is executed, the entire 13-bit PC is popped
off the stack. Therefore, manipulation of the
PCLATH<4:3> bits is not required for the RETURN
instructions (which POPs the address from the stack).

And the truth is, in my original code I didn't need to change program pages. I just wrote that program to test my hypothesis.

I had a table called TEXT, it didn't work with it. I made a copy of the table just under the original table, and renamed the original table to TEXTD. And remarkably, it worked. And those tables were located directly under "goto Init" and were 18 words long.

But what could be wrong? I agree it's very unlikely that the PIC is broken somehow.
 
Code:
Main      bsf      LCDBL         ;LCD backlight ON
      call      Delay250

      bsf      pclath,   4   ;Select page 2
      bcf      pclath,   3
      call      Flash_Buttons

      bcf      LCDBL         ;LCD backlight OFF
      call      Delay250    <<<<<<   Is this routine in page 2 also ???

      bsf      pclath,   4   ;Select page 2
      bcf      pclath,   3
      call      Flash_Buttons

      goto      Main

You are calling Delay250 when you are in page 2, but are you sure Delay250 is located in page 2?
 
hantto said:
And about setting to page 0, the stack is 13-bit long, there is no need. The datasheet says:
The guy who wrote the datasheet said:
If a return from a CALL instruction
(or interrupt) is executed, the entire 13-bit PC is popped
off the stack. Therefore, manipulation of the
PCLATH<4:3> bits is not required for the RETURN
instructions (which POPs the address from the stack).

As I understand it, that means you don't need to alter PCLATH before you return - but when it gets back from the return PCLATH is still set to page 2, and NOT page 0 - so you need to reset PCLATH after you've returned.

As eblc1388 says, you're calling a subroutine in page 0 while you're still set to page 2 - a sure method for a disaster!.
 
Nigel Goodwin said:
hantto said:
And about setting to page 0, the stack is 13-bit long, there is no need. The datasheet says:
The guy who wrote the datasheet said:
If a return from a CALL instruction
(or interrupt) is executed, the entire 13-bit PC is popped
off the stack. Therefore, manipulation of the
PCLATH<4:3> bits is not required for the RETURN
instructions (which POPs the address from the stack).

As I understand it, that means you don't need to alter PCLATH before you return - but when it gets back from the return PCLATH is still set to page 2, and NOT page 0 - so you need to reset PCLATH after you've returned.

As eblc1388 says, you're calling a subroutine in page 0 while you're still set to page 2 - a sure method for a disaster!.

Oh, right :D one more thing learned.

But the problem still remains. How come that my tables do not always work. I'm using a table to round off a decimal value for a DS1631 thermometer too. And the weird thing is that is I run the code without the thermometer the pic crashes when it should output the decimal value. When I have the thermometer plugged in it works. It should have no effect on the pic if the thermometer is plugged in or not, the returned value will only be wrong (al ones, as it is a I²C device).
 
I would suggest that the I2C routine is probably failing?, I imagine it's waiting for the ACK back from the I2C bus? - it's NOT a good idea to disconnect things from I2C!.

If you're having problems with tables, it's almost certainly due to 256 byte paging problems!.
 
Nigel Goodwin said:
I would suggest that the I2C routine is probably failing?, I imagine it's waiting for the ACK back from the I2C bus? - it's NOT a good idea to disconnect things from I2C!.

If you're having problems with tables, it's almost certainly due to 256 byte paging problems!.
isn't I2C hot swappable?, because, if no device is connected the SDA will be high , so that a NACK will result.?
 
And the truth is, in my original code I didn't need to change program pages. I just wrote that program to test my hypothesis.

If this test program works and your original program doesn't then the problem is likely there. It is probably just a small bug that you overlooked. However, with inivisible code, we cannot help you there.

If a return from a CALL instruction (or interrupt) is executed, the entire 13-bit PC is popped off the stack.

Only the program counter (PC) is restored but PCLATH is still pointing to page 2. PCLATH<4:3> would be transferred back to the PC on the next GOTO or CALL.
 
motion said:
And the truth is, in my original code I didn't need to change program pages. I just wrote that program to test my hypothesis.

If this test program works and your original program doesn't then the problem is likely there. It is probably just a small bug that you overlooked. However, with inivisible code, we cannot help you there.

Yes, it worked after the modification.

motion said:
If a return from a CALL instruction (or interrupt) is executed, the entire 13-bit PC is popped off the stack.

Only the program counter (PC) is restored but PCLATH is still pointing to page 2. PCLATH<4:3> would be transferred back to the PC on the next GOTO or CALL.

Nigel said:
I would suggest that the I2C routine is probably failing?, I imagine it's waiting for the ACK back from the I2C bus? - it's NOT a good idea to disconnect things from I2C!.

No, the code doesn't wait for the 'right' input, it just takes what's there and contiunes.

Your both's help is much appreciated.

Here is the whole code. It still crashes if I remove a temperature sensor. And when it gets to the Text printing part, it just prints the LCD full with Ss.
 

Attachments

  • saab_mainpic.txt
    35.1 KB · Views: 188
akg said:
isn't I2C hot swappable?, because, if no device is connected the SDA will be high , so that a NACK will result.?

I2C is designed for interconnections between chips on the same board, it's designed purely to make PCB design easier - why on earth would it be 'hot swappable', it doesn't even need to be 'cold swappable'.

As to the effects of a faulty chip (or a removed one in your case), it depends completely on the software you use - certainly unless your I2C routines are specifically written to work around a missing chip, then it's unlikely to work!.
 
Nigel Goodwin said:
As to the effects of a faulty chip (or a removed one in your case), it depends completely on the software you use - certainly unless your I2C routines are specifically written to work around a missing chip, then it's unlikely to work!.

But still, the PIC shouldn't crash there if there is no chip.
 
hantto said:
Nigel Goodwin said:
As to the effects of a faulty chip (or a removed one in your case), it depends completely on the software you use - certainly unless your I2C routines are specifically written to work around a missing chip, then it's unlikely to work!.

But still, the PIC shouldn't crash there if there is no chip.

I would have thought the chances are very good it will hang, waiting for the ACK and readings back from the chip - as I said, it depends completely on how the I2C routines are written - and I2C doesn't expect chips to be removed!.
 
Nigel Goodwin said:
hantto said:
Nigel Goodwin said:
As to the effects of a faulty chip (or a removed one in your case), it depends completely on the software you use - certainly unless your I2C routines are specifically written to work around a missing chip, then it's unlikely to work!.

But still, the PIC shouldn't crash there if there is no chip.

I would have thought the chances are very good it will hang, waiting for the ACK and readings back from the chip - as I said, it depends completely on how the I2C routines are written - and I2C doesn't expect chips to be removed!.

I've written the routines myself, they do not wait for anything, it outputs the clock, reads the state of SDA and continues with outputing the next clock. So if there isn't a chip on the I²C, the PIC will not notice it, I could be using the I²C lines to flash leds (but too fast to see ofcourse :lol:). So if there is no chip it will always read '1' because of the pull-up resistor. Hm, that gave me an idea, I will increase the I²C delay and put a led on the SCL and SDA line and see what it really is doing.

And I'm not going to hotswap the I²C devices. I merely removed one before powering up the PIC and noticed that the PIC hangs there.
 
Ah! I have solved the mystery behind the temperature decimal :lol:

I had used andfw b'00001111' instead of andlw b'00001111', so it had anded the TMR1H with W and stored that back in TMR1H and left W untouched instead of anding F with W :D so if it was higher than 15 it would had jumped farther down, past the table.

Now only the text mystery remains...
 
so if it was higher than 15 it would had jumped farther down, past the table.

Using the instruction "addwf PCL,f" without any safeguard like limiting the value of W to less than 16, could cause very unpredictable results should any of the assumed values be off. You could add the ff. code just for protection:

Code:
        andlw b'00001111'
        addwf PCL,f
        retlw 'D'
        retlw 'a'

If after adding the modification somewhat fixes the problem, then the calling routine obviously loads W with a value longer than the table.

In addition, there are ways to use packed ascii strings instead of a series of retlw's.

e.g.

Code:
        DA "Date: ",0

You can read the program memory space via the EEADR and EEADRH registers so you can avoid using the dangerous computed GOTO for storing strings. This will also save program space by halving the memory used for strings.
 
motion said:
In addition, there are ways to use packed ascii strings instead of a series of retlw's.

e.g.

Code:
        DA "Date: ",0

You can read the program memory space via the EEADR and EEADRH registers so you can avoid using the dangerous computed GOTO for storing strings. This will also save program space by halving the memory used for strings.
I don't understand this, please elaborate.
 
I don't understand this, please elaborate.

Each instruction step on the PIC16F877A uses 14-bits. Therefore it is possible to store two 7-bit ascii characters instead of one for every instruction step. The "DA" directive does exactly this. See the MPASM user's guide for a detailed explanation.

The trick is retrieving, unpacking and displaying the string. Modifying the thread starter's code as an example:

Code:
Text_OUT:
         BANKSEL  EEADR           ; BANK 2
;         
         MOVLW    LOW Text
         MOVWF    EEADR
;
         MOVLW    HIGH Text
         MOVWF    EEADRH
STRING_OUT:
         BSF      STATUS,RP0      ; BANK2 -> BANK3
         BSF      EECON1,EEPGD    ; Point to program memory
         BSF      EECON1,RD       ; GO Read!
         NOP
         NOP
         BCF      STATUS,RP0      ; BANK3 -> BANK2
         MOVF     EEDATH,W
         BCF      STATUS,RP1      ; BANK2 -> BANK0
         MOVWF    TEMP2
         BSF      STATUS,RP1      ; BANK0 -> BANK2
         MOVF     EEDATA,W
         BCF      STATUS,RP1      ; BANK2 -> BANK0
         MOVWF    TEMP1
;
         RLF      TEMP1,W         ; Unpack - shift bit7 to carry 
         RLF      TEMP2,F         ; shift carry into bit0
;
         MOVLW    7Fh
         ANDWF    TEMP2,W
         SKPNZ
         RETURN
;
         CALL     LCD_Char
;
         MOVLW    7Fh
         ANDWF    TEMP1,W
         SKPNZ
         RETURN
;
         CALL     LCD_Char
;
         BSF      STATUS,RP1      ; BANK0 -> BANK2
         INCF     EEADR,F           ; Increment pointer to the next address
;
         GOTO     STRING_OUT
;
Text     DA       "SloboSaabSystems",0
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top