Recently I've been writing a "CCP: Capture and Compare" assembly language tutorial for enhanced mid-range PICs.
It's based on lesson 17 in the mid-range PIC assembly language series, and should be straightforward to update for enhanced mid-range PICs because the capture and compare functionality is pretty much identical to that in the older mid-range PICs. Sure, the 16F684 used mid-range lesson has only one ECCP module, compared with the 16F1824's two ECCP and two CCP modules, but the capture and compare modes in all of those "CCP modules work the same way, controlled by the same bits in the same registers and affect the same interrupt flags in the same way.
That means that "capture mode" code written for the 16F684 shoudl be pretty easy to migrate to the 16F1824 - sure, some of the initialisation code (ports, timer, oscillator setup) needs updating, but the main loop code involving the CCP registers shouldn't need to be change. In theory...
So I was a bit bewildered when this fragment of code, part of a known-working capture mode example from the 16F1824, didn't work:
banksel PIR1
w_rise btfss PIR1,CCP1IF ; wait for CCP1 interrupt flag to go high
goto w_rise
bcf PIR1,CCP1IF
; save capture time at pulse start
movf CCPR1L,w
movwf ccpr1_s
movf CCPR1H,w
movwf ccpr1_s+1
What could possibly be wrong with it? Such a short, simple piece of code. I stared and stared. I set up the MPLAB simulator, creating a simulated stimulus signal to capture and single stepping the code, looking carefully at register contents as I went - I spent more than an hour trying to figure out why this code, that worked fine on the 16F684, failed with the supposedly identical CCP capture mode on the 16F1824.
And then I saw what was happening.
It's because I'd been sloppy when writing the original program. On the 16F684, the PIR1 register just happens to be in the bank as the CCP registers. That's not guaranteed to be true on other PICs. Sure, you can reasonably expect that the CCPR1L and CCRP1H registers will always be together in the same bank, but it was just a lucky coincidence that the PIR1 register is also in the same bank on the 16F684. It wasn't good coding - just luck.
The right thing to do would have been to add a "banksel" directive before accessing the CCP registers. Even though, strictly speaking, it isn't necessary on the 16F684, I should have done it anyway, because it makes the code more portable.
So I added the missing "banksel":
banksel PIR1
w_rise btfss PIR1,CCP1IF ; wait for CCP1 interrupt flag to go high
goto w_rise
bcf PIR1,CCP1IF
; save capture time at pulse start
banksel CCPR1L
movf CCPR1L,w
movwf ccpr1_s
movf CCPR1H,w
movwf ccpr1_s+1
And it worked! Yaay!
And so obvious in hindsight...
Moral of the story - do what I wrote in my own PIC tutorials, and include banksel directives! It will make your life much easier if you ever move your program, or even just fragments of code like this, to another PIC in future...





Enter the code in the box below: