Learning to program the PIC16LF1823

jpanhalt

Joined Jan 18, 2008
11,087
Here's the generic map. Not call chips have the same amount of linear memory, but I believe the mapping is the same to the extent of memory on each chip in the PIC16F1xxx group.

NB: Linear addresses are all offset by 0x2000. Bank0 GPRAM starts at 0x020 and goes to 0x06F. Linear starts at 0x2000, which corresponds to 0x020, and last GPRAM in Bank0 is 0x06F, which corresponds to 0x204F. Common RAM begins at 0x70 and that is preserved, so Linear 0x2050 jumps to Bank1. That is why you need the cheat sheet.

Just looked at the 16F1823 memory map. Didn't realize it was so small:

1590998782722.png
Your Linear RAM will be limited to just banks 0 and 1 (112 bytes).
 

Attachments

Thread Starter

cmartinez

Joined Jan 17, 2007
8,765
What's the deal with LVP?

If I wanted to use the RA3 (/MCLR) pin as a general purpose I/O, the manual says that I have to clear the /MCLR bit and the LVP bit in the configuration word. But doing that would disable the Low Voltage Programming (LVP) feature on the chip.

What does that mean? Does it mean that I won't be able to perform write to flash (self programming) instructions? Will my PickIt3 programmer cease to function? Will the chip explode with a bang, releasing a lethally toxic smoke mushroom?
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
What's the deal with LVP?

If I wanted to use the RA3 (/MCLR) pin as a general purpose I/O, the manual says that I have to clear the /MCLR bit and the LVP bit in the configuration word. But doing that would disable the Low Voltage Programming (LVP) feature on the chip.

What does that mean? Does it mean that I won't be able to perform write to flash (self programming) instructions? Will my PickIt3 programmer cease to function? Will the chip explode with a bang, releasing a lethally toxic smoke mushroom?
Low Voltage Programming is just that, it allows you to (re-)program the chip, on the board, without using a programmer (Like a PICKit3) that generates the high Vpp voltate on MCLR/ used in normal ICSP programming. It requires one more pin (LVP) AND requires that LVP is enabled in the CONFIG word (LVP is enabled by default on a new chip).

If you disable LVP in programming then you can reprogram the chip but you'll need the PICkit3 or something that will generate the high Vpp. If your design uses LVP and you inadvertently disable LVP in the CONFIG register, you'll have to program the chip with a PICkit using the high Vpp level.

Note that high Vpp will ALWAYS put the PIC into programming mode regardless of the LVP config bit. If LVP is enabled, then the programmer can also signal the PIC on that extra LVP line to get it into programming mode. In either case, programming clock and data go on the ICSP pins.

Specifics can be found in the Programming Specification for the chip.
http://ww1.microchip.com/downloads/en/DeviceDoc/41390D.pdf

Have fun!
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,765
Low Voltage Programming is just that, it allows you to (re-)program the chip, on the board, without using a programmer (Like a PICKit3) that generates the high Vpp voltate on MCLR/ used in normal ICSP programming. It requires one more pin (LVP) AND requires that LVP is enabled in the CONFIG word (LVP is enabled by default on a new chip).

If you disable LVP in programming then you can reprogram the chip but you'll need the PICkit3 or something that will generate the high Vpp. If your design uses LVP and you inadvertently disable LVP in the CONFIG register, you'll have to program the chip with a PICkit using the high Vpp level.

Note that high Vpp will ALWAYS put the PIC into programming mode regardless of the LVP config bit. If LVP is enabled, then the programmer can also signal the PIC on that extra LVP line to get it into programming mode. In either case, programming clock and data go on the ICSP pins.

Specifics can be found in the Programming Specification for the chip.
http://ww1.microchip.com/downloads/en/DeviceDoc/41390D.pdf

Have fun!
So in essence, the self-program (i.e. write to flash) feature of the chip remains unaffected regardless of the status of LVP?
 

JohnInTX

Joined Jun 26, 2012
4,787
So in essence, the self-program (i.e. write to flash) feature of the chip remains unaffected regardless of the status of LVP?
Yes.
Some chips allow you to write-protect sections of or the whole program flash in the CONFIG reg though to protect bootloaders, etc. See section 4.3 and REGISTER 4-2: CONFIGURATION WORD 2 on pp 48 of the datasheet for yours.
 

jpanhalt

Joined Jan 18, 2008
11,087
If I wanted to use the RA3 (/MCLR) pin as a general purpose I/O, the manual says that I have to clear the /MCLR bit and the LVP bit in the configuration word. But doing that would disable the Low Voltage Programming (LVP) feature on the chip.

