eeprom record passed as a function parameter

  • 1
  • 2
  • Page 1 of 2
Avra
Schreiberling
Avatar
Gender:
Location: Belgrade, Serbia
Age: 53
Homepage: rs.linkedin.com/in…
Posts: 653
Registered: 07 / 2002
Subject:

eeprom record passed as a function parameter

 · 
Posted: 22.05.2015 - 12:23  ·  #1
I have a very big eeprom structure which I will simplify for demonstration like this:
Code
type
  TEnum = (Zero, One);

  TAiSettings = record
    Correction : TEnum;
    Filter     : TEnum;
  end;
  
  TSettings = record
    AI        : array[1..6] of TAiSettings;
    General   : TEnum;
  end;

var
{$EEPROM}
  Settings: TSettings, locked;
  ptr: pointer to TAiSettings;

If later in code I try to pass TAiSettings var type to function like this:
Code
CalcAi(Settings.AI[3]);

then when I try to access record elements I expected them to be in eeprom, but it seams that they point to ram instead, since this reads totally wrong values:
Code
procedure CalcAi(var SettingsAi: TAiSettings);
begin
  if (SettingsAi.Correction = One) then // <<< value of SettingsAi.Correction is wrong 
    Write(LCDout, 'One');
  else
    Write(LCDout, 'Zero');
  endif;
end;

I have found a workaround replacement call like this:
Code
      ptr := @Settings.AI[i];  // eeprom pointer works well
      CalcAi(ptr);             // eeprom pointer works well

and it works fine if I change CalcAi() to be like this:
Code
procedure CalcAi(var SettingsAiPtr: pointer to TAiSettings);
begin
  if (EEpromPtr(SettingsAiPtr)^.Correction = One) then
    Write(LCDout, 'One');
  else
    Write(LCDout, 'Zero');
  endif;
end;

This is very ugly and reminds me like working with C. Not to mention that my eeprom structures have complex records in thousands of bytes and I would literally have to use this ugly workaround in hundreds of places, and introduce dozens of pointers for each subrecord that I need. Is there some other way? Maybe I can somehow redefine function parameter type so it is told to point to eeprom? Can compiler somehow know that any function record parameter points to eeprom? Can it be fixed anyhow?
Merlin
Administrator
Avatar
Gender:
Age: 24
Posts: 1409
Registered: 03 / 2005
Subject:

Re: eeprom record passed as a function parameter

 · 
Posted: 22.05.2015 - 12:59  ·  #2
Hi Avra.

There is a fundamental problem here with AVR micros in that the model they use has overlapping memory addresses rather than contiguous ones. This means that when you pass an address, which certainly for smaller chips there is no room for passing the data space without adding an extra byte to every pointer parameter. Bear in mind that these can be very small chips, and that a choice had to be made in the early days whether to add this overhead or not. Which choice is the right one is arguable. It is a very fine balance when space is at a premium, but before the advent of XMEGAs not to include this overhead was probably the right decision.

Your suggestion of telling the compiler that the pointer is to EEPROM sounds fundamentally good, but very difficult to implement I suspect, and presents problems of its own. After all, copying a structure from eeprom to memory might be difficult, and it would be very easy to fall into the trap of sending the wrong type.

So I think your suggestions overcomplicate the issue. Going back to your original code

Code
CalcAi(Settings.AI[3]);


should work and IMHO it is a bug that it doesn't. It should set up a copy from eeprom to the stack (which is in ram) but the bug is that it copies from ram to ram instead.

I think that another workaround might be

Code

x := Setting.AI[3];
CalcAi( x );
rh
Administrator
Avatar
Gender:
Location: Germany
Age: 24
Homepage: e-lab.de
Posts: 5558
Registered: 03 / 2002
Subject:

Re: eeprom record passed as a function parameter

 · 
Posted: 22.05.2015 - 14:51  ·  #3
Hello Avra,

your function
procedure CalcAi(var SettingsAi: TAiSettings);
is using the VAR directive. This means that this parameter is
not a copy of the EEprom contents on the frame, but only a pointer
to this structure is copied on the frame. Further working with this
"pointer" always points into RAM because any type of pointers don't
have any memory type infos.

So in this case passing a typed pointer to this function is much more
better. Then using EEpromPtr(nnnn) in this function will do it correct.

And why is this construction "ugly"? We don't have a huge 32bit engine
here or a PC, but an 8bit machine with some restrictions.

Of course, if the system always uses 24 or 32bit pointers then it is
possible to put the information RAM/FLASH/EEPROM in a pointer.
But this is a penalty for 90% of the standard operations. Sorry.

rolf
Avra
Schreiberling
Avatar
Gender:
Location: Belgrade, Serbia
Age: 53
Homepage: rs.linkedin.com/in…
Posts: 653
Registered: 07 / 2002
Subject:

