News:

;) This forum is the property of Proton software developers

Main Menu

HEF read-write help

Started by Maxi, Jun 10, 2026, 04:02 PM

Previous topic - Next topic

Maxi

Hello everyone.
I hope you're all well.
I've had to read-write with the HEF side for the first time (pic16F1575)

I don't understand why this is so difficult? have I missed something?

Isn't there a command similar to the classic and reliable `ewrite` and `eread` commands for this?

I'm at a loss as to what to do – how can I write and read values such as bits, bytes, words, floats and double words?

xvovanx

#1
Please check the datasheet, and you will see that your microcontroller does not have EEPROM memory; it only has flash memory, but flash memory is more complicated to work with.

Maxi

Quote from: xvovanx on Jun 10, 2026, 05:58 PMPlease check the datasheet, and you will see that your microcontroller does not have EEPROM memory; it only has flash memory, but flash memory is more complicated to work with.

Hi, I started this thread because I know there isn't an EEPROM.

Stephen Moss

Quote from: Maxi on Jun 10, 2026, 04:02 PMIsn't there a command similar to the classic and reliable `ewrite` and `eread` commands for this?
Have you used the forums search facility to look for a solution as I seem to recall dealing with HEF having been mentioned before.

Maxi

Quote from: Stephen Moss on Today at 08:08 AM
Quote from: Maxi on Jun 10, 2026, 04:02 PMIsn't there a command similar to the classic and reliable `ewrite` and `eread` commands for this?
Have you used the forums search facility to look for a solution as I seem to recall dealing with HEF having been mentioned before.

Yeah, yeah, I looked, but there's so much conflicting information out there, no any clear answer
or maybe I just couldn't find it :(

charliecoutas

#5
I don't know if this will help, but I was struggling to use HEF. Some kind forum member (can't remember who) showed me how. The code below uses it. See Read_HEF() and Write_HEF() procedures.

Charlie.

(*  This is "IntelliPot" An encoder drives a DAC which is the source for power setting. The encoder is sensitive to the speed at which it is turned.
    Two ranges are provided: coarse and fine. Pressing the encoder toggles between the two ranges
   
    We have a 12 Bit DAC with int Ref of 2.048v: MCP4821 Farnell 1439421  There is a 16 bit DAC which we might consider: MAX5216 Instr
    It can produce a max o/p voltage of 4.09 volts
    This is then multiplied by 2.5 with an op-amp on the same board                                                                                                                                                                         

                16F1704
                =======
          1 Vcc        GND    14 
          2 RA5        RA0/DAT 13
          3 RA4        RA1/CLK 12
          4 RA3/MCLR  RA2    11 
          5 RC5        RC0    10 
          6 RC4        RC1    9   
          7 RC3        RC2    8
                 
05.09.24 Working well. If more bits of DAC are reqd, try MAX5216 for 16 bits and MAX5214 for 14. They need an external ref, say 4.096V?
                                                        MAX5214/MAX5216
08.09.24 Decided to change to a 16 bit DAC:MAX5216. The serial interface needs changing, keep the old one just in case (we have several PCBs for 12 bit vsn)
        This is the 16 bit vsn: 10V/65536=153uV per step  We will need to change the update amounts, do it when we have the new board running
        The MAX5216 needs ext ref, we use 4.096V
       
20.09.24  WE NEED TO DEAL WITH MAX SIZE OF 16 BIT WORD to see when it overflows - done
25.09.24  The 16 bit DAC vsn works well. Added a feature where pressing the encoder for more than 1.5 seconds sets a mid-point voltage                                                                       
24.11.24  Improved so that a period of 4 second must elapse with no encoder moves, before the current DAC value is written to Flash memory.
          That value will be restored when the unit is next powered up. We are using the High Endurance Flash Memory which lives at the end
          of conventional flash. Each entry in the table is 14 bits so only bytes can sensibly be used
27.11.24  PCB which used to work fine didn't work! It was a pcb track on the solder side which failed to link o/p of DAC with op-amp pin 3
          Wire link installed an now works fine. The HEF memory works very well
          If endurance of HEF is 100K then 100Kx4=4.63 days of changing encoder every 4 seconds       
*)                                               

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Device = 16F1704                                                       

