Learning to program the PIC16LF1823

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
Doesn't make any difference. Current will still flow from the +6V battery through R1 into the upper ESD protection diode of the PIC's ADC input.

If you want to prevent that, you need a high-side switch between the battery and your voltage divider, not a low-side switch between the divider and ground.
Ah! ... so a pFet would be a better choice then? ... I have a few DMP2066LSN with me that I could use. Thanks for the suggestion.
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
Question:

I'm currently using MPLAB X IDE v4.20 for assembly and programming my devices. Is there a way to visually compare the memory contents of the device vs the program?

I know there's a way to download the device's memory to a file. But it's saved in a format that is not easy to compare against the compiled (assembled?) version of the original program.
 

peterdeco

Joined Oct 8, 2019
484
If I understand you properly, in MPLAB I load the file, insert the PIC and hit VERIFY, as long as it's not code protected it should pass or fail.
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
If I understand you properly, in MPLAB I load the file, insert the PIC and hit VERIFY, as long as it's not code protected it should pass or fail.
My question is, that procedure would verify the device's contents against what?
Will it compare it to the currently loaded program, or would it simply verify that whatever is in it is uncorrupted?
 

peterdeco

Joined Oct 8, 2019
484
Just tried it. 2 identical PICs programmed with 2 different programs. Load the proper program and the proper chip verifies. Switch the program or PIC so they don't match and I get a page full of errors.
 

jpanhalt

Joined Jan 18, 2008
11,087
That is what I would expect. Verify compares the loaded code with what was expected to be loaded. Check empty (or words to the effect) checks whether the PIC is empty. I always erase before loading/programming and then verify.
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
After a couple of days of studying the chip (PIC16LF1823) I was finally able to make its UART work and link it with my computer. There were quite a few registers involved to accomplish this small, but important feat.

I needed the UART to work at 115200,8,N,1 and the challenge was the speed. The datasheet mentions that to accomplish that baudrate using the chip's internal clock, the chip needs to run at 32MHz. But even at that speed, the most approximate generated baud rate is 117,647 which yields an error of approximately 2% ... a little to large for my taste.

So what I did is play a bit with the OSCTUNE register, which allows the fine tuning of the internal oscillator. And after some testing and scoping, I found out that it allows the user to adjust the frequency by exactly ±3%

1590715465891.png

And after some calculations I accomplished a baud rate of 115256.2 which yields an error of only 0.049%. Roughly 40 times more accurate than without adjusting OSCTUNE. Not too shabby. :cool:

Anyway ... what I found annoying was all the dancing around with the memory banks, switching from one to another as I wrote the routines... a little inefficient from my point view. I'm just not used to that. So what I did in the end is I forced all of the routines in the program to switch to memory bank 0 just before returning.

Question, is this good practice? Is there a standard way to handle that memory bank back and forth and tug of war?
 
Last edited:

jpanhalt

Joined Jan 18, 2008
11,087
Question, is this good practice? Is there a standard way to handle that memory bank back and forth and tug of war?
Short answer: "That depends." :)

Wrestling with banks can be a pain. I follow some rules, but all rules are subject to violation. Sometimes when writing a lot of code, you get in the groove and doing housekeeping can be detracting. I then go back and cleans things up.

Some rules:
1) I keep tract of the Bank for everything that is not trivial. I would write a macro that did that for everything, but I don't know how to do that. MPLab is very good at keeping the columns neat (unlike this Forum:( ) , and I put Bank at a fixed number of spaces (column 76 of a typically 80 column page).
2) I try to write routines that accept any bank from a call. That is, the first step is a "movlb 0" or whatever is needed.
3) For returns, I do one of two things:
(a) I return in Bank0​
(b) I return in whatever Bank is convenient. In that case, I always have an "Exit" routine that returns in Bank0. For example, if the routine returns in Bank4, the exit routine would fix other things and end with something like "movlb 0, return."​
4) I commonly call a routine with an offset. That can eliminate a lot of code, e.g., Call "PutCMD+4," eliminates steps to set the Bank and other things that are already set.

In general, those twists save significant time only when doing a lot of repetitive things, like writing to a GLCD. If it is a much less frequently used routine, then I enter and return in Bank0.

