News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

Read from and Writing to SAF

Started by JohnB, Dec 06, 2025, 09:26 AM

Previous topic - Next topic

JohnB

I understand SAF memory is stored in words but is addressed in bytes. When addressing SAF memory do I have to incement the address by 2 or does the compiler handle the addressing.  As far as I can see there are no explicit instructions in the Positron refereance for SAF so I guess the answer is increment the address by 2. 

This is my first attemot to use SAF so any examples wojld be helpful.
JohnB

charliecoutas

John. I have an example to give you but I cannot remember how to post it. I tried dragging but it said only accepts .JPG .TXT etc. I have made it .TXT but still won't accept it.

Charlie

RGV250


charliecoutas


charliecoutas

Try this John. Thanks Bob. Hope it works...

Charlie

JohnB

Thanks very much I'll give it a try.
JohnB

JohnB

Having read your code, I dont think this is the same for the 16F15244 device.  It has an allocated SAF storage area which you have to access through a set of NVM regsters, NVMADR, NVMDAT, NVMCON1 and 2.  You have to unlock it and unlock it like you have ti when using PPS.
JohnB

trastikata

#7
Quote from: JohnB on Dec 06, 2025, 04:07 PMHaving read your code, I dont think this is the same for the 16F15244 device.  It has an allocated SAF storage area which you have to access through a set of NVM regsters, NVMADR, NVMDAT, NVMCON1 and 2.  You have to unlock it and unlock it like you have ti when using PPS.

Maybe this code for 18F27Q83 will give you a hint: https://protoncompiler.com/index.php?msg=22819

Device = 18F27Q83                       
Declare Xtal = 4                               

Declare Auto_Heap_Arrays = On
Dim wPageBuffer[128] As Word At 0x3700         'PIC18Fx7Q83 - BANK 55 = 0x3700 / PIC18Fx6Q83 - BANK 37 = 0x2500
Dim wPageAddress As Word At NVMADRH

Main:
    WriteFlashPage(316)
End
   
'wAddress = FLASH page to be erased
'Result: 0 - page write success
'        1 - erase error   
'        2 - write error
Proc WriteFlashPage(wPageAddress As wPageAddress), Byte
    Dim bTempGIE As Byte       
    Result = 0

    bTempGIE = INTCON0          'Save INTCON0 to temporary Variable
    INTCON0.7 = 0               'Disable GIE
    'Erase page
    NVMCON1 = 0x06              'Set the page erase command
    NVMLOCK = 0x55              'Unlock Sequence 0
    NVMLOCK = 0xAA              'Unlock Sequence 1
    NVMCON0.0 = 1               'Start page erase
    While NVMCON0.0 = 1 : Wend  'Wait for the erase operation to complete
    If NVMCON1.7 = 1 Then       'Verify erase operation success
        NVMCON1.7 = 0           'Clear NVM Erase/Write Error
        Result = 1              'Set Result to Erase Error
        INTCON0 = bTempGIE      'Restore INTCON0 from temporary variable
        NVMCON1 = 0             'Disable writes to memory
        ExitProc                'Exit
    EndIf
    'Write page
    NVMCON1 = 0x05              'Set the page write command
    NVMLOCK = 0x55              'Unlock Sequence 0
    NVMLOCK = 0xAA              'Unlock Sequence 1                     
    NVMCON0.0 = 1               'Start page write
    While NVMCON0.0 = 1 : Wend  'Wait for the write operation to complete
    If NVMCON1.7 = 1 Then       'Verify write operation success
        NVMCON1.7 = 0           'Clear NVM Erase/Write Error
        Result = 2              'Set Result to Write Error
    EndIf
    INTCON0 = bTempGIE          'Restore INTCON0 from temporary variable
    NVMCON1 = 0                 'Disable writes to memory
EndProc   

charliecoutas

I live and learn. Is this a forth type of memory?  EEPROM, Flash, High Endurance and SAF?

Charlie

JohnB

#9
Here is working code for the PIC16F15244
'=================================================================
' SAF Operations
'=================================================================

