Discussion:
PIC16F1508: High Endurance Flash control using Assembly (ASM)
James Wages
2016-09-28 03:03:37 UTC
Permalink
I've almost completed my 16F1508 code to generate square wave audio tones. The only thing left is the code required to save 1 of 16 different user-programmable settings as a single 8-bit word/byte into non-volatile memory. I've written ASM code for EEPROM PICs in the past, but my 16F1508 has FLASH -- storage normally used as program memory. So I am trying to figure out how to properly code flash ERASE-WRITES and READS.

I have read the entire section on Flash, pages 90-105 of the datasheet:

http://ww1.microchip.com/downloads/en/DeviceDoc/40001609E.pdf

And I have also read the unfortunately C-oriented information given in AN1673:

http://ww1.microchip.com/downloads/en/AppNotes/00001673A.pdf

NOTE: I am a PIC Assembly guy, and although I know some of you may wish to persuade me to learn C in light of the FLASH libraries available, I wish to stick with ASM. I am not going to consider C, so let's stick with a strictly ASM discussion.

Here are my questions:

1. RESERVING HIGH-ENDURANCE FLASH MEMORY. Note page 7 in the AN1673 pdf linked above where it mentions a setting only useful when programming in C. Naturally, I want to know how I write the equivalent of that within my ASM code. Surely there must be a way to reserve the High Endurance Flash using ASM code inside my program, akin to how I can write CONFIG BIT settings in my code. I know that High Endurance Flash on the 16F1508 consists of 4 rows (32 bytes in each row), addressed from 1F80 to 1FFF. What ASM code do I use to ensure my MPASM won't overwrite 1F80 to 1FFF when it writes my program code to the PIC?

2. The Flash code I have written closely follows the 16F1508 Datasheet. I modified the code only slightly, and I improved the notes. You can review my code here (ERASE, WRITE and READ code):

https://cl.ly/442m3y1E263s

I feel confident my ERASE code is correct, but please have a close look at it anyway. The question I have primarily centers on my WRITE code. For example:

movlw LOW DATA_ADDR ; Load initial data address
movwf FSR0L
movlw HIGH DATA_ADDR ; Load initial data address
movwf FSR0H

Are those LOW and HIGH "DATA_ADDR" considered to be user RAM locations that I must define and then fill with something? Or do I just write those 4 lines of code as-is? If user RAM locations that I must define, what do I fill them with? My data? (But it seems to want an "Address" not data.)

Also within the WRITE code (as per the code given in the datasheet), it says:

"64 bytes of data are loaded"

But I don't see how "64 bytes" (as opposed to 32 or even 128 bytes) is established in the datasheet's WRITE code.

In my application, I only need to deal with a single row (32 bytes), not two rows (64 bytes). I need to WRITE & READ a single 8-bit word to/from Flash. The device I am creating will be powered ON/OFF often, and there are settings that need to survive that ON/OFF cycle, which I want to store in that single 8-bit word in Flash. There will be a total of 16 settings stored in only a single 8-bit byte of FLASH, exactly as follows:

00000000
00000001
00000010
00000011
00000100
00000101
00000110
00000111
00001000
00001001
00001010
00001011
00001100
00001101
00001110
00001111

The user will use DIP switches to tell the MCU which of the 16 settings they wish to program. For example, if they select setting 3, I would need to WRITE "00000010" into a single 8-bit word of Flash. And yes, I fully understand Flash must be programmed by rows, which means 32 words, rather than just the 1 word that I need. But again, I am unsure of how to properly put together the WRITE code in ASM, hence this post.

So if I want to WRITE "00000010" to Flash, I would put "00000010" into a RAM that I defined named "LOW DATA_ADDR" (or whatever name I want to give it) and then either store "0" in "HIGH DATA_ADDR" or simply not use "HIGH DATA_ADDR" at all, since I only need to store one 8-bit word in Flash?

I look forward to your thoughts and advice.

Thank you,

James W.
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
Anthony Nixon
2016-09-28 05:20:15 UTC
Permalink
Hi James,

The read/write looks the same as for the 16F1519 that I used for the
HP calculator project.

You will probably have the data that needs to be written to ROM,
stored in consecutive RAM somewhere.

Set FSR0 or FSR1 to point to the start of this RAM memory block.

You need to set up the start address of a 32 word aligned ROM address.
(PMADRH:PMADRL)


Write Loop:

Erase the entire row (which is why you need to read and store the ROM
data here if you want it preserved)

One by one, write the X number of bytes of RAM data to the ROM
latches. (32 maximum for each write)

PMDATH:PMDATL
incf PMADRL

Pad any extra of the 32 ROM locations with blank data.

On the last write to latch, (ie prior to the 32nd write), you [bcf
PMCON1,LWLO] to write the ROW into EEPROM.

If required, you do the same with the next row(s).

