EEPROM library choosing wrong option

General discussion relating to the library modules supplied with the compiler

Moderators: David Barker, Jerry Messina

Post Reply
SHughes_Fusion
Posts: 219
Joined: Wed Sep 11, 2013 1:27 pm
Location: Chesterfield

EEPROM library choosing wrong option

Post by SHughes_Fusion » Thu Jul 24, 2014 11:25 am

I'm having a problem with the EEPROM library only writing a Word when a LongWord is passed to the Write command. Even if you call

Code: Select all

EE.Write(Address,Longword(0))
it will only write the first two bytes. When I read the value back in I get a very large number....

I've only just noticed this which leads me to believe it may have worked previously. I have changed the EEPROM library to allow me to read and write byte arrays to the EEPROM. I don't know if this change has confused the compiler or if I've done something wrong in the way I've changed the library.

I've added a new ReadItem routine. This was added after the ReadItem for strings and before the compound sub Read:

Code: Select all

{
***
* ReadItem for an array passed by reference
**
}
Sub ReadItem(ByRef pValue() As Byte)
  Dim aPtr As Byte
  
  For aPtr = 0 To Bound(pValue)
    pValue(aPtr) = ReadByte(Address)
  Next
End Sub
I've also added new WriteItem routines, as with the ReadItem routine I've added these between the WriteItem sub for strings and the compound sub Write. There are two, one for variable arrays and one for const arrays.

Code: Select all

{
***
* WriteItem for an array passed by reference
**
}
Sub WriteItem(ByRef pValue() As Byte)
  Dim aPtr As Byte
  
  For aPtr = 0 To Bound(pValue)
    WriteByte(Address,pValue(aPtr))
  Next
End Sub
    // As above for const arrays
Sub WriteItem(ByRefConst pValue() As Byte)
  Dim aPtr As Byte
  
  For aPtr = 0 To Bound(pValue)
    WriteByte(Address,pValue(aPtr))
  Next
End Sub
The Read functions still seem to work correctly - if I change from using the compound Write command to using WriteLongWord and it now works as expected, including reading the value back in.

What is the best way to work out if this is a compiler issue or something with how I've modified the library?

User avatar
David Barker
Swordfish Developer
Posts: 1214
Joined: Tue Oct 03, 2006 7:01 pm
Location: Saltburn by the Sea, UK
Contact:

Re: EEPROM library choosing wrong option

Post by David Barker » Thu Jul 24, 2014 12:51 pm

> EE.Write(Address,Longword(0))

The compiler will still see this as a byte. If you want to write a longword that is guaranteed to always write 4 bytes, then call WriteLongWord() - that's what it is there for.

SHughes_Fusion
Posts: 219
Joined: Wed Sep 11, 2013 1:27 pm
Location: Chesterfield

Re: EEPROM library choosing wrong option

Post by SHughes_Fusion » Thu Jul 24, 2014 12:53 pm

That confuses me...

I thought the point of compound subs was that the compiler chose the appropriate one to use based on the type of variable passed?

Write is a compound of several WriteItem subs so I'd assumed I could just throw any variable at it and the compiler would choose the right one?

If what you say is right then that means I need to rewrite all my code as I use write (and read) in many places with many different types of variable....

User avatar
David Barker
Swordfish Developer
Posts: 1214
Joined: Tue Oct 03, 2006 7:01 pm
Location: Saltburn by the Sea, UK
Contact:

Re: EEPROM library choosing wrong option

Post by David Barker » Thu Jul 24, 2014 1:16 pm

Actually, I've just tested some code and longword(0) will invoke the correct routine. My original concerned the use of a constant, even when used with a typecast - however, the code generated looks correct. In short

Code: Select all

Dim val As LongWord
EE.Write(0,LongWord(val))
EE.Write(4,LongWord(0))
will invoke the longword write routine. Examining the ASM (F2) shows this to be true:

Code: Select all

PROC_WRITELONGWORD_10
    MOVFF F0_U08,EEDATA
    RCALL PROC_WRITEBYTE_6
    MOVFF F1_U08,EEDATA
    RCALL PROC_WRITEBYTE_6
    MOVFF F2_U08,EEDATA
    RCALL PROC_WRITEBYTE_6
    MOVFF F3_U08,EEDATA
    BRA PROC_WRITEBYTE_6
PROC_OL_4_WRITEITEM_12
    MOVFF F4_U32HHH,F0_U32HHH
    MOVFF F4_U32HH,F0_U32HH
    MOVFF F4_U32H,F0_U32H
    MOVFF F4_U32,F0_U32
    BRA PROC_WRITELONGWORD_10