Finally, the way you use RAM can save steps. There are 3 types in that chip, as you know: General Purpose (GP), Common, and Linear. Linear RAM is just a remapping of GP RAM. It spares Common RAM and uses for the most part indirect addressing (FSR0H/L and FSR1H/L). Banking is not involved. Common RAM can also be accessed from any bank, but you only have 16 bytes of it.

For GP RAM, I generally start with Bank0 as it is convenient but not always efficient. Since I track Banks, it is often more efficient to put some registers in Banks other than Bank0. Caution: If you are also using Linear RAM, you need to check a map of where the RAM you want to use is.

Here's some rough code to illustrate:

SPI Commands:
Code:
PutCMD
     movlb     2              ;                                            |B2
     bcf       LCD_CS         ;                                            |B2
     bcf       LCD_A0         ;CMD/DAT bit, L=CMD                          |B2
     movlb     4              ;PutCMD+3                                    |B4
     movwf     SSP1BUF        ;PutCMD+4                                    |B4
     btfss     SSP1STAT,BF    ;                                            |B4
     bra       $-1            ;                                            |B4
     return                   ;                                            |B4
ExitCMD
     movlb     2              ;                                            |B2
     bsf       LCD_A0         ;                                            |B2
     bsf       LCD_CS         ;                                            |B2
     movlb     0              ;                                            |B0
     return                   ;                                            |B0
PutDat
     movlb     2              ;                                            |B2
     bcf       LCD_CS         ;A0 idles high                               |B2
     movlb     4              ;PutDat+2                                    |B4
     movwf     SSP1BUF        ;PutDat+3                                    |B4
     btfss     SSP1STAT,BF    ;                                            |B4
     bra       $-1            ;                                            |B4
     return                   ;                                            |B4
ExitDat                       ;needed???? use ExitCMD instead?
     movlb     2              ;                                            |B2
     bsf       LCD_CS         ;                                            |B2
     movlb     0              ;                                            |B0
     return                   ;                                            |B0
Here's a simple example of setting up a GLCD using a series of PutCMD + offset
Code:
     movlw     b'10100010'    ;0xA2, bias = 1/9                            |B?
     call      PutCMD         ;                                            |B?
     movlw     0xA0           ;0xA0,seg direction=normal,0xA1=reversed     |B4
     call      PutCMD+4       ;                                            |B4
     movlw     0xC8           ;                                            |B4
     call      PutCMD+4       ;                                            |B4
     movlw     0xA6           ;normal(A6) or inverse display(A7)           |B4
     call      PutCMD+4       ;                                            |B4
     call      ExitCMD        ;returns CSn,A0,and Bank to idle             |B0
Edit: Changed the example. Posting code here that one needs to modify in the slightest is a nightmare.
Edit2: Fixed FSR typo
 
Last edited:

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
My question stands ...

I find the 8051 architecture to be far more versatile than the PIC16. It's got a much larger instruction set, and it's the hell of a lot easier to structure routines and interrupts through the use of the stack.

Is there an equivalent way of performing PUSH and POP instructions in the PIC16 architecture? ... @JohnInTX , if I remember correctly, you are acquainted with both. Any thoughts?
 
Last edited:

jpanhalt

Joined Jan 18, 2008
11,087
Assuming you are referring to the 16F1823, Push and Pop* are not named functions for that PIC, but yes, the stack can be accessed (Bank31). The registers are: STKPTR (stackpointer) and TOSH/L. The 10F322 does not have STKPTR, and its stack cannot be directly accessed.

John

*One could write a macro with those names, however.
 

JohnInTX

Joined Jun 26, 2012
4,787
Is there an equivalent way of performing PUSH and POP instructions in the PIC16 architecture?
Not really. The stack in the midrange parts is not user-accessible at all, it just stores subroutine return addresses.
The stack in the 18F can be PUSHed and POPed but not into any of the registers. You have to manually load the top of stack registers the PUSH. After POPing, TOSU,H,L have the data and that has to be moved to the destination manually. The stack pointer in the 18F is accessible and that can have some use if you're careful.
The stack in the enhanced midrange 16F1xxx is similar in operation to the 18F. PUSH and POP are not instructions but as John just said, you can use the stack pointer to emulate them. Data must still be moved manually to and from TopOfStack registers.