I have some code if you would like it.

cheers

Tony
Post by James Wages
I've almost completed my 16F1508 code to generate square wave audio tones. The only thing left is the code required to save 1 of 16 different user-programmable settings as a single 8-bit word/byte into non-volatile memory. I've written ASM code for EEPROM PICs in the past, but my 16F1508 has FLASH -- storage normally used as program memory. So I am trying to figure out how to properly code flash ERASE-WRITES and READS.
http://ww1.microchip.com/downloads/en/DeviceDoc/40001609E.pdf
http://ww1.microchip.com/downloads/en/AppNotes/00001673A.pdf
NOTE: I am a PIC Assembly guy, and although I know some of you may wish to persuade me to learn C in light of the FLASH libraries available, I wish to stick with ASM. I am not going to consider C, so let's stick with a strictly ASM discussion.
1. RESERVING HIGH-ENDURANCE FLASH MEMORY. Note page 7 in the AN1673 pdf linked above where it mentions a setting only useful when programming in C. Naturally, I want to know how I write the equivalent of that within my ASM code. Surely there must be a way to reserve the High Endurance Flash using ASM code inside my program, akin to how I can write CONFIG BIT settings in my code. I know that High Endurance Flash on the 16F1508 consists of 4 rows (32 bytes in each row), addressed from 1F80 to 1FFF. What ASM code do I use to ensure my MPASM won't overwrite 1F80 to 1FFF when it writes my program code to the PIC?
https://cl.ly/442m3y1E263s
movlw LOW DATA_ADDR ; Load initial data address
movwf FSR0L
movlw HIGH DATA_ADDR ; Load initial data address
movwf FSR0H
Are those LOW and HIGH "DATA_ADDR" considered to be user RAM locations that I must define and then fill with something? Or do I just write those 4 lines of code as-is? If user RAM locations that I must define, what do I fill them with? My data? (But it seems to want an "Address" not data.)
"64 bytes of data are loaded"
But I don't see how "64 bytes" (as opposed to 32 or even 128 bytes) is established in the datasheet's WRITE code.
00000000
00000001
00000010
00000011
00000100
00000101
00000110
00000111
00001000
00001001
00001010
00001011
00001100
00001101
00001110
00001111
The user will use DIP switches to tell the MCU which of the 16 settings they wish to program. For example, if they select setting 3, I would need to WRITE "00000010" into a single 8-bit word of Flash. And yes, I fully understand Flash must be programmed by rows, which means 32 words, rather than just the 1 word that I need. But again, I am unsure of how to properly put together the WRITE code in ASM, hence this post.
So if I want to WRITE "00000010" to Flash, I would put "00000010" into a RAM that I defined named "LOW DATA_ADDR" (or whatever name I want to give it) and then either store "0" in "HIGH DATA_ADDR" or simply not use "HIGH DATA_ADDR" at all, since I only need to store one 8-bit word in Flash?
I look forward to your thoughts and advice.
Thank you,
James W.
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
James Wages
2016-09-29 01:05:05 UTC
Permalink
Tony,

Thank you for your advice. But I would like to point out one error.

I am writing to High Endurance Flash (HEF) which has 100k write endurance, not the regular Flash which has only 10k write endurance. HEF on the 16F1508 starts at address 0F80h and goes to FFFh. So while you are correct that PMDATH:PMDATL are both required to, for example, start writing at HEF address 0F80h, it is not correct that both PMDATH:PMDATL are used.

Regular 10k endurance flash is 14-bit.
HEF is 8-bit.

Therefore, only PMDATL is used. PMDATH is not needed or used at all.

Next...

As I mentioned in an earlier post, I only want to write a single 8-bit byte of data to HEF. Since an entire row must be erase/written, that means I will only use 1 out of 32, and in my case I am writing that 8-bits starting at 0F80h. The remaining 31 words are not needed by me, so I don't see why I need to "pad" them (write data into them). If such truly is required, can you please explain why?

Once again, here is the code I presented in the second email I posted to this list yesterday:

https://cl.ly/120Z2G331x0a

(Again, I verified that code works perfectly, despite my lack of padding unused words.)

Thanks,

James W.


9/28/16, 2:20 PM, "Anthony Nixon" <piclist-***@mit.edu on behalf of ***@gmail.com>:

You need to set up the start address of a 32 word aligned ROM address.
(PMADRH:PMADRL)

Write Loop:

Erase the entire row (which is why you need to read and store the ROM
data here if you want it preserved)

One by one, write the X number of bytes of RAM data to the ROM
latches. (32 maximum for each write)

PMDATH:PMDATL
incf PMADRL

Pad any extra of the 32 ROM locations with blank data.

On the last write to latch, (ie prior to the 32nd write), you [bcf
PMCON1,LWLO] to write the ROW into EEPROM.