MAIN
    CLRF EEADR,0
    MOVFF M0_U32HHH,F4_U32HHH
    MOVFF M0_U32HH,F4_U32HH
    MOVFF M0_U32H,F4_U32H
    MOVFF M0_U32,F4_U32
    RCALL PROC_OL_4_WRITEITEM_12
    MOVLW 4
    MOVWF EEADR,0
    CLRF F4_U32HHH,0
    CLRF F4_U32HH,0
    CLRF F4_U32H,0
    CLRF F4_U32,0
    RCALL PROC_OL_4_WRITEITEM_12

SHughes_Fusion
Posts: 219
Joined: Wed Sep 11, 2013 1:27 pm
Location: Chesterfield

Re: EEPROM library choosing wrong option

Post by SHughes_Fusion » Thu Jul 24, 2014 1:46 pm

I was originally running this with a const declared as a longword. I then changed to calling with longword(0) just to check and still only got the first two bytes written with the second two seemingly remaining unprogrammed (or being written as $FF).

I've just put some of my original code back in:

Code: Select all

EE.Write(EELocation_Chassis_Joints, LongWord(0))
Then I built the project and searched for that in the asm. What I found was:

Code: Select all

?I000633_F015_000412_P000267 ; L#MK EE.WRITE(EELOCATION_CHASSIS_JOINTS, LONGWORD(0))  //DEFAULT_...
    CLRF F7_U16H,0
    CLRF F7_U16,0
    CALL PROC_OL_2_WRITEITEM_131
Searching for this proc gives me:

Code: Select all

PROC_OL_2_WRITEITEM_131
?I000133_F008_000329_P000081 ; L#MK WRITEWORD(ADDRESS, PVALUE)
    MOVFF F7_U16H,F3_U16H
    MOVFF F7_U16,F3_U16
    BRA PROC_WRITEWORD_115
So it is trying to write a word even when called with a LongWord.

I tried changing my code to:

Code: Select all

Dim TL as LongWord
TL = LongWord(0)
EE.Write(EELocation_Chassis_Joints, TL)
This now does call the correct routine so it appears you were right originally, it works OK when you use a variable but using a const means the compiler doesn't always get the right routine. Determining the cases when it gets it wrong will be tricky, as I say this seemed to have been working for most of the time I've been developing this code and only just cropped up this morning when we were trying to demo it. The code is fairly big and compiles to a little over 40k so trying to dig in to that won't be easy!

I guess I need to re-write my code to either copy the consts to variables or to call the Write(variabletype) directly.

(As an aside, I've found that trying to copy and paste in to the search box in the assembler listing screen doesn't work. It pastes in to the actual window, not in to the search box, on my machine anyway)

Jerry Messina
Swordfish Developer
Posts: 1469
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: EEPROM library choosing wrong option

Post by Jerry Messina » Thu Jul 24, 2014 5:31 pm

It seems to have something to do with the new WriteItem methods you added to EEPROM.bas

When I added the ones in your first post to my eeprom.bas, all of a sudden it quit working.

Code: Select all

EE.Write(4, LongWord(0))
produced code to write a word instead of 4 bytes

Code: Select all

PROC_SUB1_18
?I000018_F002_000020_P000043 ; L#MK EE.WRITE(4,LONGWORD(0))
    MOVLW 4
    MOVWF EEADR,0
?I000019_F002_000020_P000043 ; L#MK EE.WRITE(4,LONGWORD(0))
    CLRF F2_U16H,0
    CLRF F2_U16,0
    BRA PROC_OL_2_WRITEITEM_16
When I use my original copy of eeprom.bas, it calls the proper sub to write a longword

SHughes_Fusion
Posts: 219
Joined: Wed Sep 11, 2013 1:27 pm
Location: Chesterfield

Re: EEPROM library choosing wrong option

Post by SHughes_Fusion » Fri Jul 25, 2014 7:44 am

Interesting, Jerry. I tried the code David posted with my new library and that worked fine and even in my original code it correctly selected the Longword routine when I was writing a Longword variable.

Do you think it is something wrong with my code, or is what I've done confusing the compiler in some way? I'll post the entire library below but one thing I did notice is that I've actually done the modification slightly differently from the way the original works. That had the WriteItem routines - in the main - calling another routine which actually did the writing. The exception to this it the string writing routine which processes the string in the WriteItem routine rather than having / calling a WriteString. I don't know if there is a reason for this, maybe to avoid passing the string on too many times - I had issued with that a while back although I believe David has since fixed that problem.