Config1 FOSC_INTOSC, WDTE_OFF, PWRTE_ON, MCLRE_OFF, CP_OFF, BOREN_OFF, CLKOUTEN_OFF, IESO_OFF, FCMEN_OFF
Config2 WRT_OFF, PLLEN_ON, STVREN_OFF, LVP_OFF

    Declare Xtal = 32
    On_Interrupt int
 
    Symbol  GIE        INTCON.7

    Symbol  DAC_CE      PORTC.4
    Symbol  DAC_SDI    PORTC.2
    Symbol  DAC_CLK    PORTC.1
    Symbol  Enc_1      PORTA.5
    Symbol  Enc_2      PORTA.4
    Symbol  Enc_sw      PORTC.5                   

    Symbol  PageSize    32                                              ;size of HEF area must be 32 or greater

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   
    Dim    bCounter    As Byte
    Dim    HEF_Area[PageSize] As Byte                                           
    Dim    wFlashWritePosition As Word
   
    Dim    New_Vset_val As SDword                                      ;only bottom 16 bits ready to load into the DAC - top 16 used to check >65535
    Dim    DAC_Load_Wd  As Word                                        ;..get transferred to here
    Dim    Long_press  As Word
    Dim    Enc_pos      As SByte
    Dim    Enc_current  As Byte                                        ;curent posn of enc A.4 and A.5
    Dim    Enc_old      As Byte                                        ;prev posn of    ..  ..  ..  ..
    Dim    Click_rate  As Byte                                        ;count of encoder clicks per 100mS period
    Dim    Peak_rate    As Byte
    Dim    Update      As Word                                        ;this gets added on to the DAC value + or -
    Dim    Millisecs    As Byte                                        ;1mS timer counts in here
    Dim    Idle_Roller  As Byte                                        ;rolls over every 0.25S
    Dim    Idle_Time    As Byte                                        ;counts 0.25S periods where nothing happens
    Dim    Enc_toggle  As Bit                                        ;coarse/fine
    Dim    Enc_moved    As Bit
    Dim    New_DAC_ready As Bit                                        ;a new setting is ready to go to the DAC
    Dim    Timeout      As TMR1L.Word                                  ;so we can load a 16 bit value in one hit 

    Symbol  TMR1IE      PIE1.0                                        ;T1 interrupt enable
    Symbol  TMR1IF      PIR1.0                                        ;T1    ..    flag
    Symbol  TMR1_Run    T1CON.0                                        ;T1 run/stop
     
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                   

        OSCCON = %11110000                                              ;PIC runs at 32Mhz with these settings - 8Mhz clock 4xPLL 125nS per instruction
        WPUA = %00110000                                                ;PORT A input pull-ups enabled
        WPUC = %00100000                                                ;PORTC 5 is encoder switch
        OPTION_REG = %00000000                                          ;enable the pull-ups on PORTA
        TRISA = %00111100                                              ;4 and 5 are inputs
        TRISC = %11101000
        Clear
                                                                     
        T1CON = %00110000                                              ;Timer 1 instr clk, 1:8 prescale, sec osc disabled, no sync, 16 bit write, stop
        TMR1IE = 1                                                      ;let it interrupt
        INTCON.6 = 1                                                    ;set PEIE
        Timeout = $FE10                                                ;preload timer1
        TMR1_Run = 1                                                    ;runs continuously       
                         
        DAC_CLK = 1                                                    ;clock idles HIGH      I think???
       
        DAC_CE = 0                                                      ;I've had todo this with other DACs to get them to work
        DelayUS 20
        DAC_CE = 1
             
        DelayMS 200
       
        Enc_old.0 = PORTA.4                                            ;remember encoder posn now
        Enc_old.1 = PORTA.5         

        T1CON = %00110000                                              ;Timer 1 instr clk, 1:8 prescale, sec osc disabled, no sync, 16 bit write, stop
        TMR1IE = 1                                                      ;let it interrupt
        INTCON.6 = 1                                                    ;set PEIE
        Timeout = $FE10                                                ;preload timer1
        TMR1_Run = 1                                                    ;runs continuously       

        New_Vset_val = 0                                                ;set the DAC first
        New_DAC_ready = 1                                              ;the code below will cycle the DAC and get the previous value restored
        Click_rate = 0
       
        wFlashWritePosition = $0F80                                    ;address of the High Endurance area
       
        Read_HEF()                                                      ;read the HEF from the chip
        New_Vset_val.Byte0 = HEF_Area