If required, you do the same with the next row(s).
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
Anthony Nixon
2016-09-29 01:12:08 UTC
Permalink
Hi James,

Sorry, I was in the middle of writing a help file for a project when I
replied and only briefly looked at the data sheet from your link. The
eeprom code looked the same as the chip I have been using lately, but
might have differences that I missed

There are latches that are written to each row of eeprom and these are
filled prior to the write operation. I guess if they are not filled
with anything, then random (or previous) data will be written to the
remaining row.

If you are not using the data stored in the entire row then there
probably won't be a problem.

cheers

Tony
Post by James Wages
Tony,
Thank you for your advice. But I would like to point out one error.
I am writing to High Endurance Flash (HEF) which has 100k write endurance, not the regular Flash which has only 10k write endurance. HEF on the 16F1508 starts at address 0F80h and goes to FFFh. So while you are correct that PMDATH:PMDATL are both required to, for example, start writing at HEF address 0F80h, it is not correct that both PMDATH:PMDATL are used.
Regular 10k endurance flash is 14-bit.
HEF is 8-bit.
Therefore, only PMDATL is used. PMDATH is not needed or used at all.
Next...
As I mentioned in an earlier post, I only want to write a single 8-bit byte of data to HEF. Since an entire row must be erase/written, that means I will only use 1 out of 32, and in my case I am writing that 8-bits starting at 0F80h. The remaining 31 words are not needed by me, so I don't see why I need to "pad" them (write data into them). If such truly is required, can you please explain why?
https://cl.ly/120Z2G331x0a
(Again, I verified that code works perfectly, despite my lack of padding unused words.)
Thanks,
James W.
You need to set up the start address of a 32 word aligned ROM address.
(PMADRH:PMADRL)
Erase the entire row (which is why you need to read and store the ROM
data here if you want it preserved)
One by one, write the X number of bytes of RAM data to the ROM
latches. (32 maximum for each write)
PMDATH:PMDATL
incf PMADRL
Pad any extra of the 32 ROM locations with blank data.
On the last write to latch, (ie prior to the 32nd write), you [bcf
PMCON1,LWLO] to write the ROW into EEPROM.
If required, you do the same with the next row(s).
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
James Cameron
2016-09-29 01:37:09 UTC
Permalink
G'day James,

Yes, your code looks good, though I've not checked it in fine detail.

A whole row will be erased and then the first byte is written. The
rest of the row will remain erased, or be written with whatever is in
the write latch, and that doesn't matter. You don't have to write pad
if you don't want to.

Endurance impact will be to the whole row, but as the rest of the row
doesn't matter to you, the impact can be considered as only to the byte.

Five milliseconds is a long time though; I'm still worried about power
down or reset during that time. Hope you're covering it somehow.
Internal battery? It would be interesting to add a pin write so that
you could measure the time with an oscilloscope, in case it is
completing sooner than specified.

Power down or reset between erase and write will leave the byte
unpredictable. If your application can cope with this, don't bother
handling it. If your application demands predictability, then a
simple method is to write the byte into the first address, invert the
value, and write it into the second address. Your reader would then
read the two addresses, invert and compare. Where compare fails, use
default value. This is such a popular technique it probably has a
name!

One minor concern; your code turns off interrupts (INTCON, GIE) but
does not turn them back on. ;-)
--
James Cameron
http://quozl.netrek.org/
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
James Cameron
2016-09-28 05:30:19 UTC
Permalink
Post by James Wages
I've almost completed my 16F1508 code to generate square wave audio
tones. The only thing left is the code required to save 1 of 16
different user-programmable settings as a single 8-bit word/byte
into non-volatile memory. I've written ASM code for EEPROM PICs in
the past, but my 16F1508 has FLASH -- storage normally used as
program memory. So I am trying to figure out how to properly code
flash ERASE-WRITES and READS.
http://ww1.microchip.com/downloads/en/DeviceDoc/40001609E.pdf
http://ww1.microchip.com/downloads/en/AppNotes/00001673A.pdf
NOTE: I am a PIC Assembly guy, and although I know some of you may
wish to persuade me to learn C in light of the FLASH libraries
available, I wish to stick with ASM. I am not going to consider C,
so let's stick with a strictly ASM discussion.
Sure.
Post by James Wages
1. RESERVING HIGH-ENDURANCE FLASH MEMORY. Note page 7 in the AN1673
pdf linked above where it mentions a setting only useful when
programming in C. Naturally, I want to know how I write the
equivalent of that within my ASM code. Surely there must be a way
to reserve the High Endurance Flash using ASM code inside my
program, akin to how I can write CONFIG BIT settings in my code. I
know that High Endurance Flash on the 16F1508 consists of 4 rows (32
bytes in each row), addressed from 1F80 to 1FFF.
That's not right. Page 15 says 16F1508 high-endurance flash memory
address range is 0F80 to 0FFF.
Post by James Wages
What ASM code do I use to ensure my MPASM won't overwrite 1F80 to
1FFF when it writes my program code to the PIC?
In assembly, you have reasonable control over where code is placed.
As assembly proceeds, the current address increments. So don't let it
increment into this address range.