My routines process the array in the WriteItem. I'm wondering if creating a WriteArray routine and calling that from the WriteItem will help.

Actually, that may even be the source of my problem - I've got two WriteItem routines for arrays, one for const arrays and one for string arrays - I can see the need to use either and as arrays can only be passed by reference it is necessary to have separate routines. Maybe that is causing the problem? I also need to work out in my head if I can do the double-passing in these circumstances.

I know a simple solution would just be to create WriteArray routines and remove the WriteItem ones but for neatness it would be good to get this working and also it may be ther eis an underlying issue here.

I doubt it makes a difference, but for reference I'm using a PIC18F46K22 which has 1024 bytes of EEPROM, although at the moment I'm only using the first 256 bytes.

My EEPROM.bas library:

Code: Select all

Module EE

Include "system.bas"

// does device support EEPROM...
#if _eeprom = 0 
   #error _device + " does not support EEPROM"

// EEPROM address is 8 bits...
#elseif _eeprom = 256
Dim TAddress As EEADR

// EEPROM address is 16 bits...
#else
Dim TAddress As EEADR.AsWord
#endif

// EEPROM address...
Public Dim 
   Address As TAddress    
{
****************************************************************************
* Name    : SetAddress (PRIVATE)                                           *
* Purpose : Sets the current EEPROM address                                *
****************************************************************************
}
Sub SetAddress(pAddress As TAddress)
End Sub
{
****************************************************************************
* Name    : BackToFLASH (PRIVATE)                                          *
* Purpose : Restores EECON1 register to FLASH program access. Swordfish    *
*         : needs EEPGD to be set in order to access program memory        *
*         : constants (such as strings) to be accessed when a program is   *
*         : executing. This inline sub restores EEPGD after EEPROM access  *
****************************************************************************
}
Inline Sub BackToFLASH()
   EECON1 = $80
End Sub
{
****************************************************************************
* Name    : ReadByte                                                       *
* Purpose : Read a byte from EEPROM                                        *
*         : pAddress is EEADR (EEADRH)                                     *
*         : Returned in EEDATA                                             *
****************************************************************************
}
Public Function ReadByte(pAddress As TAddress) As Byte
   Dim RD As EECON1.Booleans(0)
   EECON1 = $00
   RD = true
   result = EEDATA
   BackToFLASH
   Inc(Address)
   ClrWDT
End Function
{
****************************************************************************
* Name    : ReadBoolean                                                    *
* Purpose : Read a boolean value from EEPROM                               *
****************************************************************************
}
Public Function ReadBoolean(pAddress As TAddress) As Boolean
   Result = Boolean(ReadByte(pAddress))
End Function
{
****************************************************************************
* Name    : ReadWord                                                       *
* Purpose : Read a word from EEPROM                                        *
****************************************************************************
}
Public Function ReadWord(pAddress As TAddress) As Word
   Result.Bytes(0) = ReadByte(pAddress)
   Result.Bytes(1) = ReadByte(pAddress)
End Function  
{
****************************************************************************
* Name    : ReadLongWord                                                   *
* Purpose : Read a long word from EEPROM                                   *
****************************************************************************
}
Public Function ReadLongWord(pAddress As TAddress) As LongWord
   Result.Bytes(0) = ReadByte(pAddress)
   Result.Bytes(1) = ReadByte(pAddress)
   Result.Bytes(2) = ReadByte(pAddress)
   Result.Bytes(3) = ReadByte(pAddress)
End Function  
{
****************************************************************************
* Name    : ReadFloat                                                      *
* Purpose : Read a floating point value from EEPROM                        *
****************************************************************************
}
Public Function ReadFloat(pAddress As TAddress) As Float
   Result.Bytes(0) = ReadByte(pAddress)
   Result.Bytes(1) = ReadByte(pAddress)
   Result.Bytes(2) = ReadByte(pAddress)
   Result.Bytes(3) = ReadByte(pAddress)
End Function
{                            
****************************************************************************
* Name    : WriteByte                                                      *
* Purpose : Write a byte to EEPROM                                         *
*         : pAddress is EEADR (EEADRH)                                     *
*         : pValue is EEDATA                                               *
****************************************************************************
}
Public Sub WriteByte(pAddress As TAddress, pValue As EEDATA)
   Dim WR As EECON1.Booleans(1)
   Dim WREN As EECON1.Booleans(2)
   Dim INTCON_SHADOW As Byte
   
   // enable writes...
   EECON1 = $00
   WREN = true
   
   INTCON_SHADOW = INTCON
   // required write sequence...
   INTCON = 0
   EECON2 = $55  
   EECON2 = $AA 
   WR = true  
   INTCON = INTCON_SHADOW
   
   // wait for write completion...
   Repeat
      ClrWDT
   Until Not WR 
   WREN = false  // disable writes
   BackToFLASH
   Inc(Address)
