Archive for May, 2009

Microchip PIC16F883 Anomolies And Other Odd Behaviours

Saturday, May 16th, 2009

Recently we completed a development project which made use of the Microchip Technologies PIC16F883 microcontroller. This is a newer style PIC flash micro that includes a low voltage flash programming mode and some other enhancements to its power management and oscillator blocks. We like PIC micros because they are inexpensive, reasonably power thrifty, and normally very easy to use. We stepped on a couple of land mines with the 883 however. The first had to do with that low voltage programming mode. The documentation for this part states that the standard HV programming mode will override the low voltage programming mode. This simply isn’t true.  The documentation is confusing because it does not show the PGM pin on the standard connection diagram for the in-system programming interface. The parts are shipped from the factory with the internal configuration bit for low voltage programming enabled. Because of this, inserting the parts in a programming socket you’ve been using for something like a PIC16F685, for example, will FAIL unless you ground the PGM pin. After turning off the low voltage programming bit, the PGM pin can then be used as an ordinary GPIO pin and your HV programming issues will go away.  It’s also necessary to add a pull down resistor to the PGM pin on the board you install the 16F883 in to prevent T=0 problems with programming at manufacturing time.  The Microchip documentation is not at all clear about this so be careful.

Another stumbling block was sleep/wake. Since the 16F883 is code compatible with other parts in this series such as the 16F685, and the data sheet listed the same example code as for the 16F685, we had to struggle a bit with the 16F883 when it refused to wake up after entering sleep mode.  We never did get a satisfactory answer back from the Microchip forum about this so are publishing this here for your enjoyment and perusal.  Here is the sleep entry code for the 16F883, our first attempt:

MAIN_sleep_entry
	BANKSEL	PORTA
	clrf	PORTA
	BANKSEL TRISC
	clrf	TRISC	    ;all to outputs
	movlw	H'20'	    ;only enable bit 5
	movwf	IOCB
	bcf	PIE1,TMR1IE ;stop timer 1 ints while here in this bank...
	bcf	PIR1,TMR1IF ;case we come here from interrupt routine...
	bcf	INTCON,T0IE ;make sure timer 0 can't hit us either...
	BANKSEL	T2CON
	bcf	T2CON,TMR2ON ;stop timer
	BANKSEL PORTA
	clrf	PORTC
	clrf	PORTB
	movf	PORTB,W	    ;dummy read to clear state change ff's
	movf	PORTB,W		;again for good measure...
	bcf	INTCON,RBIF
	bsf	INTCON,RBIE ;arm wake up detection
	bsf	INTCON,GIE
	clrwdt
	BANKSEL WDTCON
	bcf	WDTCON,SWDTEN
	bcf	INTCON,T0IF
	bcf	INTCON,INTF
	bcf	INTCON,RBIF
	nop
	sleep

This is the same code sequence previously used for the 16F685, but for some reason the 16F883 would never wake up.  After trying several things, without success, we added this code right before sleep entry:

	.....
        bcf	INTCON,RBIF
	btfsc	INTCON,RBIF
	goto	$2
	nop
	sleep

Since we still went to sleep, obviously the RBIF flag was getting cleared, later verified by stepping through with the ICD2 debugger.  But it still looked for all the world like the RBIF flag was still setting prior to sleep entry.  So we tried another hack.  At the dispatcher at the top of the interrupt service routine we added a handler for the wake interrupt:

	...
	btfsc	INTCON,RBIF
	goto	SLEEP_WAKE
	goto	IRQ_DONE	;wild interrupts are ignored

SLEEP_WAKE
	bcf	INTCON,RBIF	;this might be causing problems
	goto	IRQ_DONE	;

Sure enough, after handling the RBIF flag inside interrupt context, the wakeup circuitry was armed and we could now wake the 16F883.  So what’s going on here?  The RBIF flag can obviously be cleared from normal context but it won’t stay  cleared unless it’s cleared inside interrupt context.  This isn’t the way the 16F685 behaves and sounds like we have the makings of a nice little hardware bug here.  Comments?