As the last lines in the assembly file, force an error if the current
address is above the limit. I don't know about MPASM, as I use GPASM,
and it was something like;

LAST RETLW 0

IF LAST > 0xF80
MESSG "error: code exceeds my choice of allocation limit"
ENDIF
END

Look through MPASM documentation for forcing errors based on IF/ENDIF.

It's not really a question of PIC instruction assembly, but of
assembler software.
Post by James Wages
2. The Flash code I have written closely follows the 16F1508
Datasheet. I modified the code only slightly, and I improved the
https://cl.ly/442m3y1E263s
Grey text on white background with nag popup. ;-) But otherwise
readable with a bit of manipulation.
Post by James Wages
I feel confident my ERASE code is correct, but please have a close
look at it anyway. The question I have primarily centers on my
movlw LOW DATA_ADDR ; Load initial data address
movwf FSR0L
movlw HIGH DATA_ADDR ; Load initial data address
movwf FSR0H
Are those LOW and HIGH "DATA_ADDR" considered to be user RAM
locations that I must define and then fill with something? Or do I
just write those 4 lines of code as-is? If user RAM locations that
I must define, what do I fill them with? My data? (But it seems to
want an "Address" not data.)
This is use of FSR, that's all? Yes, you should define an area of RAM
called DATA_ADDR. FSR is being used to index it.
Post by James Wages
"64 bytes of data are loaded"
But I don't see how "64 bytes" (as opposed to 32 or even 128 bytes)
is established in the datasheet's WRITE code.
It does. The counter is limited to 32 words of 14-bits, see where it
does an XORLW 0x1F, that sets the limit. You can't change for erase,
as it is the row erase size, per table 10-1 of datasheet. But I
imagine you could write less than the row size if you were writing
into previously erased Flash cells. The note above table 10-1
supports this idea.

Note: comments above your ERASE FLASH say "32 bytes/words", which
doesn't make sense to me. It should be 32 words, or 64 addressable
bytes, constrained to the 14-bit width of the program memory.
Post by James Wages
In my application, I only need to deal with a single row (32 bytes),
not two rows (64 bytes).
The code as it stands works on 64 addressable bytes.
Post by James Wages
I need to WRITE & READ a single 8-bit word to/from Flash. The
device I am creating will be powered ON/OFF often, and there are
settings that need to survive that ON/OFF cycle, which I want to
store in that single 8-bit word in Flash.
Um, what if power goes off between erase and write? How are you going
to handle that? I would do it by adding a checksum to the data, and
by writing either the first 64-bytes or the second 64-bytes of the
HEF, and switch between them. That way if the power goes off, you'll
end up with an erased 64-bytes and a usable 64-bytes containing the
previous settings.

Anthony mentions reading and storing the row before erasing; that's
only necessary if you don't have another row with useful data.
Post by James Wages
There will be a total of 16 settings stored in only a single 8-bit
Plenty of space available then. ;-)
Post by James Wages
00000000
00000001
00000010
00000011
00000100
00000101
00000110
00000111
00001000
00001001
00001010
00001011
00001100
00001101
00001110
00001111
The user will use DIP switches to tell the MCU which of the 16 settings they wish to program. For example, if they select setting 3, I would need to WRITE "00000010" into a single 8-bit word of Flash. And yes, I fully understand Flash must be programmed by rows, which means 32 words, rather than just the 1 word that I need. But again, I am unsure of how to properly put together the WRITE code in ASM, hence this post.
So if I want to WRITE "00000010" to Flash, I would put "00000010" into a RAM that I defined named "LOW DATA_ADDR" (or whatever name I want to give it) and then either store "0" in "HIGH DATA_ADDR" or simply not use "HIGH DATA_ADDR" at all, since I only need to store one 8-bit word in Flash?
I look forward to your thoughts and advice.
Thank you,
James W.
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
--
James Cameron
http://quozl.netrek.org/
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
James Wages
2016-09-28 10:03:03 UTC
Permalink
Thank you for your detailed reply, James C.

9/28/16, 2:30 PM, "James Cameron" <***@laptop.org>:
...I use GPASM,

Why use GPASM over MPASM?

Best,

James W.
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
James Cameron
2016-09-28 11:18:43 UTC
Permalink
Post by James Wages
Thank you for your detailed reply, James C.
...I use GPASM,
Why use GPASM over MPASM?
Because I could fix the assembler when it had a problem. I remember
doing that once or twice, back when Scott Dattalo supported GPUTILS.