[o]                                ;preset the previous value at last power-down
        New_Vset_val.Byte1 = HEF_Area[1]
 
        GIE = 1                                                        ;allow interrupts
        Enc_pos = 0
           
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Main Run ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~     
       
        While
              If New_DAC_ready = 1 Then                                ;is a new setting available?
                  New_DAC_ready = 0                                    ;clear flag
                 
                  DAC_CE = 0                                            ;enable the DAC
                  DAC_Load_Wd.Byte1 = New_Vset_val.Byte1
                  DAC_Load_Wd.Byte0 = New_Vset_val.Byte0                ;just load the bottom 16 bits
                 
                  SHOut DAC_SDI, DAC_CLK, MsbFirst_H, [%01\2, DAC_Load_Wd\16, %000000\6] ;16 bit vsn: 2 control, 16 data, 6 zeroes - see data sheet
                               
                  DAC_CE = 1                                            ;disable it 
              EndIf
             
              DelayMS 1
             
              If Enc_sw = 0 Then
                Toggle Enc_toggle
                Repeat
                Until Enc_sw = 1                                        ;debounce the encoder button
              EndIf
         
              If Idle_Time > 16 Then                                    ;has 4 seconds gone by with no action on encoder?

;It is also worth noting that bottom of each high-endurance cell can be used only to hold an 8-bit value (bootom 8 bits), whereas the
;standard Flash memory will hold 14 bits of information per word
   
                HEF_Area