What does that mean? Does it mean that I won't be able to perform write to flash (self programming) instructions? Will my PickIt3 programmer cease to function? Will the chip explode with a bang, releasing a lethally toxic smoke mushroom?
Re: Using MCLR as input

That's a common point of confusion about turning MCLR off so the pin can be used for input. Remember, MCLR has two functions: 1) VPP for programming; and 2) A reset when pulled low.

When you set MCLR ro OFF in configuration, the only function that affects is reset. It can always be used for VPP and programming.

As a corollary, remember VPP can be as high as 13 V for some chips. For more modern chips it is around 8V, as I recall. I am not certain of those voltages, but the point is that VPP will be enough higher than VCC that whatever you are using as an input needs to be protected from or tolerant of the higher voltage. Also, VPP has to change quickly, and whatever the input is, it cannot represent much of a load
.
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,765
Re: Using MCLR as input

That's a common point of confusion about turning MCLR off so the pin can be used for input. Remember, MCLR has two functions: 1) VPP for programming; and 2) A reset when pulled low.

When you set MCLR ro OFF in configuration, the only function that affects is reset. It can always be used for VPP and programming.

As a corollary, remember VPP can be as high as 13 V for some chips. For more modern chips it is around 8V, as I recall. I am not certain of those voltages, but the point is that VPP will be enough higher than VCC that whatever you are using as an input needs to be protected from or tolerant of the higher voltage. Also, VPP has to change quickly, and whatever the input is, it cannot represent much of a load
.
I understand ... but since I'm using the PicIt3 programmer, and not my own or a third party, it shouldn't matter much if I set or clear the LVP bit in the configuration word, should it?
 

jpanhalt

Joined Jan 18, 2008
11,087
I understand ... but since I'm using the PicIt3 programmer, and not my own or a third party, it shouldn't matter much if I set or clear the LVP bit in the configuration word, should it?
I always clear LVP. It is clear why it has to be set on by default, but I use an ICD3 (or PK3) to program. If left on, it can be a problem, or at least it comes up in discussion of problems frequently.
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,765
I just found out that the simple instruction of dividing an 8 bit register by another, with an integer result and a remainder does not exist in the PCI16F1823... :mad:

In the 8051, said instruction is DIV AB, which divides A by B, leaving the result in A, and the remainder in B ... simple as that.

I've done some googling around looking for a simple function that will do the same thing, and unfortunately every function I've found relates to much harder math, such as floating point or 32 bit integers, etc...

Can any of you guys share the code for this menial task?
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,765
Ok, so as not to be judged as lazy by any of the people that I respect and appreciate, here's my first attempt at a simple 8bit/8bit division.

Code:
; The following routine will perform the division operation of DIVIDEND/DIVISOR

division:
  clrf RESULT          ;start by clearing the RESULT resgister

division_loop:
  movfw DIVISOR       
  subwf DIVIDEND, 1    ;subtract DIVISOR from DIVIDEND, and store the result in DIVIDEND
  incf RESULT, 1
  movfw DIVISOR        ;test if DIVISOR > DIVIDEND
  subwf DIVIDEND, 0
  btfsc STATUS, 0      ;if DIVISOR <= DIVIDEND, keep looping
goto division_loop

;At this point RESULT will hold the resulting value of DIVIDEND/DIVISOR
;and DIVIDEND will hold the remainder
The code above feels to me rather primitive and clumsy to say the least. What I see is that, for example, dividing 255 by 1 would take 255 iterations of the division loop!
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,765
Did you find any luck in the PicList site?
Max.
Not really. What I found are more complex division and multiplication operations, even square roots!.

Here's my second attempt at coding DIVIDEND/DIVISOR:

Code:
divide:
  clrf RESULT              ;start by clearing the RESULT resgister

division_loop:
  movfw DIVISOR            ;test if DIVISOR > DIVIDEND
  subwf DIVIDEND, 0
  btfsc STATUS, Z
  goto exit_exact_division ;if the result of the previous subtraction was 0, then exit
                           ;reporting an exact division
  btfsc STATUS, C          ;if the previous subtraction generated a negative result
   goto exit_division      ;then exit directly the division process

  movfw DIVISOR            ;if the result previous subtraction was neither negative nor
  subwf DIVIDEND, 1        ;exact, the perform the subtraction again, this time leaving
  incf RESULT, 1           ;the result in DIVIDEND, and incrementing the RESULT register
goto division_loop

exit_exact_division:
  incf RESULT, 1           ;if the test subtraction was exact, then increment the RESULT
  clrf DIVIDEND            ;register, and set DIVIDEND to zero to report no remainder