The wonderful ability to push PSW to temporarily save flags just isn't practical using 8bit PIC.
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
Ok ... so I think I half understand ... the PUSH/POP approach here would not be practical, from what I'm gathering.
Q: What is the best technique for administering registers then? Would one simply use unique registers in each routine? That would be a little complicated for programs with just a few routines in them. Or would one have to manually keep track of each and every register being used throughout the firmware?

EDIT: I've changed the title of this thread so as to more accurately reflect what I'm currently working on.
 

jpanhalt

Joined Jan 18, 2008
11,087
Q: What is the best technique for administering registers then? Would one simply use unique registers in each routine? That would be a little complicated for programs with just a few routines in them. Or would one have to manually keep track of each and every register being used throughout the firmware?
1) I have some uniquely named registers that are constantly in use (Bufpull and Bufpush in Common RAM for a FIFO buffer).
2) I also have 3 or 4 garbage registers, Temp0 ... Temp3. They are usually in Common RAM. I use and reuse them all the time. I have others with specific names in Common RAM, but remember that is only 16 bytes.
3) Then for named registers, I use GP RAM, and as mentioned above, I will use different banks for them to avoid having to switch banks..

I use indirect addressing (FSR0 and FSR1) a lot. Instead of names, one just uses the register number or its offset from a named register. I keep a cheat sheet from @JohnInTX (but available at a lot of places) that correlates Linear Memory mapping to Bank mapping. Needless to say, if you are using Linear Memory for something, you don't want to access the same register in a Bank for something else.

I have mentioned Linear Memory. I consider it, being able to address the stack, and being able to operate directly on WREG the top three advantages of that chip line. Glad to see you have migrated.
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
1) I have some uniquely named registers that are constantly in use (Bufpull and Bufpush in Common RAM for a FIFO buffer).
2) I also have 3 or 4 garbage registers, Temp0 ... Temp3. They are usually in Common RAM. I use and reuse them all the time. I have others with specific names in Common RAM, but remember that is only 16 bytes.
3) Then for named registers, I use GP RAM, and as mentioned above, I will use different banks for them to avoid having to switch banks..

I use indirect addressing (FSR0 and FSR1) a lot. Instead of names, one just uses the register number or its offset from a named register. I keep a cheat sheet from @JohnInTX (but available at a lot of places) that correlates Linear Memory mapping to Bank mapping. Needless to say, if you are using Linear Memory for something, you don't want to access the same register in a Bank for something else.

I have mentioned Linear Memory. I consider it, being able to address the stack, and being able to operate directly on WREG the top three advantages of that chip line. Glad to see you have migrated.
Excellent advice, John. Many thanks.

To be honest, the only reason why I'm working with this architecture is because of its superb energy efficiency. And another advantage I found is its highly configurable internal oscillator.

But other than that, I find the 8051 far easier to work with... I guess I need to gather more experience with the PiC16 (and maybe later I'll look at the PiC18) so as to form a more objective opinion later on.
 

jpanhalt

Joined Jan 18, 2008
11,087
I am still stuck on MPLAB 8.92, which limits my use of even more advanced 8-bit chips. If you take the time to learn MPLAB X, there are even greater things available in Microchips's peripherals. @joeyd999 said he has never seen the necessity to go 16-bits or more. For anything I am likely to attempt, I agree. Now, if you get into more sophisticated graphics stuff, like one of my SIL's and nephews does, then you need more.

As for the PIC 18 and Assembly, I have decided that should I make the jump, I will go to the PIC 24. The PIC 18 is like a steamboat with sails. The PIC 24 is nuclear.
 
Last edited:

jpanhalt

Joined Jan 18, 2008
11,087
Yes, but my recent experience with NXP 32-bit ARM (LPC 2134) would make me wary of that particular brand. Talk about being touchy for the bootloader. I spent 2 weeks getting a program loaded. Maybe if I need to do it again, it will only tale 3 days.

Glad to see you back and active. I thought "IT" was really funny. Perhaps to close to reality to be enjoyed by everyone. Here's the "like" I was afraid to give, Yes, I can be a coward facing a 50 caliber machine gun.
 
Last edited:
Top