MPASM wasn't practical at the time on Linux. Apparently that has
changed since, but I've not yet adapted. All my new designs are on
AVR, ARM, or ESP8266. I'd love to get back into PICs, but I'd need to
be happy with the toolchain on Linux and invest in a new programmer.

Any PIC expertise you see from me is ancient history combined with
reading latest datasheet. ;-)
--
James Cameron
http://quozl.netrek.org/
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
James Wages
2016-09-28 08:13:10 UTC
Permalink
I am sorry if anyone replied after my first post, but since I get the DIGEST I have not seen your replies. I've spent the last few hours mulling options and testing by trial and error. I found that the following PIC16F1508 ASM subroutines work perfectly to ERASE-WRITE a single 8-bit value (b'00000001') to High Endurance Flash, then READ it back:

https://cl.ly/120Z2G331x0a

As you can see, it's a cut-down version of my previously posted code. Also note that I made an error in my previous code in that I said the HEF starts at 1F80, but on the 16F1508 it actually starts at 0F80.

The only thing I still don't know how to do is protect the HEF range of 0F80 to 0FFF using an Assembler directive. So for now I can only try ensure my Program Code is short enough so it won't reach 0F80. If you have thoughts on this, please let me know.

Thank you,

James W.

========

Previous Code: https://cl.ly/442m3y1E263s

16F1508 DataSheet (See pg.90):
http://ww1.microchip.com/downloads/en/DeviceDoc/40001609E.pdf

AN1673:
http://ww1.microchip.com/downloads/en/AppNotes/00001673A.pdf
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
Anthony Nixon
2016-09-28 08:33:50 UTC
Permalink
The only thing I still don't know how to do is protect the HEF range
of 0F80 to 0FFF using an Assembler directive. So for now I can only
try ensure my Program Code is short enough so it won't reach 0F80. If
you have thoughts on this, please let me know.


The CP bit in the config 1 can be cleared to protect all flash memory
from external reading, but you can still write to it internally.

__CONFIG _CONFIG1, _CP_ON

cheers

Tony
Post by James Wages
https://cl.ly/120Z2G331x0a
As you can see, it's a cut-down version of my previously posted code. Also note that I made an error in my previous code in that I said the HEF starts at 1F80, but on the 16F1508 it actually starts at 0F80.
The only thing I still don't know how to do is protect the HEF range of 0F80 to 0FFF using an Assembler directive. So for now I can only try ensure my Program Code is short enough so it won't reach 0F80. If you have thoughts on this, please let me know.
Thank you,
James W.
========
Previous Code: https://cl.ly/442m3y1E263s
http://ww1.microchip.com/downloads/en/DeviceDoc/40001609E.pdf
http://ww1.microchip.com/downloads/en/AppNotes/00001673A.pdf
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
James Cameron
2016-09-28 09:52:17 UTC
Permalink
Use __maxrom or __badrom directives.

http://ww1.microchip.com/downloads/en/DeviceDoc/33014L.pdf page 76.
Post by James Wages
https://cl.ly/120Z2G331x0a
As you can see, it's a cut-down version of my previously posted code. Also note that I made an error in my previous code in that I said the HEF starts at 1F80, but on the 16F1508 it actually starts at 0F80.
The only thing I still don't know how to do is protect the HEF range of 0F80 to 0FFF using an Assembler directive. So for now I can only try ensure my Program Code is short enough so it won't reach 0F80. If you have thoughts on this, please let me know.
Thank you,
James W.
========
Previous Code: https://cl.ly/442m3y1E263s
http://ww1.microchip.com/downloads/en/DeviceDoc/40001609E.pdf
http://ww1.microchip.com/downloads/en/AppNotes/00001673A.pdf
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
--
James Cameron
http://quozl.netrek.org/
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
James Wages
2016-09-29 02:01:03 UTC
Permalink
9/28/16, 6:52 PM, "James Cameron" <***@laptop.org>:
Use __maxrom or __badrom directives.

Thank you, James C.

Here is the code I will use:

; -------------------------------
; High Endurance Flash Protection
; -------------------------------
; Make sure Program Memory never overwrites HEF: F80h to FFFh
__maxrom 0xFFF ; 16F1508 is 4k, so Flash Program Memory goes to FFFh.
__badrom 0xF80 - 0xFFF ; Protect HEF address range.


Some people who use the linker will of course recommend that I too should use the linker, but I really don't need to or want to. I like everything in one box, so to speak, all contained in a single ASM file. I have zero need for code portability, so breaking it apart makes me feel rather scatter-brained. The assembler directives above should be all I need. That way, in the unlikely event I accidentally write too much program code that would extend into the HEF block, MPASM will throw an error at assembly time. I've not tested it yet, but that's how it should work.




