News:

Let's find out together what makes a PIC Tick!

Main Menu

Dreaded DFM!!

Started by JonW, Oct 04, 2022, 11:32 AM

Previous topic - Next topic

JonW

On my oh my, DFM writing, reading... I need around 10kb of Calibration dataspace and almost got the point that I was going to use external rather than internal flash!  I thought it was going to be easy to write some procs for reading and writing DFM on the 26K42.  Bad start referencing the K22 datasheet DOH (in error) and it actually almost worked on a K42 even with different register names.  After realising and getting the correct datasheet, understanding how it functions is not easy, getting your head around the boundaries due to the freaky table pointers from the datasheet explanation is a challenge.  The datasheet is all over the place and confusing with respect the the Table pointer and how it works with the TABLAT (presume this is a shift register).

Finally managed to get it all working and will share the procedures as an include file  if you guys want it once its tidied up.

Procedure list

ADDR is Long variable, DATA is byte

ERASE128(ADDR)                 ' Erases 64 word block on 128 byte boundary
WRITE128(ADDR)                 ' Erases and Writes a 128 block from an array to a 128 byte boundary
FLASHWRITE(ADDR,DATA)   ' Writes a single byte to DFM (reads 128 bytes to an array, erases the flash, updates the byte and writes  the128 bytes block back to DFM) .. is fairly slow for 1000's of individual writes
FLASHREAD(ADDR)              '   Reads a single address from DFM


JonW

#1
Here the example

'*******************************************************************
'* Name    : FLASHTEST                                          *
'*  Author  : JON WALKER                                          *
'*  Notice  : Copyright (c) 2022 ELECIUM LTD                      *
'* Version  :  0.0.0.3                                            *
'*  Date    : 04/10/2022                                          *
'*                                                                *
'*  Version : 0.1                                                  *
'*******************************************************************
Device = 18F26K42
;-------------------------------------------------------------------------------
; NOTES
;
;-------------------------------------------------------------------------------

Declare Optimiser_Level = 0
Xtal = 64                                ' using pll at full speed (62.5nS/instruction)
Declare Hserial_Baud = 115200            ' Set baud rate to 115200
Declare Hserial_RCSTA = %10010000        ' Enable serial port and continuous receive
Declare Hserial_TXSTA = %00100100        ' Enable transmit and asynchronous mode
Declare Hserial_Clear = On                ' Enable Error clearing on received characters
Declare Float_Display_Type = Fast        ' Use the more accurate and faster Floating Point conversion internal library routine
Declare Access_Upper_64K = True          ' Set the compiler to see all 128K of flash memory
Declare Auto_Variable_Bank_Cross = On    ' Enable multi-byte variables to stay in the same RAM bank



'-------------------------------------------------------------------------------------
'                          Includes
'-------------------------------------------------------------------------------------
Include "K42FLASHWRITE.INC"
'-------------------------------------------------------------------------------------
'                          Port Alias
'-------------------------------------------------------------------------------------
'
Dim APIN    As LATA.0

'-------------------------------------------------------------------------------------
'                          Variable Declarations
'-------------------------------------------------------------------------------------

Dim FLASHDATA        As Byte Heap
Dim FLASHADDR        As Long Heap

'-------------------------------------------------------------------------------------
'                          LOCAL PROCEDURES
'-------------------------------------------------------------------------------------

'-------------------------------------------------------------------------------------
'                          SET UP PIC
'-------------------------------------------------------------------------------------

SETUP:
        INTCON0.7 = 0          ; Disable ints
        ANSELA = 0
        ANSELB = 0
        ANSELC = 0
        CM1CON0 = 0
        T3CON =    %00000000
        TRISA =    %00000000  ; ALL OUTPUT
        TRISB =    %00000010  ;
        TRISC =    %10001000  ;
        WPUA =      %00000000  ; NO PULLUPS
        WPUB =      %00000000  ; NO PULLUPS
        WPUC =      %00000000  ; NO PULLUPS

RESET_:
        GoTo MAINSTART


;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;                                  START OF MAIN PROGRAM
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

MAINSTART:
        FLASHDATA = 0
        For FLASHADDR = 10001 To 10105                ' WRITE A NUMBER OF ADDRESSES INDIVIDUALLY
            FLASHWRITE(FLASHADDR,FLASHDATA)
            Inc FLASHDATA
        Next

        For FLASHADDR = 10001 To 10105                ' READ ADDRESSES AND SENT TO SERIAL PORT
            FLASHDATA = FLASHREAD(FLASHADDR)
            HRSOut "ADDR: ", Dec5 FLASHADDR," DATA: ",Dec3 FLASHDATA,13,10
        Next

        DelayMS 3000
        HRSOut "------------------------------------------------------",13,10
        GoTo MAINSTART