End Sub
{
****************************************************************************
* Name    : WriteBoolean                                                   *
* Purpose : Write a boolean to EEPROM                                      *
****************************************************************************
}
Public Sub WriteBoolean(pAddress As TAddress,pValue As Boolean)
   WriteByte(pAddress,Byte(pValue))
End Sub
{
****************************************************************************
* Name    : WriteWord                                                      *
* Purpose : Write a word to EEPROM                                         *
****************************************************************************
}
Public Sub WriteWord(pAddress As TAddress,pValue As Word)
   WriteByte(pAddress,pValue.Bytes(0))
   WriteByte(pAddress,pValue.Bytes(1))
End Sub
{
****************************************************************************
* Name    : WriteLongWord                                                  *
* Purpose : Write a long word to EEPROM                                    *
****************************************************************************
}
Public Sub WriteLongWord(pAddress As TAddress, pValue As LongWord)
   WriteByte(pAddress,pValue.Bytes(0))
   WriteByte(pAddress,pValue.Bytes(1))
   WriteByte(pAddress,pValue.Bytes(2))
   WriteByte(pAddress,pValue.Bytes(3))
End Sub
{
****************************************************************************
* Name    : WriteFloat                                                     *
* Purpose : Write a floating point value to EEPROM                         *
****************************************************************************
}
Public Sub WriteFloat(pAddress As TAddress, pValue As Float)
   WriteByte(pAddress,pValue.Bytes(0))
   WriteByte(pAddress,pValue.Bytes(1))
   WriteByte(pAddress,pValue.Bytes(2))
   WriteByte(pAddress,pValue.Bytes(3))
End Sub
{
****************************************************************************
* Name    : ReadItem (OVERLOAD)                                            *
* Purpose : Read a boolean value from EEPROM                               *
****************************************************************************
}
Sub ReadItem(ByRef pValue As Boolean)
   pValue = Boolean(ReadByte(Address))
End Sub
{
****************************************************************************
* Name    : ReadItem (OVERLOAD)                                            *
* Purpose : Read a byte value from EEPROM                                  *
****************************************************************************
}
Sub ReadItem(ByRef pValue As Byte)
   pValue = ReadByte(Address)
End Sub
{
****************************************************************************
* Name    : ReadItem (OVERLOAD)                                            *
* Purpose : Read a shortint value from EEPROM                              *
****************************************************************************
}
Sub ReadItem(ByRef pValue As ShortInt)
   pValue = ReadByte(Address)
End Sub
{
****************************************************************************
* Name    : ReadItem (OVERLOAD)                                            *
* Purpose : Read a word from EEPROM                                        *
****************************************************************************
}
Sub ReadItem(ByRef pValue As Word)
   pValue = ReadWord(Address)
End Sub   
{
****************************************************************************
* Name    : ReadItem (OVERLOAD)                                            *
* Purpose : Read an integer from EEPROM                                    *
****************************************************************************
}
Sub ReadItem(ByRef pValue As Integer)
   pValue = ReadWord(Address)
End Sub   
{
****************************************************************************
* Name    : ReadItem (OVERLOAD)                                            *
* Purpose : Read a long word from EEPROM                                   *
****************************************************************************
}
Sub ReadItem(ByRef pValue As LongWord)
   pValue = ReadLongWord(Address)
End Sub   
{
****************************************************************************
* Name    : ReadItem (OVERLOAD)                                            *
* Purpose : Read a long integer from EEPROM                                *
****************************************************************************
}
Sub ReadItem(ByRef pValue As LongInt)
   pValue = ReadLongWord(Address)
End Sub   
{
****************************************************************************
* Name    : ReadItem (OVERLOAD)                                            *
* Purpose : Read a floating point value from EEPROM                        *
****************************************************************************
}
Sub ReadItem(ByRef pValue As Float)
   pValue = ReadFloat(Address)
End Sub
{
****************************************************************************
* Name    : ReadItem (OVERLOAD)                                            *
* Purpose : Read a string from EEPROM                                      *
****************************************************************************
}
Sub ReadItem(ByRef pStr As String)
   Dim StrPtr As POSTINC0
   FSR0 = @pStr
   Repeat
      StrPtr = ReadByte(Address)
   Until Char(EEDATA) = null
