Menu

Using HEFRead and HEFWrite on the 12F1571

Help
mkstevo
2020-05-01
2020-05-06
  • mkstevo

    mkstevo - 2020-05-01

    I am writing a program that uses a 12F1571. This device has HEF data storage, rather than EeProm as I'm used to.

    Whilst I have been waiting for the 12F1571 to be delivered, I have written my program for the 12F1840 which uses EeProm. I have the program all working well until I get to changing the #Chip definition to 12F1571, and adding a conditional compile which changes the use of EeProm, to HEF. All of a sudden, the program no longer fits into the memory of the 12F1571. Comment out only the HEFRead and HEFWrite commands, and I have used about 70% of available program space for the 12F1571, add them back in and the program is too large.

    I thought that there might be some optimisation available for the HEF commands so started to look and see if I could find any but came up empty. It was then that I spotted @evanvennn 's tutorial on the subject and I watched this to see if I could glean any tips.

    When the video got to the section on HEF, it showed the PicKit window, with a small tickbox where HEF/SAF could be enabled or disabled, along with an area that defined the space of HEF/SAF allocated. It struck me that when I selected HEF (by use of the HEFWrite/HEFRead commands) perhaps the compiler was allocating the full 128 words that are available for HEF for use as HEF?

    If this is the case:
    Could I define a smaller section to be allocated (I only need to store one byte)?
    Or, would I be better using ProgramWrite with this set for the "top" value in Program memory, 7FFF?
    Is there any way of programatically writing, and reading, the User ID location?

     

    Last edit: mkstevo 2020-05-01
  • Anobium

    Anobium - 2020-05-01

    Re Great Cow BASIC. EEPROM and HEF from a usage point of view were designed to be interchangeable. So, moving from EEPROM to HEF should be very easy.

    The compiler does not allocate HEF. You need to specify the HEF See #Option ReserveHighProg this will ensure that the compiler does not overwrite the HEF space you allocate. You can only allocated in blocks. Two constants are made available to you.

    ChipHEFMemWords is used within hefsaf.h. This constant provides information with respect to the register used for setting the HEF operations
    HEFMemWords=128

    ChipsEraseRowSizeWords is used within hefsaf.h. This constant provides information with respect to the register used for setting the HEFSAF operations
    EraseRowSizeWords=32

    Could I define a smaller section to be allocated (I only need to store one byte)?
    No. The minimum equates to the constant EraseRowSizeWords

    Or, would I be better using ProgramWrite with this set for the "top" value in Program memory, 7FFF?
    No. Use HEFWrite etc . The block erase and write is all automatic.

    Is there any way of programatically writing, and reading, the User ID location?
    Yes. See https://github.com/Anobium/PICKitPlus/tree/master/R209/UserID_Family19Erase I have the Great Cow BASIC source.... I do not publish Great Cow BASIC source on the PICKit Plus GITHub.


    Hope this all helps.

    @williamroth... anything to add?

     
  • mkstevo

    mkstevo - 2020-05-01

    Thanks for your suggestions.

    It isn't that I'm struggling with the HEFRead/HEFWrite commands themselves. Indeed using HEF is as simple as using EeProm. The trouble is, that the HEF commands appear to use a vast amount of memory, in comparison to the EeProm commands.

    I have this in my code, to make it portable between the 12F1840 and 12F1571:

        #IfDef UseHEF
            HEFRead(StoredVolume,VolumeLevel)
        #EndIf
        #IfDef UseEp
            EpRead(StoredVolume,VolumeLevel)
        #EndIf
    
        then later in the code
    
         #IfDef UseHEF
            HEFWrite(StoredVolume,VolumeLevel)
        #EndIf
        #IfDef UseEp
            EpWrite(StoredVolume,VolumeLevel)
        #EndIf
    

    As you might surmise, this is for storing the volume level for a DfPlayer MP3 controller.

    Here is the result of a series of compilations for the 12F1840.
    With neither UseHEF or UseEP declared: 444/4096 words used. (Same as the 12F1571)
    With UseEp declared: 485/4096 words used.
    With UseHEF declared: 456/4096 words used. As the 12F1840 can't use HEF I presume it was excluded on compile.

    Here is the identical program compiled for the 12F1571.
    With neither UseHEF or UseEP declared: 444/1024 words used. (Same as the 12F1840)
    With UseEp declared: 475/1024 words used. As the 12F1571 can't use EeProm I presume it was excluded on compile.
    With UseHEF declared: 803/1024 words used.

    For the 12F1840, using EpRead/EpWrite used an additional 31 words.
    For the 12F1571, using HEFRed/HEFWrite used an additional 359 words.

    If that is the case, what with the additional calculations required to find the blocks of memory, the erase routines needed before memory can be written to and so on, so be it. It just seemed such a large jump. Especially so as the 12F1571 has rather limited memory to start with.

    If you do have the source for writing to/reading from the User ID and are willing to email it to me, I would be grateful. If I could 'decode' it to write my volume value into that space it would hopefully save some of my precious memory.

    Of course, I could always 'admit defeat' and use the 12F1840.

     
  • mkstevo

    mkstevo - 2020-05-01

    Looking at the assembled program, the routine for HEFRead (and HEFReadBlock) seem to occupy about 120 commands, and that for HEFWrite (and HEFWriteBlock) occupies about 200 commands. These counts do include some of the commented commands. That certainly accounts for much of the 359 words my compilation experiment showed the HEF commands using.

    By contrast, the EpRead command seems to only use around 11 commands, and EpWrite around 27. Again, these counts include the commented commands. As these commands use only 31 commands in the compilation, I guess there are no further commands used for writing/reading EeProm than those I could see.

    So it would seem that the memory is being used by the HEF routines.

    I've managed to trim the program such that it should (just) fit into the 12F1571 once I've added back in some of those routines I initially removed to allow it to compile without exceeding the memory capacity of the device.

    Of course, I hadn't anticipated the program space changing so dramatically between HEF use and EeProm use as much as turned out to be the case. I thought I'd finished and only added the HEFRead/HEFWrite changes as the very last thing I did. I knew it needed to be done, but concentrated on doing everything else first as I could do everything else, and test it on a 12F1840 making sure it worked. Then, finally, added the HEF commands, compiled for the 12F1571 and... Oh dear! I've run out of memory unexpectedly.

     
  • Anobium

    Anobium - 2020-05-01

    I would buy a chip with the memory you need. There are many chips with Eeprom.

     
    • mkstevo

      mkstevo - 2020-05-01

      That's too easy!

      The 12F1840 is a more versatile device, with significantly more memory than the 12F1571, and has EeProm.

      I had designed a circuit which used a 12F1840 but used only a small fraction of the memory when I spotted the 12F1571 which costs half as much. As we are using these in a commercial machine, a few hundred of devices at 41p each is a significant saving over a few hundred at 78p each.

      As I'd already written (most) of the program for this new product design, and knew it only used about 800 words of program I specified the 12F1571 again, confident I'd have plenty of space. Of course, the previous design and program didn't use any EeProm so indeed had no problem in fitting into the 12F1571 as anticipated. This design however, does use EeProm (HEF memory in the case of the 12F1571)...

      You live and learn.

       

      Last edit: mkstevo 2020-05-04
  • Anobium

    Anobium - 2020-05-02

    WeWe need Bill to into the details of the HEF library. The methods use a very different approach to the simple Eeprom write. With HEF to update one byte you need to read the block, erase the block, write the block ( and, maybe verify the block).

    To program the chip is even more complex. To retain the HEF means to read, merge with new Progmem, write and verify.

    EEProm was so easy.

     
  • kent_twt4

    kent_twt4 - 2020-05-02

    Remember back when this first started with Jacques Nilo's original heflash.h library. https://sourceforge.net/p/gcbasic/discussion/629990/thread/e84e263c/#baa6 A write block back then was about 70 words (including the erase row) on a 12f1503.

    A program memory read word , read and write blocks about 100 words for a 12f1822.

     
  • William Roth

    William Roth - 2020-05-02

    EEPROM can be written one byte at a time. This is not the case with HEF. HEF must be written in blocks. But before it can be written the entire block must first be erased (unless it is already erased)

    So to write one byte of HEF the entire block must first be saved to a buffer/array. The byte to be written is written to the buffer, the HEF block is erased , and then the saved HEF block is written back to HEF from the buffer. This is not only slow compared to EEPROM but requires substantial memory becasue of the buffer/array.

    If there is no need to save the existing data in HEF, then it is possible to just erase the block and then re-write it without using a buffer/array. However this would reqire a rewrite of the HEF library and I am not keen to do that.

    If this memory usage is an issue then I suggest either chosing a chip with sufficient memory or chosing using a chip with EEPROM.

    Bill

     
  • mkstevo

    mkstevo - 2020-05-04

    As ever, thanks for all your kind replies. I do realise that the methods of usin HEF involved more work than EeProm, but perhaps not quite how much that difference was.

    Anobium has suggested some improvements which are hoped to save a little space which I will report back on once my 12F1571 are delivered.

    I suppose that lower price has come at a cost. Time.

     
  • mkstevo

    mkstevo - 2020-05-04

    A quick update.
    Anobium suggested directly calling HEFBlockWrite and HEFBlockRead as opposed to HEFRead and HEFWrite.

    This does indeed save some code space.

        #IfDef UseHEF
        'For the 12F1571
            #IfnDef UseOptimisedHEF
                HEFRead(StoredVolume,VolumeLevel)
            #EndIf
            #IfDef UseOptimisedHEF
                HEFReadBlock(StoredVolume,_HEF_Buffer(),HEF_ROWSIZE_BYTES)
                Let VolumeLevel = _HEF_Buffer(0)
            #EndIf
        #EndIf
        'For the 12F1840
        #IfDef UseEp
            EpRead(StoredVolume,VolumeLevel)
        #EndIf
    
        and later in the code...
    
            #IfDef UseHEF
           'For the 12F1571
            #IfnDef UseOptimisedHEF
                HEFWrite(StoredVolume,VolumeLevel)
            #EndIf
            #IfDef UseOptimisedHEF
                Let _HEF_Buffer(0) = VolumeLevel
                HEFWriteBlock(StoredVolume,_HEF_Buffer(),HEF_ROWSIZE_BYTES)
            #EndIf
        #EndIf
        'For the 12F1840
        #IfDef UseEp
            EpWrite(StoredVolume,VolumeLevel)
        #EndIf
    

    With only UseHEF #Define 'd the memory use is: 866 words.
    With the "UseOptimisedHEF" section #Define 'd the memory use is: 798

    This is a saving of 68 words. Not enormous, but on the 12F1571 that amounts to 6.6% of the available space.

    I'm yet to transfer this into a 12F1571 as they've not been delivered yet but I have no reason to imagine it won't work.

     
  • Anobium

    Anobium - 2020-05-04

    The risk you are accepting you managing the addressing - it is a good solution for this but could be bad for those who do not know that the buffer is managed by the routines you are skipping around.

    Change the chip.

     
  • William Roth

    William Roth - 2020-05-04

    The PIC12F1572 doubles both the Prpgram Memory and the RAM of the 12F1751 . Here in the US it costs about 6 -10 cents more, depending upon the package and the volume.

    I usually do initial develpment with a chip that has lots of memory and lots of pins but with the same peripherals and features that Ithink are needed.

    Then, after the code is done and a prototype is working on a breadboard, I select the chip to be used in the final product. But before committing to a large order I get my hands on a few samples or make a small order and test to make sure all is good.

    Bill

     
  • mkstevo

    mkstevo - 2020-05-04

    Again. Thanks for all the input.

    As much as anything, it was the surprise at the difference between the program size using EPRead and EpWrite to a program using HEFRead and HEFWrite that caused my first question.

    None of this was intended as a compliant, or criticism, simply a desire to minimise the memory usage by the largest amount possible.

    Having never used HEF memory before, I thought I'd made some mistake initially.

    For the time being, taking Anobium's and William's advice, I'll stick to the standard HEFRead/HEFWrite.

     
  • kent_twt4

    kent_twt4 - 2020-05-04

    A couple of brainstorming ideas, not knowing exactly what is being saved and how often it needs to be saved. 1- Wear leveling by also saving a byte for a counter that would cycle through however many rows of HEF there is on the chip. 2- An off time bleed capacitor setup that allows time to transfer value(s) from ram to eeprom on shutdown.

     
  • mkstevo

    mkstevo - 2020-05-04

    This is for storing the audio volume level of a static piece of semi-industrial equipment. Not expected to change more than a few times a month, if that.

    Regarding life, I had been led to believe that HEF memory had near unlimited write cycle lifetime? Perhaps I just dreamt that?

    As an educative exercise, I tried using ProgramWrite/Read/Erase. This initially failed to compile due to incompatibilities in the eprom.h file and the 12F1571. I then copied the assembler from the Microchip data sheet into my program and compiled this which (after some jiggling) did compile. Spurred on by this, I then studied the reasons why compilation failed using the standard ProgramWrite/Read/Erase routines and re-wrote these to suit the specific requirements of the 12F1571.

    Using this has allowed me to build the program, with the (single byte) storage I wanted, occupying 548 words, rather than 803. Still more than the 485 that the 12F1840 uses with EpWrite/Read, but a big improvement, and well worth my efforts.

    There is a further overhead on top of this for the reserved memory area of 16 words using: #Option ReserveHighProg 16. ProgramErase erases a "block" that is 16 words in size. Using ReserveHighProg 16 ensures that if the program encroaches into the last 16 words of memory, when compiled, it will show a program too large error. That way I am less likely to erase part of my program with ProgramErase. Which is of course why HEFWrite saves the existing contents first, erases, and then writes the original values and the changed values back into the HEF memory. I simply write my value into the top word of memory, having erased all 16 words before it first.

     

    Last edit: mkstevo 2020-05-08
  • kent_twt4

    kent_twt4 - 2020-05-04

    Sounds like you found your solution, good job. I had previously used the same method on program write procedure, amongst others.

     
  • mkstevo

    mkstevo - 2020-05-06

    To round out this thread.

    The problems using ProgramWrite (and ProgramErase and ProgramRead) on the12F1571 I remarked upon earlier have been identified, fixed and will hopefully be included in the next release of GreatCowBasic.

    Many thanks to all who helped.

     

    Last edit: mkstevo 2020-05-08

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.