' Returns with 1 if write succeeds
Proc SAF_Write(Addr As Byte, Dat As Word), Byte
    Dim Adr As Word
    Dim Verify As Word

    Adr = SAF_Base + Addr
    INTCONbits_GIE = 0
    NVMCON1 = 0

    NVMADRL = Adr.LowByte
    NVMADRH = Adr.HighByte
    NVMDATL = Dat.LowByte
    NVMDATH = Dat.HighByte

    ' Configure for SAF write
    NVMCON1bits_NVMREGS = 0
    NVMCON1bits_WREN = 1

    NVMCON2 = $55
    NVMCON2 = $AA
    NVMCON1bits_WR = 1

    Nop
    Nop

    While NVMCON1bits_WR = 1 : Wend

    If NVMCON1bits_WRERR = 1 Then
        NVMCON1 = 0
        INTCONbits_GIE = 1
        Result = 0
        Return
    EndIf

    NVMCON1 = 0
    INTCONbits_GIE = 1
    DelayMS 2

    Verify = SAF_Read(Addr)

    If Verify = Dat Then
        Result = 1
    Else
        Result = 0
    EndIf
EndProc

' Returns with 14bit Word at address ADDR
Proc SAF_Read(Addr As Byte), Word
    Dim Adr As Word

    Adr = SAF_Base + Addr

    NVMADRL = Adr.LowByte
    NVMADRH = Adr.HighByte

    ' Configure for SAF read
    NVMCON1bits_NVMREGS = 0
    NVMCON1bits_RD = 1

    Nop
    Nop

    Result.LowByte = NVMDATL
    Result.HighByte = NVMDATH
EndProc

Proc SAF_Erase()

    INTCONbits_GIE = 0
    NVMCON1 = 0

    NVMADRL = SAF_Base.LowByte
    NVMADRH = SAF_Base.HighByte

    NVMCON1bits_NVMREGS = 0
    NVMCON1bits_FREE = 1
    NVMCON1bits_WREN = 1

    NVMCON2 = $55
    NVMCON2 = $AA
    NVMCON1bits_WR = 1

    Nop
    Nop

    While NVMCON1bits_WR = 1 : Wend

    NVMCON1 = 0
    DelayMS 20
    INTCONbits_GIE = 1

EndProc

And here are some example read/writes

Proc Load_Params()
    If SAF_Read(7) = SAF_Magic_Val Then
        Dir_Servo_Forward = SAF_Read(0)
        Dir_Servo_Neutral = SAF_Read(1)
        Dir_Servo_Back = SAF_Read(2)
        Low_Speed_Threshold = SAF_Read(3)
        High_Speed_Threshold = SAF_Read(4)
        Cooling_Speed_Threshold = SAF_Read(5)
        Motor_Deadzone = SAF_Read(6)
    Else
        Dir_Servo_Forward = Def_Fwd
        Dir_Servo_Neutral = Def_Neu
        Dir_Servo_Back = Def_Bck
        Low_Speed_Threshold = Def_Low
        High_Speed_Threshold = Def_High
        Cooling_Speed_Threshold = Def_Cool
        Motor_Deadzone = Def_Dead
    EndIf
EndProc

Proc Save_Params(),Byte

    SAF_Erase()

    Result = SAF_Write(0, Dir_Servo_Forward)
    If Result = 0 then return
    DelayMS 5

    Result = SAF_Write(1, Dir_Servo_Neutral)
    If Result = 0 then return
    DelayMS 5

    Result = SAF_Write(2, Dir_Servo_Back)
    If Result = 0 then return
    DelayMS 5

    Result = SAF_Write(3, Low_Speed_Threshold)
    If Result = 0 then return
    DelayMS 5

    Result = SAF_Write(4, High_Speed_Threshold)
    If Result = 0 then return
    DelayMS 5

    Result = SAF_Write(5, Cooling_Speed_Threshold)
    If Result = 0 then return
    DelayMS 5  '

    Result = SAF_Write(6, Motor_Deadzone)
    If Result = 0 then return
    DelayMS 5

    Result = Saf_write(7, SAF_Magic_Val )

EndProc

What caught me was the magic number.  I had a magic nuber which occupied 16 bits but we are only reading 14 bits of data.

I should add, if you are using PCKit3+ make sure you have HEF/SAF enabled and that HEF/SAF Automerge are enabled

I Hope they might prove useful
JohnB

charliecoutas

Glad you got it sorted John. Thanks for the examples also.
Charlie