9/28/16, 2:30 PM, "James Cameron" <***@laptop.org>:
Note: comments above your ERASE FLASH say "32 bytes/words", which
doesn't make sense to me. It should be 32 words, or 64 addressable
bytes, constrained to the 14-bit width of the program memory.

Just to clarify, 10k endurance Flash is 14-bit whereas HEF is 8-bit, as per TABLE3-1 on page 15 of the Datasheet:

http://ww1.microchip.com/downloads/en/DeviceDoc/40001609E.pdf

That is also mentioned in the note at the bottom left of page 2 in this PDF:

http://ww1.microchip.com/downloads/en/AppNotes/00001673A.pdf





9/28/16, 2:30 PM, "James Cameron" <***@laptop.org>:
Um, what if power goes off between erase and write? How are you going
to handle that? I would do it by adding a checksum to the data, and
by writing either the first 64-bytes or the second 64-bytes of the
HEF, and switch between them. That way if the power goes off, you'll
end up with an erased 64-bytes and a usable 64-bytes containing the
previous settings.

I will give "power-failure during an erase/write sequence" further thought; but honestly, even if bad data is written into flash, it won't affect anything critical in my application. The device would simply generate a different tone than the user thought they had programmed. That's all. And the user will notice that and they can then just enter program mode again (via DIP switch) and reprogram. It would be no big deal at all.

I have actually been giving more thought to VERIFY. The datasheet mentions that after doing an ERASE-WRITE it's good programming practice to VERIFY that the written data is correct. So what I was thinking is that if I do a VERIFY and find the written data is not what should have been written, I could do another ERASE-WRITE starting at the next block of 32 words, which for the 16F1508 would be 0FA0, and if that fails I would try again doing and ERASE-WRITE at 0FC0, and if that fails, I would try again at 0FE0, and if that too fails, I could flash an LED to inform the user there is an internal flash failure, which could remain until they reset the device. So if each block of 32 words is rated at 100k ERASE-WRITES, and if I primarily use only one of those blocks, that switching code would allow auto switching in case one block failed, effectively giving 400k ERASE-WRITES for my application. Or at least, I think that's how it would work. But honestly, the programming mode will likely be used only a few times and then never again, so even 10k endurance flash should be sufficient for my application. I am simply using HEF because, well, why not? :-)



9/28/16, 2:30 PM, "James Cameron" <***@laptop.org>:
Grey text on white background with nag popup. ;-) But otherwise
readable with a bit of manipulation.

Yes, CloudApp has its negatives, but it's free for my purpose and it allows easy sharing from my Mac. My worry about posting lots of ASM code to this list via email is the maximum with and line-wrapping. Code becomes very hard to follow if my comments are wrapped, which is why I posted the code to CloudApp. There's no fancy highlighting like in a good text editor, but the spacing and indents are correct.




9/29/16, 10:37 AM, "James Cameron" <***@laptop.org>:
One minor concern; your code turns off interrupts (INTCON, GIE) but
does not turn them back on. ;-)

By design, yes. I want interrupts OFF until I need them. There are parts of my code I don't want interrupted, even for the tiny duration it would take to enter/exit the ISR. But thanks for taking note of that.


Best,

James W.
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mi
James Cameron
2016-09-29 02:54:11 UTC
Permalink
Post by James Cameron
Use __maxrom or __badrom directives.
Thank you, James C.
; -------------------------------
; High Endurance Flash Protection
; -------------------------------
; Make sure Program Memory never overwrites HEF: F80h to FFFh
__maxrom 0xFFF ; 16F1508 is 4k, so Flash Program Memory goes to FFFh.
You might find __maxrom in the processor include file already.
Post by James Cameron
__badrom 0xF80 - 0xFFF ; Protect HEF address range.
[...] The assembler directives above should be all I need. That
way, in the unlikely event I accidentally write too much program
code that would extend into the HEF block, MPASM will throw an error
at assembly time. I've not tested it yet, but that's how it should
work.
Why not test it? Edit your file, change 0xF80 to 0x020, then run the
assembler and expect it to fail. Observe the failure. Then undo the
edits to your file, changing 0x020 back to 0xF80. Run the assembler
again, and it should not fail.

That way, you'll (a) test that it works, and (b) prepare yourself for
recognising the future event you are hoping not to experience. ;-)
Post by James Cameron
[... rewind ...] Some people who use the linker will of course
recommend that I too should use the linker, but I really don't need
to or want to. I like everything in one box, so to speak, all
contained in a single ASM file. I have zero need for code
portability, so breaking it apart makes me feel rather
scatter-brained.
Don't feel scatter-brained; it's normal to resist complexity
thresholds, and all of us do it all the time. There has to be a good
reason before a complexity is adopted, and until you are happy with
that reason, please continue to resist.

Other complexity thresholds you may look forward to some day;

- using multiple source files, to isolate concepts, enforce
modularity, and re-use common code,