[o]= DAC_Load_Wd.Byte0                        ;put current DAC value into HEF area
                HEF_Area[1] = DAC_Load_Wd.Byte1                        ; ..    ..
               
                Write_HEF()                                            ;write the HEF area back to the chip (erase theh write several words
               
                Idle_Time = 0                                          ;clear timer
                Enc_moved = 0                                          ;don't allow 0.25S timer until encoder has moved
              EndIf 
                           
        Wend

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
Proc Test_DAC()                                                        ;diagnostic only - not usually used
        While
                  DAC_CE = 0                                            ;enable the DAC
                  DAC_Load_Wd.Byte1 = New_Vset_val. Byte1
                  DAC_Load_Wd.Byte0 = New_Vset_val.Byte0                ;just the bottom 16 bits
                 
                  SHOut DAC_SDI, DAC_CLK, MsbFirst_H, [%01\2, 65535\16, %000000\6]    ;16 bit vsn: 2 control, 16 data, 6 zeroes - see data sheet
                                                                                      ;65535 should give 4.096 volts - and it does!!!
                  DAC_CE = 1                                            ;disable it
                  DelayMS 100
        Wend
EndProc

Proc Read_HEF()                                                        ;this reads a page of HEF in a buffer
        For bCounter = 0 To PageSize - 1                                ;Read FLASH page to buffer
          HEF_Area[bCounter] = CRead ((wFlashWritePosition / PageSize) * PageSize + bCounter)
        Next
EndProc

Proc Write_HEF()
        GIE = 0                                                        ;stop interrupts
        CErase ((wFlashWritePosition / PageSize) * PageSize)            ;Erase Flash page
        DelayMS 12

        For bCounter = 0 To PageSize - 1                                ;Write Flash page back
          CWrite ((wFlashWritePosition / PageSize) * PageSize + bCounter), [HEF_Area[bCounter]]
        Next
        DelayMS 12                                                      ;wait for cpu to actually write array
        GIE = 1                                                        ;allow ints again
EndProc

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         
int:      Context Save                                                ;timer1 is only source of interrupt
             
            If TMR1IF = 1 Then                                          ;Timer 1 has expired  (1mS duration)
                TMR1IF = 0                                              ;clear int
                Timeout = $FE10                                        ;reload timer0 to give next 1mS interval
               
                If Enc_sw = 0 Then                                      ;count the number of millisecs the enc button is pressed for
                  Enc_moved = 1                                        ;allow timing of 4 secs for non-volatile store to kick in (HEF)
                  Inc Long_press
                  If Long_press > 1500 Then
                      New_Vset_val = 32768                              ;output to half way
                      Enc_toggle = 0                                    ;set coarse
                      DAC_CE = 0                                        ;enable CE
                      SHOut DAC_SDI, DAC_CLK, MsbFirst_H, [%01\2, New_Vset_val\16, %000000\6] ;load the DAC
                      DAC_CE = 1                                        ;disable CE
                  EndIf 
                  Else
                  Long_press = 0
                EndIf 
               
                If Enc_moved = 1 Then                                  ;only start timing the idle period when the encoder has moved
                  Inc Idle_Roller
                  If Idle_Roller = 0 Then
                      Inc Idle_Time                                    ;increment every 256 millisecs, so the units are quarter-seconds
                  EndIf
                EndIf
                 
                Select Millisecs                                        ;this new code writes the DAC value to Flash when nothing has happened for a while
                    Case < 255                                          ;don't let it go beyond 255
                      Inc Millisecs
                EndSelect

                Enc_current.0 = PORTA.4                                ;set the encoder current values for A.4,5
                Enc_current.1 = PORTA.5
         
                If Enc_current != Enc_old Then                          ;has it actually moved? 
                      If Enc_old = 1 And PORTA & %00110000 = 0 Then Inc Enc_pos
                      If Enc_old = 2 And PORTA & %00110000 = 0 Then Dec Enc_pos
                      Enc_old.0 = PORTA.4                              ;remember posn now
                      Enc_old.1 = PORTA.5         
                      Inc Click_rate                                  ;one more click in this period
                      Enc_moved = 1                                    ;encoder has moved so we can start timimg idle period
                      Idle_Time = 0                                    ;cancel idle time (no of 025S periods where nothing happened to encoder)
                EndIf                   
               
                If Millisecs > 250 Then                                ;are we ready to apply this 250mS period?
                                     
                    If Click_rate > Peak_rate Then                      ;diagnostic only
                      Peak_rate = Click_rate
                    EndIf 
                   
                    If Enc_toggle = 0 Then                              ;coarse/fine selection - coarse 
                      Select Click_rate                                ;number of times the encoder has clicked in the last 250mS - coarse range
                          Case > 8
                            Update = 400                              ;lots
                          Case > 7
                            Update = 200;60 
                          Case > 5                                      ;quite a few
                            Update = 90
                          Case > 4                                      ;not too many
                            Update = 60
                          Case > 2
                            Update = 6
                          Case Else                                    ;slow
                            Update = 1
                      EndSelect
                      Else                     
                      Select Click_rate                                ;number of times the encoder has clicked in the last 250mS - fine range
                          Case > 8
                            Update = 6
                          Case > 7
                            Update = 4 
                          Case > 5                                      ;quite a few
                            Update = 3
                          Case > 4                                      ;not too many
                            Update = 2
                          Case > 2
                            Update = 1
                          Case Else                                    ;slow'ish
                            Update = 1
                      EndSelect                     
                    EndIf
                     
                    New_Vset_val  = New_Vset_val + (Enc_pos * Update)  ;calculate the amount to change: steps x update rate
                   
                    Select New_Vset_val                                ;check if still within range
                        Case > 65535
                          New_Vset_val = 65535
                        Case < 0
                          New_Vset_val = 0
                    EndSelect
         
                    New_DAC_ready = 1                                  ;indicate that a new setting is available
                    Click_rate = 0
                    Millisecs = 0                                      ;reset 0.1Sec timer
                    Enc_pos = 0
                       
                EndIf
            EndIf
                                     
          Context Restore                                              ;out

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



TimB

In case its any good for you

This is for the 12f1572

    Proc Unlock_Flash()
        PMCON2 = 0x55
        PMCON2 = 0xAA
        PMCON1bits_WR = 1
        NOP
        NOP

    ENdProc


    Proc EraseFlashRow(pAddress as word)

        PMCON1bits_CFGS = 0
        PMCON1bits_FREE = 1
        PMCON1bits_WREN = 1
        rPMADDRESS = pAddress
        Unlock_Flash()

        PMCON1bits_WREN = 0

    EndProc



    Proc WriteThresholds(pThesholdVal as word, pDACLevel as byte)

        EraseFlashRow(cCurrentThrsholdAddrs)                                    ' Erase the row the threshold is on

' Write the ADC thrshold level

        PMCON1bits_CFGS = 0
        PMCON1bits_FREE = 0                                                     '
        PMCON1bits_WREN = 1

        PMCON1bits_LWLO = 1

        rPMAddress = cCurrentThrsholdAddrs
        rPMData = pThesholdVal

        Unlock_Flash()

        rPMAddress = cCurrentDACThrsHoldAddrs
        rPMData = pDACLevel

        Unlock_Flash()

        PMCON1bits_LWLO = 0
        Unlock_Flash()
        PMCON1Bits_WREN = 0

    EndProc