Menu

Problems storing a Long variable in Eeprom

mkstevo
2017-09-15
2017-09-15
  • mkstevo

    mkstevo - 2017-09-15

    Hello.
    I'm attempting to store a "Long" variable value in Eeprom. I only need values upto about 15,000,000 so I'm splitting my "Long" variable across three byte Eeprom locations. My problem is that while checking to see if my maths is correct, my Long variable resets back to zero upon reaching 65536. I have triple checked that I've declared my variables as Long not Word, I have re-written the program a few times to try to eliminate any silly typos, but I just can't see where I'm going wrong.

    I'm stumped.

    Assuming this is due to a problem with my logic, can anyone suggest how I can store and recall a value of 15,000,000 or thereabouts in Eeprom for displaying on an LCD display?

    #Option Explicit
    
    #Chip 16F1829, 32
    
    'LCD connection settings
    #Define LCD_IO 4
    #Define LCD_SPEED FAST
    
    #Define LCD_NO_RW
    
    #Define LCD_RS              PortA.0
    #Define LCD_Enable      PortA.1
    
    #Define LCD_DB4       PortA.2
    #Define LCD_DB5       PortC.0
    #Define LCD_DB6       PortC.1
    #Define LCD_DB7       PortC.2
    
    'Eeprom location
    #Define E_Save        10 'Start of Long(ish) Eeprom locations
                             'Occupies 3 bytes for Hi,Mid and Low
    
    Dim     Long_Saved    As Long
    Dim     Long_Returned As Long
    Dim     S_Hi          As Long
    Dim     S_Mi          As Long
    Dim     S_Lo          As Long
    Dim     Temp          As Byte
    
    Let Long_Saved = GetLEeprom(E_Save)
    
    Do
    
        Locate 0, 0
        Print "                "
        Locate 1, 0
        Print "                "
        Let Long_Saved = Long_Saved + 135
        PutLEeprom(E_Save, Long_Saved)
        Wait 5 mS
        Locate 0, 0
        Print Long_Saved
        Print " "
    
        Long_Returned = GetLEeprom(E_Save)
        Locate 1, 0
        Print Long_Returned
        Print " "
        Wait 100 mS
    Loop
    
    Sub PutLEeprom (HiAddr As Byte, Save_Long As Long) 'Places a Long(ish) into three bytes of
                                                    'Eeprom, HiAddr is the first Byte
                                                    'location in Eeprom, the lower Bytes
                                                    'are placed into the adjacent bytes
        Let S_Hi      = Save_Long / 65536
        Let Save_Long = Save_Long - (S_Hi * 65536)
    
        Let S_Mi = Save_Long / 256
        Let S_Lo = Save_Long - (S_Mi * 256)
    
        EpRead HiAddr,Temp
        If Temp <> S_Hi Then
            EpWrite HiAddr,  S_Hi      'The high byte
        End If
    
        EpRead HiAddr+1,Temp
        If Temp <> S_Mi Then
            EpWrite HiAddr+1,S_Mi      'The Mid  byte
        End If
    
        EpRead HiAddr+2,Temp
        If Temp <> S_Lo Then
            EpWrite HiAddr+2,S_Lo      'The Low  byte
        End If
    
        Locate 0, 7
        Print S_Hi
        Print "  "
    
        Locate 0, 10
        Print S_Mi
        Print "  "
    
        Locate 0, 13
        Print S_Lo
        Print "  "
    
    End Sub
    
    Function GetLEeprom (HiAddr As Byte) As Long 'Takes the address of the High Byte and returns
                                                 'a Long(ish) made from the HiAddr and the adjacent
                                                 'bytes in Eeprom
        EpRead HiAddr,  S_Hi
        EpRead HiAddr+1,S_Mi
        EpRead HiAddr+2,S_Lo
    
        Locate 1, 7
        Print S_Hi
        Print "  "
    
        Locate 1, 10
        Print S_Mi
        Print "  "
    
        Locate 1, 13
        Print S_Lo
        Print "  "
    
        Let S_Hi = S_Hi * 65536              'Build the High byte
        Let S_Mi = S_Mi *   256              'Build the Mid  byte
    
        Let GetLEeprom = S_Hi + S_Mi + S_Lo
    
    End Function
    
     

    Last edit: mkstevo 2017-09-15
  • mkstevo

    mkstevo - 2017-09-15

    Further experimentation has shown that the problem appears to lie with the SubRoutine declaration (and possibly the Function declaration too) where the "As Long" may be incorrectly interpreted.

    This works as I'd expected:

    #Option Explicit
    
    #Chip 16F1829, 32
    
    'LCD connection settings
    #Define LCD_IO 4
    #Define LCD_SPEED FAST
    
    #Define LCD_NO_RW
    
    #Define LCD_RS              PortA.0
    #Define LCD_Enable      PortA.1
    
    #Define LCD_DB4       PortA.2
    #Define LCD_DB5       PortC.0
    #Define LCD_DB6       PortC.1
    #Define LCD_DB7       PortC.2
    
    'Eeprom location
    #Define E_Save        10 'Start of Long(ish) Eeprom locations
                             'Occupies 3 bytes for Hi,Mid and Low
    
    Dim     Long_Saved    As Long
    Dim     Long_Returned As Long
    Dim     Save_Long     As Long
    Dim     Ret_Long      As Long
    
    Dim     S_Hi          As Long
    Dim     S_Mi          As Long
    Dim     S_Lo          As Long
    Dim     Temp          As Byte
    
    GetLEeprom(E_Save)
    Let Long_Saved = Ret_Long
    If Long_Saved > 16777000 Then
       Let Long_Saved = 0
    End If
    
    Do
    
        Locate 0, 0
        Print "                "
        Locate 1, 0
        Print "                "
        Let Long_Saved = Long_Saved + 135
    
        Let Save_Long = Long_Saved
        PutLEeprom(E_Save)
        Wait 5 mS
        Locate 0, 0
        Print Long_Saved
        Print " "
    
        GetLEeprom(E_Save)
        Let Long_Returned = Ret_Long
        Locate 1, 0
        Print Long_Returned
        Print " "
        Wait 100 mS
    Loop
    
    Sub PutLEeprom (HiAddr As Byte) 'Places a Long(ish) into three bytes of
                                                    'Eeprom, HiAddr is the first Byte
                                                    'location in Eeprom, the lower Bytes
                                                    'are placed into the adjacent bytes
    
        Let S_Hi      = Save_Long / 65536
        Let Save_Long = Save_Long - (S_Hi * 65536)
    
        Let S_Mi = Save_Long / 256
        Let S_Lo = Save_Long - (S_Mi * 256)
    
        EpRead HiAddr,Temp
        If Temp <> S_Hi Then
            EpWrite HiAddr,  S_Hi      'The high byte
        End If
    
        EpRead HiAddr+1,Temp
        If Temp <> S_Mi Then
            EpWrite HiAddr+1,S_Mi      'The Mid  byte
        End If
    
        EpRead HiAddr+2,Temp
        If Temp <> S_Lo Then
            EpWrite HiAddr+2,S_Lo      'The Low  byte
        End If
    
        Locate 0, 7
        Print S_Hi
        Print "  "
    
        Locate 0, 10
        Print S_Mi
        Print "  "
    
        Locate 0, 13
        Print S_Lo
        Print "  "
    
    End Sub
    
    Sub GetLEeprom (HiAddr As Byte) 'Takes the address of the High Byte and returns
                                                 'a Long(ish) made from the HiAddr and the adjacent
                                                 'bytes in Eeprom
        EpRead HiAddr,  S_Hi
        EpRead HiAddr+1,S_Mi
        EpRead HiAddr+2,S_Lo
    
        Locate 1, 7
        Print S_Hi
        Print "  "
    
        Locate 1, 10
        Print S_Mi
        Print "  "
    
        Locate 1, 13
        Print S_Lo
        Print "  "
    
        Let S_Hi = S_Hi * 65536              'Build the High byte
        Let S_Mi = S_Mi *   256              'Build the Mid  byte
    
        'Let GetLEeprom = S_Hi + S_Mi + S_Lo
        Let Ret_Long = S_Hi + S_Mi + S_Lo
    
    End Sub
    
     
  • Anobium

    Anobium - 2017-09-16

    @Steve. I think you should review https://sourceforge.net/p/gcbasic/discussion/579126/thread/16ce811d/#ef41

    I am thinking you should be addressing as follows:

    Dim workvariable as long
    
    'where this is also true
    lowb      = workvariable
    highb     = workvariable_H
    upperb    = workvariable_U
    lastb     = workvariable_E
    

    Then, you can remove some complexity by simply address the bytes with the the long variable.

     
  • mkstevo

    mkstevo - 2017-09-16

    Many thanks for your kind reply.

    I had previously tried to use the WordVariable_H method when storing a Word variable in Eeprom, but failed to get it to work correctly. Having used my long winded method for extracting the byte values from a Word successfully in that instance, I simply "scaled" it up for the additional byte required to give me the maximum value I needed to store in Eeprom.

    When I am next at my computer, I will try again using the LongVariable_H, LongVariable_U, LongVariable_E methods and see if I can spot why I couldn't get it to work.

     
  • Anobium

    Anobium - 2017-09-16

    Something is not correct somewhere. Use a Sub to return the value as this always works.

    What is very odd is that the first call to print the long value is correct, the, second is incorrect.

    Evan

    #Option Explicit
    
    #Chip 16F877a,4
    
    'LCD connection settings
    #Define LCD_IO 4
    #Define LCD_SPEED FAST
    
    #Define LCD_NO_RW
    
    #Define LCD_RS              PortA.0
    #Define LCD_Enable      PortA.1
    
    #Define LCD_DB4       PortA.2
    #Define LCD_DB5       PortC.0
    #Define LCD_DB6       PortC.1
    #Define LCD_DB7       PortC.2
    
    'Eeprom location
    #Define E_Save        10 'Start of Long(ish) Eeprom locations
                             'Occupies 3 bytes for Hi,Mid and Low
    
    Dim     Long_Saved    As Long
    Dim     Long_Returned As Long
    Dim     Temp          As Byte
    
    Long_Saved = 0
    
    Do
    
        Locate 0, 0
        Print "                "
        Locate 1, 0
        Print "                "
        Let Long_Saved = Long_Saved + 135
        PutLEeprom( E_Save, Long_Saved )
        Wait 5 mS
        Locate 0, 0
        Print Long_Saved
        Print " "
    
        GetLEeprom( E_Save, Long_Returned )
        Locate 1, 0
        Print Long_Returned
    
        wait 10 ms
    Loop
    
    Sub PutLEeprom (HiAddr As Byte, Save_Long As Long) 'Places a Long(ish) into three bytes of
                                                    'Eeprom, HiAddr is the first Byte
                                                    'location in Eeprom, the lower Bytes
                                                    'are placed into the adjacent bytes
            EpWrite (HiAddr,  Save_Long_E)      'The high byte
            EpWrite (HiAddr+1,Save_Long_U)      'The Mid  byte
            EpWrite (HiAddr+2,Save_Long_H)      'The Low  byte
            EpWrite (HiAddr+3,Save_Long)      'The Low  byte
    
    End Sub
    
    Sub GetLEeprom(HiAddr, out EepromVal as long ) 'Takes the address of the High Byte and returns
                                                    'a Long(ish) made from the HiAddr and the adjacent
                                                    'bytes in Eeprom
        EpRead HiAddr+3, EepromVal
        EpRead HiAddr+2, EepromVal_H
        EpRead HiAddr+1, EepromVal_U
        EpRead HiAddr,   EepromVal_E
    
    End Sub
    
     
  • William Roth

    William Roth - 2017-09-17

    Since only 24bits are being used, there is no need to write the "E" byte. The code below demos how to write and read a 24bit value to and from EEPROM.

     #chip 18F25K80, 16
     #Config OSC = INTIO2
     #config MCLRE = ON
    
     #option explicit
    
     ;----- Define I2C settings - CHANGE PORTS
     #define I2C_MODE Master
     #define I2C_DATA PORTC.4
     #define I2C_CLOCK PORTC.5
     #define I2C_DISABLE_INTERRUPTS ON
    
      ;----- Set up LCD
      #define LCD_IO 10
      #define LCD_I2C_Address_1 0x7E
    
     CLS
     Wait 1 s
    
     '// delcare variables
    DIM Var1 as Long
    DIM Var2 as Long
    DIM Var3 as Long
    
    ' // set values to test
    Var1 = 11476222
    Var2 = 14777810
    Var3 = 0'clear
    
    '// write 24 bits Vales to EEPRPoM
    EPWRITE_24 0, Var1
    EPWRITE_24 3, Var2
    
    '// read stored Var1 back into var3
    EPREAD_24 0, Var3
    Locate 0,0 : Print Var3
    
    'read stored var2 back into Var3
    Var3 = 0  '//clear variable
    EPREAD_24 3, Var3
    Locate 1,0 : Print Var3
    
    End
    
    Sub EPWRITE_24 (IN Mem_Loc as Byte, in TMP_LONG as LONG)
          EPWRITE Mem_Loc, TMP_LONG
          EPWRITE Mem_Loc + 1, TMP_LONG_H
          EPWRITE Mem_Loc + 2, TMP_LONG_U
    END SUB
    
    SUB EPREAD_24 (IN Mem_Loc as Byte, OUT NewVal as LONG)
         EPREAD Mem_Loc, NewVal
         EPREAD Mem_Loc + 1, NewVal_H
         EPREAD Mem_Loc + 2, NewVal_U
    End SUB
    
     
  • Anobium

    Anobium - 2017-09-17

    The root cause of the isue has been found and resolved. We have found a long standing issue (2009) where setting the return value of a function by using it as a subroutine parameter did not work. This is the issue that Steve found. The issue only related to the use of a function not a subroutine.

    The fix will be included in v0.98.00. Meanwhile, use the subroutine techniques that Bill and I have recommended.

    I also have created a few demos based on this posting. Writing and Reading variables has been asked many times, so, I created two test programs (now deoms) and I have adapted Bill's code. These can be adapted by others in GitHub. See https://github.com/Anobium/Great-Cow-BASIC-Demonstration-Sources/tree/master/EEPROM%20Solutions/Save_and_Read_Variables_to_EEPROM

     

    Last edit: Anobium 2017-09-17
  • mkstevo

    mkstevo - 2017-09-17

    Hello to you both, and thanks for your suggestions. I won't be able to test any of your suggestions for a few hours, possibly Monday evening at the earliest. Once I've had a chance to test your examples, I'll report back.

    I will also look into using the EepromVal_E,EepromVal_U and EepromVal_H type methods of extracting the byte values from the Long. When I last tried using them (on Word values) I possibly misinterpreted the ability to extract the lowest byte value by assigning the Long directly to a Byte, I might have tried to use an alias of something similar to 'EepromVal_L' for the lowest byte.

    As I say, thanks for your help so far, I'll report back as soon as I can.

     
  • mkstevo

    mkstevo - 2017-09-17

    Thanks to all who kindly gave their time in looking at this. It appears as though I found a small bug relating to Long variables being used as parameters in SubRoutines and Functions. I have tested a bug fix version of the compiler which does indeed work as anticipated.

    From the release of V0.98 onwards this error regarding Functions should be fixed.

    I have to say that using the examples given above, I have been able to tidy my code enourmously, and have been able to increase my storing of a Long value to the full four Byte length allowing me to store values of up to 4+ Billion.

    Once again, I'd like to thank everyone's kind contributions.

    This code does work as expected on V0.96, and is based on William's and Anobium's suggestions to use a SubRoutine to return the values.

    #Option Explicit
    
    #Chip 16F1829, 32
    
    'LCD connection settings
    #Define LCD_IO 4
    #Define LCD_SPEED FAST
    
    #Define LCD_NO_RW
    
    #Define LCD_RS              PortA.0
    #Define LCD_Enable      PortA.1
    
    #Define LCD_DB4       PortA.2
    #Define LCD_DB5       PortC.0
    #Define LCD_DB6       PortC.1
    #Define LCD_DB7       PortC.2
    
    'Eeprom location
    #Define E_Save        10 'Start of Long Eeprom locations
                             'Occupies 4 bytes for High, UMid, LMid and Low
    
    Dim     Long_Saved    As Long
    Dim     Long_Returned As Long
    Dim     Temp          As Byte
    Dim     TempR         As Byte
    
    GetLEeprom(E_Save, Long_Saved)
    If Long_Saved > 4000000000 Then
       Let Long_Saved = 0
    End If
    
    Cls
    Locate 0, 11
    Print":Save"
    Locate 1, 11
    Print": Ret"
    
    Do
        If Long_Saved < 917575 Then
           Cls
           Locate 0, 11
           Print":Save"
           Locate 1, 11
           Print": Ret"
        End If
    
        Let Long_Saved = Long_Saved + 917575
        PutLEeprom(E_Save, Long_Saved)
        Locate 0, 0
        Print Long_Saved
    
        GetLEeprom(E_Save, Long_Returned)
        Locate 1, 0
        Print Long_Returned
        Wait 1 mS
    
    Loop
    
    Sub PutLEeprom (In HiAddr As Byte, In Save_Long As Long) 'Places a Long into four bytes of
                                                    'Eeprom, HiAddr is the first Byte
                                                    'location in Eeprom, the lower Bytes
                                                    'are placed into the adjacent bytes
    
        Let Temp = Save_Long_E
        EpRead HiAddr,TempR
        If Temp <> TempR Then
            EpWrite (HiAddr  , Temp)    'The High byte
        End If
    
        Let Temp = Save_Long_U
        EpRead HiAddr+1,TempR
        If Temp <> TempR Then
            EpWrite (HiAddr+1, Temp)    'The UMid  byte
        End If
    
        Let Temp = Save_Long_H
        EpRead HiAddr+2,TempR
        If Temp <> TempR Then
            EpWrite (HiAddr+2, Temp)    'The LMid  byte
        End If
    
        Let Temp = Save_Long
        EpRead HiAddr+3,TempR
        If Temp <> TempR Then
            EpWrite (HiAddr+3, Temp)    'The Low  byte
        End If
    
    End Sub
    
    Sub GetLEeprom (In HiAddr As Byte, Out EepromVal As Long) 'Takes the address of the High Byte and returns
                                                 'a Long made from the HiAddr and the adjacent
                                                 'bytes in Eeprom
    
        'The sequence of this 'Rebuild' appears important.
        'The order of Low byte - High must be maintained.
        EpRead HiAddr+3, EepromVal
        EpRead HiAddr+2, EepromVal_H
        EpRead HiAddr+1, EepromVal_U
        EpRead HiAddr,   EepromVal_E
    
    End Sub
    
     

    Last edit: mkstevo 2017-09-17

Log in to post a comment.