Re: eeprom record passed as a function parameter

 · 
Posted: 22.05.2015 - 15:16  ·  #4
@Merlin:
Your workaround would be OK if I only need reading, but I also need writing so I really need eeprom record...

@Rolf:
I know that VAR passes just a pointer, so I was hoping something like this to work, but it doesn't:
Code
procedure CalcAi(var SettingsAi: TAiSettings);
var
  x: TAiSettings;
begin
  x := EEpromPtr(SettingsAi)^;
  if (x.Correction = One) then
    ...

I get wrong results. Probably because it's just a nonsence and x variable points to whole subrecord is in ram and dereferenced pointer can't be assigned to it, so it looks like my workaround is the only one that can give me both read and write access to eeprom subrecord elements...

Thanks both for your help! I really appreciate it.


UPDATE:
Code
      ptr := @Settings.AI[3];  // eeprom pointer works well
      CalcAi(ptr);             // eeprom pointer works well

I have tried to shorten this to CalcAi(@Settings.AI[3]) but it is not accepted by compiler. I have to use ptr like above, don't I?
Merlin
Administrator
Avatar
Gender:
Age: 24
Posts: 1409
Registered: 03 / 2005
Subject:

Re: eeprom record passed as a function parameter

 · 
Posted: 22.05.2015 - 15:33  ·  #5
Hi Avra.

Sorry - I missed the 'var' bit. (also sorry Rolf!).

I guess you mean CalcAi needs to both read and write, in which case I think your solution is probably the only valid one. In this case though could you not use something like

Code
function CalcAi( SettingsAi : TAiSettings ) : TAiSettings


and

Code
Setting.AI[3] := CalcAi( Setting.AI[3] );


or is TAiSettings too big?

(You could also modify my workaround with

Code
x := Setting.AI[3]; 
CalcAi( x ); 
Setting.AI[3] := x;


again assuming TAiSettings is not too big)
Avra
Schreiberling
Avatar
Gender:
Location: Belgrade, Serbia
Age: 53
Homepage: rs.linkedin.com/in…
Posts: 653
Registered: 07 / 2002
Subject:

Re: eeprom record passed as a function parameter

 · 
Posted: 22.05.2015 - 15:39  ·  #6
Quote by Merlin
or is TAiSettings too big?


It is too big for free ram I have left after running all processes.
Avra
Schreiberling
Avatar
Gender:
Location: Belgrade, Serbia
Age: 53
Homepage: rs.linkedin.com/in…
Posts: 653
Registered: 07 / 2002
Subject:

Re: eeprom record passed as a function parameter

 · 
Posted: 29.05.2015 - 11:19  ·  #7
I get an error that I suspect compiler should handle without problems. In original code bellow IF produces error "Type Missmatch! expected":
Code
  if (EEpromPtr(SettingsAiPtr)^.Out[i].Test > Runtime.AI[4].Filter) then
    nop;
  endif;

Both Test and Filter are of TEnum type which is defined as:
Code
TEnum = (Zero, One);

Test is in eeprom complex record, and Filter is in ram complex record. If needed I can provide a full working code example project.

This probably provides more info why is compiler confused:
Code
  if TEnum(EEpromPtr(SettingsAiPtr)^.Out[i].Test) > TEnum(Runtime.AI[4].Filter) then
    nop;
  endif;
since error at Test variable is this: "Type Missmatch! byte or char or enumeration expected".

So I have made a following workaround which compiles:
Code
  if byte(EEpromPtr(SettingsAiPtr)^.Out[i].Test) > byte(Runtime.AI[4].Filter) then
    nop;
  endif;


Rolf, please fix this if it is a bug.
Merlin
Administrator
Avatar
Gender:
Age: 24
Posts: 1409
Registered: 03 / 2005
Subject:

Re: eeprom record passed as a function parameter

 · 
Posted: 29.05.2015 - 11:38  ·  #8
Hi Avra.

More of a comment than anything else, but personally I am not a fan of inequality tests on enums, and certainly the manual does not say that these inequalities are allowed, so to me your workaround is actually the right way to do it because you are explicitly accepting that you are doing something dodgy.

Imagine these two sets

TDays = (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday);

and

TDays = (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday);

to illustrate why I don't like the idea.
  • 1
  • 2
  • Page 1 of 2
Selected quotes for multi-quoting:   0

Registered users in this topic

Currently no registered users in this section

The statistic shows who was online during the last 5 minutes. Updated every 90 seconds.
MySQL Queries: 15 · Cache Hits: 14   122   136 · Page-Gen-Time: 0.039953s · Memory Usage: 2 MB · GZIP: on · Viewport: SMXL-HiDPI