The case of the missing banksel directive

The case of the missing banksel directive

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...

 

 

Posted by David Meiklejohn

Products related to this article

0 Comments To "The case of the missing banksel directive"

Write a comment

Your Name:


Enter the code in the box below:

Your Comment:
Note: HTML is not translated!
Powered By OpenCart
Gooligum Electronics © 2017