- using dependency checking rebuilds ("make" files), to speed
assembly,

- using a linker to combine prebuilt modules with new modules,

- using a linker to combine objects from different languages,

- using revision control systems to maintain a time machine,
(e.g. git),

- using revision control systems for branches of a build to match
different target hardware,

- collaborating with other people through revision control systems
(e.g. github),

But again, until you need these things, ignore them and those of us
who keep bringing them up. ;-)

For me, my work involves tens of thousands of source files with
assembly times ranging from tenth of a second to half a day.

Justifiable complexity.
Post by James Cameron
Note: comments above your ERASE FLASH say "32 bytes/words", which
doesn't make sense to me. It should be 32 words, or 64 addressable
bytes, constrained to the 14-bit width of the program memory.
http://ww1.microchip.com/downloads/en/DeviceDoc/40001609E.pdf
http://ww1.microchip.com/downloads/en/AppNotes/00001673A.pdf
Yes, but you still have "bytes/words" in your code comments, and that still
doesn't make sense when read out of context.

Looking again at the datasheet, my guess is that HEF is implemented by
the address decoder avoiding the main Flash array for that specific
range. Yet the bytes are probably usable if that range is needed for code.
Post by James Cameron
Um, what if power goes off between erase and write? How are you going
to handle that? I would do it by adding a checksum to the data, and
by writing either the first 64-bytes or the second 64-bytes of the
HEF, and switch between them. That way if the power goes off, you'll
end up with an erased 64-bytes and a usable 64-bytes containing the
previous settings.
I will give "power-failure during an erase/write sequence" further
thought; but honestly, even if bad data is written into flash, it
won't affect anything critical in my application. The device would
simply generate a different tone than the user thought they had
programmed. That's all. And the user will notice that and they can
then just enter program mode again (via DIP switch) and reprogram.
It would be no big deal at all.
Good.
Post by James Cameron
I have actually been giving more thought to VERIFY. The datasheet
mentions that after doing an ERASE-WRITE it's good programming
practice to VERIFY that the written data is correct.
For the application you describe, I don't think it is worth doing a
VERIFY.
Post by James Cameron
So what I was thinking is that if I do a VERIFY and find the written
data is not what should have been written, I could do another
ERASE-WRITE starting at the next block of 32 words,
You have assumed that a VERIFY has failed because of a fault with the
row. That isn't the only cause. Voltages out of spec can do that, as
can heat or ionising radiation. Repeating the erase and write at the
_same_ location would be my response.
Post by James Cameron
which for the 16F1508 would be 0FA0, and if that fails I would try
again doing and ERASE-WRITE at 0FC0, and if that fails, I would try
again at 0FE0, and if that too fails, I could flash an LED to inform
the user there is an internal flash failure, which could remain
until they reset the device. So if each block of 32 words is rated
at 100k ERASE-WRITES, and if I primarily use only one of those
blocks, that switching code would allow auto switching in case one
block failed, effectively giving 400k ERASE-WRITES for my
application. Or at least, I think that's how it would work. But
honestly, the programming mode will likely be used only a few times
and then never again, so even 10k endurance flash should be
sufficient for my application. I am simply using HEF because, well,
why not? :-)
I agree.
Post by James Cameron
Grey text on white background with nag popup. ;-) But otherwise
readable with a bit of manipulation.
Yes, CloudApp has its negatives, but it's free for my purpose and it
allows easy sharing from my Mac. My worry about posting lots of ASM
code to this list via email is the maximum with and line-wrapping.
Code becomes very hard to follow if my comments are wrapped, which
is why I posted the code to CloudApp. There's no fancy highlighting
like in a good text editor, but the spacing and indents are correct.
One minor concern; your code turns off interrupts (INTCON, GIE) but
does not turn them back on. ;-)
By design, yes. I want interrupts OFF until I need them. There are
parts of my code I don't want interrupted, even for the tiny
duration it would take to enter/exit the ISR. But thanks for taking
note of that.
No worries. Coding brain notices imbalances like that. While it is
probably necessary to enforce the cycle timing of the access to erase
and write operations, one would normally at least set it back to what
it was.
Post by James Cameron
Best,
James W.
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
--
James Cameron
http://quozl.netrek.org/
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo
James Wages
2016-09-29 03:09:04 UTC
Permalink
9/29/16, 11:54 AM, "James Cameron" <***@laptop.org>:
You might find __maxrom in the processor include file already.

You're right. Thank you. Here's my modified code:

; -------------------------------
; High Endurance Flash Protection
; -------------------------------
; Make sure Program Memory never overwrites HEF: F80h to FFFh
; Don't need next line because it's already in the p16f1508.inc file.
; __maxrom 0xFFF ; 16F1508 is 4k, so Flash Program Memory goes to FFFh.
__badrom 0xF80 - 0xFFF ; Protect HEF address range.