End Sub
{
***
* ReadItem for an array passed by reference
**
}
Sub ReadItem(ByRef pValue() As Byte)
  Dim aPtr As Byte
  
  For aPtr = 0 To Bound(pValue)
    pValue(aPtr) = ReadByte(Address)
  Next
End Sub
{
****************************************************************************
* Name    : Read (COMPOUND)                                                *
* Purpose : Read multiple items to EEPROM                                  *
****************************************************************************
}
Public Compound Sub Read(SetAddress, ReadItem)
{
****************************************************************************
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Write a boolean to EEPROM                                      *
****************************************************************************
}
Sub WriteItem(pValue As Boolean)
   WriteByte(Address,Byte(pValue))
End Sub
{
****************************************************************************
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Write a byte to EEPROM                                         *
****************************************************************************
}
Sub WriteItem(pValue As Byte)
   WriteByte(Address,pValue)
End Sub
{
****************************************************************************
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Write a short integer to EEPROM                                *
****************************************************************************
}
Sub WriteItem(pValue As ShortInt)
   WriteByte(Address,pValue)
End Sub
{
****************************************************************************
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Write a word to EEPROM                                         *
****************************************************************************
}
Sub WriteItem(pValue As Word)
   WriteWord(Address, pValue)
End Sub
{
****************************************************************************
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Write an integer to EEPROM                                     *
****************************************************************************
}
Sub WriteItem(pValue As Integer)
   WriteWord(Address, pValue)
End Sub
{
****************************************************************************
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Write a long word to EEPROM                                    *
****************************************************************************
}
Sub WriteItem(pValue As LongWord)
   WriteLongWord(Address, pValue)
End Sub
{
****************************************************************************
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Write a long integer to EEPROM                                 *
****************************************************************************
}
Sub WriteItem(pValue As LongInt)
   WriteLongWord(Address, pValue)
End Sub
{
****************************************************************************
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Write a floating point value to EEPROM                         *
****************************************************************************
}
Sub WriteItem(pValue As Float)
   WriteFloat(Address, pValue)
End Sub
{
****************************************************************************
* Name    : WriteItem (OVERLOAD)                                           *
* Purpose : Write a string value to EEPROM                                 *
****************************************************************************
}
Sub WriteItem(pValue As String)
   Dim StrPtr As POSTINC0
   FSR0 = @pValue
   Repeat
      WriteByte(Address,StrPtr)
   Until Char(EEDATA) = null
End Sub
{
***
* WriteItem for an array passed by reference
**
}
Sub WriteItem(ByRef pValue() As Byte)
  Dim aPtr As Byte
  
  For aPtr = 0 To Bound(pValue)
    WriteByte(Address,pValue(aPtr))
  Next
End Sub
    // As above for const arrays
Sub WriteItem(ByRefConst pValue() As Byte)
  Dim aPtr As Byte
  
  For aPtr = 0 To Bound(pValue)
    WriteByte(Address,pValue(aPtr))
  Next
End Sub
{
****************************************************************************
* Name    : Write (COMPOUND)                                               *
* Purpose : Write multiple items to EEPROM                                 *
****************************************************************************
}
Public Compound Sub Write(SetAddress, WriteItem)

{
****************************************************************************
* Name    : RefreshArray()                                                 *
* Purpose : Reads and writes back the entire EEPROM memory. This should be *
*           done periodically to ensure data is not lost.                  *
*           Disable interrupts before calling this routine.                *
****************************************************************************
}
Public Sub RefreshArray()
   Dim RD As EECON1.Booleans(0)
   Dim WR As EECON1.Booleans(1)
   Dim WREN As EECON1.Booleans(2)
   
   EEADR = 0                    // Set address to zero  
   EECON1 = $00                 // enable writes...
   WREN = true

   Repeat
     RD = true                  // Read in to EEDATA register
     EECON2 = $55               // required write sequence...     
     EECON2 = $AA               
     WR = true                  // Initiate write - will write the contents of EEDATA back to the same location
     Repeat                     // wait for write completion...
        ClrWDT
     Until Not WR 
     Inc(EEADR)                 // Increment EEADR, will loop to zero when memory size exceeded
   Until EEADR = 0
   
   WREN = false                 // disable writes
   BackToFLASH
End Sub

SHughes_Fusion
Posts: 219
Joined: Wed Sep 11, 2013 1:27 pm
Location: Chesterfield

Re: EEPROM library choosing wrong option

Post by SHughes_Fusion » Fri Jul 25, 2014 9:01 am

Just to confirm, removing the WriteItem entries for arrays and creating a separate WriteArray sub seems to fix the issue.

Whether this is a compiler problem or whether I'm mis-using the compound sub function I'm not sure.

Post Reply