The PIC16F1937 can be a bit of a pain to transition to from the PIC16F877. Lack of online discussion for this relatively new microcontroller is an especial annoyance. Therefore, I have decided to share a few solutions I have discovered to non-trivial problems in my short time working with the 1937. Hopefully these are of some use to someone.

1. Using internal clocks (and clocking to 32MHz):

In the first config word, set the FOSC bit to INTOSC (put _FOSC_INTOSC instead of _FOSC_HT or something like that). The internal oscillator defaults to .5MHz medium freq oscillator (there are three internal oscillators). This is probably way too slow, but this can be changed. Also, the SCS<1:0> bits of the OSCCON register (Bank 1) must be set to 00 for the internal oscillator to be selected.

For some strange and undocumented reason, writing bytes to the OSCCON register doesn't work, so use explicit bcf and bsf instructions (e.g. bsf OSCCON, SCS0).

The OSCCON register has four bits called IRCF<3:0>. Set the first bit to a 1 for the high freq (HF) oscillator. The frequency of the HF oscillator can be set with the IRCF<2:0> bits by the formula: f = 0.125MHz*(2^IRCF<2:0>). That is, for IRCF<2:0> = 000, f = 0.125MHz, and for IRCF<2:0> = 111, f = 16MHz, etc.

To get to 32 MHz, use IRCF<2:0> = 110 (f = 8MHz) and set the SPLLEN bit of the OSCCON register. The SPLLEN bit activates a 4x PLL module (whatever that is), which quadruples your clock rate. You cannot get to 64MHz like this, however.

2. Timer0 and prescaler:

If you want to start and run the timer in timer mode (as opposed to counter mode), you have to jump through a few hoops. 

First, you have to select clock source and rising/falling edge increment. For internal clocks, clear the TMR0CS bit of the OPTION_REG register (Bank 1). For external clocks, set the TMR0CS bit. The TMR0SE bit controls whether the timer increments on rise or fall of the clock signal, you probably aren't worried about this in timer mode, so leave it at its default.

To use the prescaler (slows down the timer by powers of 2 when enabled), clear the PSA bit. The next three bits (PS<2:0>) control the prescaler ratio by the formula p = 2^(PS<2:0> + 1). That is, for PS<2:0> = 000, the ratio is 2, and for PS<2:0> = 111, the ratio is 256. When setting these bits, use explicit bsf and bcf instructions instead of writing a byte to OPTION_REG, or it will not work.

The timer does not have an activation bit; it begins when you write a value to the TMR0 register (Bank 0). The timer counts UP from its value, and generates interrupts when it overflows (rolls over from 255 to 0). To use these interrupts, set the TMR0IE bit of the INTCON register. The flag TMR0IF is also located in the INTCON register.

3. Using indirect addressing:

The linearly accessible general-purpose RAM feature of the PIC16F1937 is really nice (be sure to read about it if you haven't already), but indirect addressing is annoying to troubleshoot. To make your life easier, stay away from the MOVIW, MOVWI, and ADDFSR instructions, as they can behave unpredictably.

4. Computed jumps:

The PIC16F1937 has a neat workaround that allows you to do computer jumps without worrying about paging. That means no paging issues, ever. 

The naive way to do computed jumps is to call addwf PCL, f, with the jump value in W. This fails when the table you are jumping from is not completely addressable with changing PCLATH.

You can avoid this forever by using stack manipulation. Define a subroutine as follows:

CJUMP:

movlb 0x1F ; (Bank 31)

addwf TOSL, f 

btfsc STATUS, C

incf TOSH, f

return

When you call this subroutine, the PCLATH:PCL register pair plus one is stored on the top of the stack, because normally you would want return to send you back to the next instruction after call CJUMP. This subroutine just adds W to the PCLATH:PCL register pair so you return to a place W + 1 instructions after the call CJUMP instruction.

5. Bit shifting:

My first note about bit shifting is that you can't shift the W register. You can use a temporary register to store the value of W, and then you can shift that temporary register into W.

My second note is that you can easily use bit shifting for computed jumps. For an example, look at the following code:

SETPORTDBIT:

movwf TMP

lslf TMP, W

call CJUMP ;(see previous example code)

bsf PORTD, 0

return

bsf PORTD, 1

return

...

bsf PORTD, 7

return

The lslf instruction serves to mutiply the jump value by 2. Multiple lslf instructions can obviously jump greater distances, but lslf can only be used to multiple by powers of two. Use nop instructions to increase your table block size if it needs to be rounded up to a power of 2.

Views: 431

Reply to This

© 2024   Created by PML.   Powered by

Badges  |  Report an Issue  |  Terms of Service