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?