;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;                                  Configs
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Config_Start
  FEXTOSC = OFF              ;Oscillator not enable
  RSTOSC = HFINTOSC_64MHZ    ;HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:
  CLKOUTEN = OFF            ;CLKOUT function is disable
  PR1WAY = On                ;PRLOCK bit can be cleared and set only onc
  CSWEN = On                ;Writing to NOSC and NDIV is allowe
  FCMEN = On                ;Fail-Safe Clock Monitor enable
  MCLRE = INTMCLR            ;If LVP = 0, MCLR pin function is port defined function; If LVP =1, RE3 pin fuction is MCL
  PWRTS = PWRT_OFF          ;PWRT is disable
  MVECEN = On                ;Multi-vector enabled, Vector table used for interrupt
  IVT1WAY = On              ;IVTLOCK bit can be cleared and set only onc
  LPBOREN = OFF              ;ULPBOR disable
  BOREN = SBORDIS            ;Brown-out Reset enabled , SBOREN bit is ignore
  BORV = VBOR_2P45          ;Brown-out Reset Voltage (VBOR) set to 2.45
  ZCD = OFF                  ;ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCO
  PPS1WAY = On              ;PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycl
  STVREN = On                ;Stack full/underflow will cause Rese
  Debug = OFF                ;Background debugger disable
  XINST = OFF                ;Extended Instruction Set and Indexed Addressing Mode disable
  WDTCPS = WDTCPS_31        ;Divider ratio 1:65536; software control of WDTP
  WDTE = OFF                ;WDT Disabled; SWDTEN is ignore
  WDTCWS = WDTCWS_7          ;window always open (100%); software control; keyed access not require
  WDTCCS = SC                ;Software Contro
  BBSIZE = BBSIZE_512        ;Boot Block size is 512 word
  BBEN = OFF                ;Boot block disable
  SAFEN = OFF                ;SAF disable
  WRTAPP = OFF              ;Application Block not write protecte
  WRTB = OFF                ;Configuration registers (300000-30000Bh) not write-protecte
  WRTC = OFF                ;Boot Block (000000-0007FFh) not write-protecte
  WRTD = OFF                ;Data EEPROM not write-protecte
  WRTSAF = OFF              ;SAF not Write Protecte
  LVP = On                  ;Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignore
  Cp = OFF                  ;PFM and Data EEPROM code protection disable
Config_End

'**** End of Fuse Configurator Settings ****
'-------------------------------------------------------------------------------


Include file