exit_division:

;At this point RESULT will hold the resulting value of DIVIDEND/DIVISOR
;and DIVIDEND will hold the remainder

end
This looks better... but it's still a lot of code for such a simple operation... it sucks. I'm going to study it and test it and see if it works and if it can be improved.
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
Howdy! Here's an old apnote that shows many fixed point math routines for midrange. I've adapted these for baseline and 18F but not the 1xxx stuff so I don't have any drop in code for you. But you should be able to port most of it as is with few changes and I can probably help with that. I know we have some members who use the 1xxx stuff a lot so maybe they have some canned routines.
FXD0808S is 8/8 signed division, FXD0808U is unsigned. Code starts on pp233. Note that those routines make use of macros (also included in the code). This is old stuff before MPASM had a linker. You can include the macro code and run the code as is or just copy the code from the body of the macro to the routine itself. These use a traditional shift and subtract algorithm which will run faster than successive subtraction.
Good luck!
 

Attachments

Last edited:

Thread Starter

cmartinez

Joined Jan 17, 2007
8,765
Ok, here's the code I rescued translated from John's paper:

Code:
;*****************************************************************
;
;           The following code was extracted from AN617
;
;       8/8 Bit Unsigned Fixed Point Divide 8/8 -> 08.08
;       Input:
;        8 bit unsigned fixed point dividend in DIVIDEND
;        8 bit unsigned fixed point divisor in DIVISOR
;       Output:
;        8 bit unsigned fixed point quotient in DIVIDEND
;        8 bit unsigned fixed point remainder in REMAINDER
;       Result: DIVIDEND, REMAINDER <-- DIVIDEND / DIVISOR
;        Max Timing: 100 clks
;        Min Timing:  92 clks
;        PM: 15, DM: 4
;*****************************************************************

divide_8_bit:
  movf DIVIDEND, w      ;save the original value of DIVIDEND
  movwf TEMP00          ;so as to restore it before returning

  clrf REMAINDER
  movlw d'8'
  movwf LOOPCOUNT

division_loop:
  rlf DIVIDEND, w
  rlf REMAINDER, f
  movf DIVISOR, w
  subwf REMAINDER, f
  btfsc STATUS, C
  goto skip_addition
  addwf REMAINDER, f
  bcf STATUS, C
skip_addition:
  rlf DIVIDEND, f
  decfsz LOOPCOUNT, f
goto division_loop

  movf DIVIDEND, w     ;load RESULT with the result of
  movwf RESULT         ;the division operation

  movf TEMP00, w       ;restore the value of DIVIDEND before
  movwf DIVIDEND       ;returning

return
It looks nice, tight, and very efficient ... problem is that the code's uncommented and I barely understand what it's doing... I'm gonna stare at it a bit more and see if the light reaches my only working neuron... Either way, I plan to physically test it and see if it works the way it's supposed to.
 
Last edited:

jpanhalt

Joined Jan 18, 2008
11,087
PICList has some routines. Golocvhenko's are usually pretty compact (http://www.piclist.com/techref/microchip/math/div/index.htm ). But there is no 8 bit by 8 bit with remainder. Any of the routines for larger bit sizes can be made smaller.

This page shows a comparison of some of the methods: http://www.piclist.com/techref/member/NG--944/pic_collection.htm

A couple on that list look promising:
http://www.piclist.com/techref/microchip/math/8bmul256div8b-ng.htm (uses 3 temp registers) http://www.piclist.com/techref/microchip/math/div10byfxp7q8.htm

It's a bit late for me and I have to go to Cleveland early in the morning. My procedure is based on the "Kenyan" method (shift the divisor until it is the largest possible, then do subtractions and right shifts). I won't be able to get to it until later. What do you know about the dividend and divisor? Can either be zero? My method does not re-do failed subtractions. It just carries the negative. That speeds it up, but requires a couple of additional steps at the end to extract the remainder. The code is a little longer, but faster for lack of loops. It also includes the enhanced mid-range simplified instructions for subtraction.
 
Last edited:

atferrari

Joined Jan 6, 2004
5,012
César
The very first thing I learnt when dealing with maths routines (division) is the need of being sure that somewhere at the start or prior to call the routine you are certain of not running inadvertently into a "divide by zero" situation with unexpected results.
Happened to me.

Edit/
Keep in mind Peter Hemsley for eventual future necessities.
Part of his routines are in PIClist and a lot was in a site of the old EPE magazine or related with it.
I extended some of his routines. Good work.
/Edit
 
Last edited:
Top