Thank you for your other detailed help and advice too. I sincerely appreciate it!

--James W.
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
James Wages
2016-09-29 06:31:33 UTC
Permalink
9/29/16, 11:54 AM, "James Cameron" <***@laptop.org>:
You might find __maxrom in the processor include file already.

James C., I just conducted a test and discovered the following 2 things:

1. Even though __maxrom is found inside the p16f1508.inc file, MPASM still coughs up an error at assembly time saying __maxrom must "come first." Technically it does come first because I mention the include file first in my code. But despite that, I still get the MPASM error. But if I unquote that __maxrom line I wrote in my code and then reassemble, then there is no error.

2. I used the following code to see how MPASM would respond to "nop" being written in the HEF address range:

ORG 0xF80 ; Just for an MPASM test
nop

No error resulted at assembly time. Reason? I am using the following line of code to suppress banksel warnings:

errorlevel -302

Commenting out that errorlevel line shows the HEF address warning during assembly time, but failing to use errorlevel -302 results in my poor Error log being filled with 200 messages about banking!

So obviously, I would want to suppress the banksel messages but retain any message that pertains to program code overflowing into the HEF address range. So I guess this MPASM warning is just not possible to implement (without using a linker, which I am not going to use). I will just keep an eye on my code length.

--James W.
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
James Cameron
2016-09-29 13:10:47 UTC
Permalink
Post by James Cameron
You might find __maxrom in the processor include file already.
1. Even though __maxrom is found inside the p16f1508.inc file, MPASM still coughs up an error at assembly time saying __maxrom must "come first." Technically it does come first because I mention the include file first in my code. But despite that, I still get the MPASM error. But if I unquote that __maxrom line I wrote in my code and then reassemble, then there is no error.
ORG 0xF80 ; Just for an MPASM test
nop
errorlevel -302
Can you change the errorlevel just before ORG 0xF80? ;-)
Post by James Cameron
Commenting out that errorlevel line shows the HEF address warning
during assembly time, but failing to use errorlevel -302 results in
my poor Error log being filled with 200 messages about banking!
Heh.
Post by James Cameron
So obviously, I would want to suppress the banksel messages but
retain any message that pertains to program code overflowing into
the HEF address range. So I guess this MPASM warning is just not
possible to implement (without using a linker, which I am not going
to use). I will just keep an eye on my code length.
Still think that IF/ENDIF can be used, as I first said.
--
James Cameron
http://quozl.netrek.org/
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
Bob Ammerman
2016-09-29 13:34:11 UTC
Permalink
Given that you are using absolute mode in the assembler, a line like this:

TOOBIG = 1/($ <= 0xF80)

at the end of your code will generate a divide by zero error at assembly
time if your code exceeds the maximum allowed size.

Pretty sneaky!

~ Bob Ammerman
RAm Systems
-----Original Message-----
Of
James Wages
Sent: Thursday, September 29, 2016 2:32 AM
Subject: Re: PIC16F1508: High Endurance Flash control using Assembly (ASM)
You might find __maxrom in the processor include file already.
1. Even though __maxrom is found inside the p16f1508.inc file, MPASM still
coughs up an error at assembly time saying __maxrom must "come first."
Technically it does come first because I mention the include file first in
my
code. But despite that, I still get the MPASM error. But if I unquote
that
__maxrom line I wrote in my code and then reassemble, then there is no
error.
2. I used the following code to see how MPASM would respond to "nop" being
ORG 0xF80 ; Just for an MPASM test
nop
No error resulted at assembly time. Reason? I am using the following
line of
errorlevel -302
Commenting out that errorlevel line shows the HEF address warning during
assembly time, but failing to use errorlevel -302 results in my poor Error
log
being filled with 200 messages about banking!
So obviously, I would want to suppress the banksel messages but retain any
message that pertains to program code overflowing into the HEF address
range. So I guess this MPASM warning is just not possible to implement
(without using a linker, which I am not going to use). I will just keep
an eye on
my code length.
--James W.
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change
your membership options at http://mailman.mit.edu/mailman/listinfo/piclist
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
a***@stfc.ac.uk
2016-09-28 10:26:45 UTC
Permalink
Post by James Wages
The only thing I still don't know how to do is protect the HEF range of 0F80 to
0FFF using an Assembler directive. So for now I can only try ensure my
Program Code is short enough so it won't reach 0F80. If you have thoughts
on this, please let me know.
Most people would have the assembler code broken up into reusable modules, and then on the linker map have this area reserved. Then you don't need to worry about generating any warnings or anything in the assembly code because the linker barfs with saying there is no room if you try and use that reserved space.
--
http://www.piclist.com/techref/piclist PIC/SX FAQ & list archive
View/change your membership options at
http://mailman.mit.edu/mailman/listinfo/piclist
Loading...