(*************************************************************************************************
* Name      :  C:\MWAVE\MWAVE_MICRO\K42FLASHWRITE..INC                                              *
* Author    :  JON WALKER                                                                        *
* Copyright :  MWAVE LTD                                                                        *
* Version  :  0.0.0.1                                                                          *
* History  :  INITIAL RELEASE                                                                  *
* Notes    :  K42 DFM WRITES IN 128BYTE BLOCKS, CAN WRITE 128BYTES STARTING AT ANY LOCATION    *
'*************************************************************************************************)



' Global Variables

Dim b_FLASH128[128] As Byte Heap  ' ARRAY FOR 128 BYTES TO STORE IN FLASH MEMORY  (KEEP AT TOP)
Dim b_LD1          As Byte Heap  ' COUNTER VARIABLE
Dim b_GIESTORE      As Bit        ' STORAGE FOR GIE BIT

(********************************************************************************************
* Title    :  UNLOCKDFM (UNLOCK THE DATA FLASH)                                            *
* Input    :  FLASH ADDRESS                                                                *
* Output    :  FLASH CONTENT                                                                *
* Notes    :  26/27K42                                                                    *
********************************************************************************************)
Proc UNLOCKDFM()
        NVMCON2 = $55                        ' Required Writes
        NVMCON2 = $AA                        ' Required Wrtits
        NVMCON1.1 = 1                        ' Set WRITE CONTROL BIT
EndProc

(********************************************************************************************
* Title    :  READADDR                                                                    *
* Input    :  FLASH ADDRESS                                                                *
* Output    :  FLASH CONTENT                                                                *
* Notes    :  26/27K42    READS A SINGLE BYTE FROM ADDRESS                                *
********************************************************************************************)
Proc FLASHREAD(ADDR As Long),Byte

      TBLPTRL = ADDR.Byte0                    ' LOAD THE POINTERS
      TBLPTRH = ADDR.Byte1
      TBLPTRU = ADDR.Byte2
      Asm
        Tblrd*                                ' INITIATE A READ
      EndAsm
      Result = TABLAT                        ' RETURN DATA
EndProc

(********************************************************************************************
* Title    :  FLASHWRITE                                                                  *
* Input    :  FLASH ADDRESS, BYTE TO WRITE                                                *
* Output    :  NONE                                                                        *
* Notes    :  26/27K42 UPDATE 1 BYTE IN DFM (CAN WRITE TO ANY LOCATION)                    *
*********************************************************************************************)
Proc FLASHWRITE(ADDR As Long, B2LOAD As Byte )

    Dim b_STORE As Byte                            ' NEED A TEMPORY BYTE TO STORE THE ADDR.BYTE0

    b_store = ADDR.Byte0                          ' SAVE THE LOWBYTE ADDRESS
    ADDR.Byte0 = ADDR.Byte0 & b'10000000'          ' MASK BIT 7

    For b_LD1 = 0 To 127                          ' EXTRACT 128 BYTES AT BOUNDARY INTO ARRAY
        b_FLASH128[b_LD1] = FLASHREAD(ADDR + b_LD1)
    Next

    ADDR.Byte0 = b_StORE                          ' REPLACE THE LOWBYTE
    b_LD1 = ADDR.Byte0                            ' EXTRACT THE BYTE TO WRITE
    b_LD1.7 = 0                                    ' MASK THE UPPER BIT
    b_FLASH128[b_LD1] = B2LOAD                    ' UPDATE THE BYTE IN THE ARRAY
    WRITE128(ADDR)                                ' FLASH THE WHOLE 128 BYTE BLOCK
EndProc


(********************************************************************************************
* Title    :  WRITE128                                                                    *
* Input    :  FLASH ADDRESS  (ONLY WRITES TO 128 BYTE BOUNDARIES)                        *
* Output    :  NONE                                                                        *
* Notes    :  26/27K42 ERASES AND WRITES 128 BYTES TO FLASH MEM FROM FLASH64[] ARRAY      *
*********************************************************************************************)
Proc  WRITE128(ADDR As Long)

      ERASE128(ADDR)              ' ERASE 128  '
      TBLPTRL = 0                ' PREP TABLAT ARRAY

      For b_LD1 = 0 To 127        ' LOAD THE TABLAT ARRAY (128 BYTES)
          TABLAT = b_FLASH128[b_LD1]
          Asm
          Tblwt*+                ' LOAD AND INCREMENT THE TBLPTRL
          EndAsm
      Next

      TBLPTRL = ADDR.Byte0        ' NOW POINT TO THE ADDRESS TO WRITE
      TBLPTRH = ADDR.Byte1
      TBLPTRU = ADDR.Byte2

      b_GIESTORE = INTCON0.7    ' BACKUP INT STATUS
      INTCON0.7 = 0  ' DISABLE INTERRUPTS
      NVMCON1.7 = 1  ' ACCESS FLASH MEMORY
      NVMCON1.6 = 0  ' ACCESS FLASH (NOT CONFIG)
      NVMCON1.2 = 1  ' ENABLE WRITE TO MEM
      UNLOCKDFM()    ' UNLOCK DFM
      Nop            ' REQUIRED
      NVMCON1.2 = 0  ' DISABLE WRITE TO MEM
      INTCON0.7 = b_GIESTORE  ' RETURN INT STATUS
EndProc

(********************************************************************************************
* Title    :  ERASE128                                                                    *
* Input    :  FLASH ADDRESS                                                                *
* Output    :  NONE                                                                        *
* Notes    :  26/27K42 ERASES  64 WORDS OF DFM  (ADDR NEEDS TO BE ON 128BYE BOUNDARY)      *
*********************************************************************************************)
Proc  ERASE128(ADDR As Long)  ' KEEP THIS PROC SEPERATE SO WE CAN ERASE ANY 64-BYTE BLOCK

      TBLPTRL = ADDR.Byte0
      TBLPTRH = ADDR.Byte1
      TBLPTRU = ADDR.Byte2
      b_GIESTORE = INTCON0.7

      INTCON0.7 = 0  ' DISABLE INTERRUPTS
      NVMCON1.7 = 1  ' ACCESS FLASH MEMORY
      NVMCON1.6 = 0  ' ACCESS FLASH (NOT CONFIG)
      NVMCON1.2 = 1  ' ENABLE WRITE TO MEM
      NVMCON1.4 = 1  ' ERASE BLOCK
      UNLOCKDFM()    ' UNLOCK DFM
      Nop            ' REQUIRED
      NVMCON1.2 = 0  ' DISABLE WRITE TO MEM
      INTCON0.7 = b_GIESTORE  ' RETURN INT STATUS
EndProc

Not added any verification routines just to keep it simple


HAL

Hello Jon

Thank you for posting your code.  I am relatively new at this, thus posts give me a chance to learn by example.   
One question I have is related to the main program under the includes section. 
Should the statement:  Include "K42FLASHWRITE.INC" be Include K42FLASH64.INC instead?

Thank you in advance  HLD

JonW

Hi Hal
Sorry that is a typo in the header.  You just need to call it the same as its saved name so in this case I had saved it as K42FLASHWRITE.INC

Post has been updated too

Cheers
J

HAL

Hi Jon
Thanks again!   These posts do help in the learning process "at least for me".
I try to look at most every day or two. 
I am trying to escape my KiCad addiction and get back to learning Positron...;-)
Best regards
Hal