| Author |
Message |
|
|
Posted: Jun 06, 2012 - 09:20 AM |
|

Joined: Jul 04, 2009
Posts: 36
Location: Brisbane, Australia
|
|
I have some arrays of structs that I need to store in an external SPI EEPROM. The structs will be something like this:
Code:
struct stepvalues
{
unsigned char pitch; // Pitch is one byte.
unsigned char velocity; // Velocity is one byte.
unsigned char gate_time; // Gate time is one byte.
unsigned int gate:1; // Gate only needs one bit.
unsigned int slide:1; // Slide only needs one bit.
unsigned int accent:1; // Accent only needs one bit.
};
struct stepvalues ch1[16]; // There are 16 steps (rows) in the pattern
struct stepvalues ch2[16]; // and there are two channels
My first question is how can I be sure that my 3 bitfields in the stuct will all be in one byte, so the struct will take 4 bytes?
The second question is how do I go about storing a complete array of the struct, and be able to retrieve it?
The code above is for one pattern. In reality there will be many patterns, all with the same variables as above. There is not enough internal RAM to store all of them, so my plan is to only have one in RAM and then store it into EEPROM. I then need to be able to retrieve a particular pattern (array of structs) from EEPROM. Any ideas of how to go about this?
FYI: I'm still learning C programming.
Regards,
Stewart. |
|
|
| |
|
|
|
|
|
Posted: Jun 06, 2012 - 09:25 AM |
|


Joined: Jul 18, 2005
Posts: 62362
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
My first question is how can I be sure that my 3 bitfields in the stuct will all be in one byte, so the struct will take 4 bytes?
Well I'd start by making those fields "unsigned char" not "unsigned int".
Quote:
The second question is how do I go about storing a complete array of the struct, and be able to retrieve it?
eeprom_write_block() though as it's 4 bytes you could do some jiggery-pokery with eeprom_write_dword() but that would break if the struct ever grew larger later.
Quote:
Any ideas of how to go about this?
Code:
typedef struct
{
unsigned char pitch; // Pitch is one byte.
unsigned char velocity; // Velocity is one byte.
unsigned char gate_time; // Gate time is one byte.
unsigned char gate:1; // Gate only needs one bit.
unsigned char slide:1; // Slide only needs one bit.
unsigned char accent:1; // Accent only needs one bit.
} stepvalues;
stepvalues one_in_ram;
stepvalues ch1[16] EEMEM = {
{ 31, 50, 10, 0, 1, 0 },
{ 17, 40, 20, 1, 1, 0 },
etc.
}
eeprom_read_block(&one_in_ram, &ch1[11], sizeof(ch1[0]));
(untested!) |
_________________
|
| |
|
|
|
|
|
Posted: Jun 06, 2012 - 09:51 AM |
|

Joined: Jul 04, 2009
Posts: 36
Location: Brisbane, Australia
|
|
|
clawson wrote:
Well I'd start by making those fields "unsigned char" not "unsigned int".
Sorry, I was playing around with the code in "Pelles C" and it wouldn't let me put birfields into a char. I'll change it to unsigned char.
Regards,
Stew. |
|
|
| |
|
|
|
|
|
Posted: Jun 06, 2012 - 10:07 AM |
|

Joined: Jul 04, 2009
Posts: 36
Location: Brisbane, Australia
|
|
I just noticed I only mentioned External SPI EEPROM at the top of my post, which you may have missed Clawson.
eeprom_write_block() won't work with external EEPROM will it?
Regards,
Stew. |
|
|
| |
|
|
|
|
|
Posted: Jun 06, 2012 - 10:12 AM |
|


Joined: Jul 18, 2005
Posts: 62362
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Nope seems Pelles isn't too keen on it even using "unsigned char":
Code:
C:\Documents and Settings\asl\My Documents\Pelles C Projects\cipher\cipher.c(7): error #2186: 'unsigned char' is an illegal bit-field type.
C:\Documents and Settings\asl\My Documents\Pelles C Projects\cipher\cipher.c(8): error #2186: 'unsigned char' is an illegal bit-field type.
yet when I do this in avr-gcc it builds without error. I haven#'t a clue why Pelles rejects this same code?
Code:
#include <stdio.h>
#include <avr/io.h>
typedef struct {
char n;
unsigned char foo:1;
unsigned char bar:1;
} test_t;
test_t test;
int main(int argc, char * argv[]) {
char buffer[20];
sprintf(buffer, "size = %d\n", sizeof(test));
}
|
_________________
|
| |
|
|
|
|
|
Posted: Jun 06, 2012 - 10:12 AM |
|


Joined: Jul 18, 2005
Posts: 62362
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
stewpye wrote:
I just noticed I only mentioned External SPI EEPROM at the top of my post, which you may have missed Clawson.
eeprom_write_block() won't work with external EEPROM will it?
Regards,
Stew.
Oh you are right - but I assume you'll be implementing a similar API? |
_________________
|
| |
|
|
|
|
|
Posted: Jun 06, 2012 - 10:13 AM |
|

Joined: Jul 04, 2009
Posts: 36
Location: Brisbane, Australia
|
|
| I'm not asking how to write the SPI EEPROM access routine, just how to keep track of the addresses that I'm storing the data to... |
|
|
| |
|
|
|
|
|
Posted: Jun 06, 2012 - 10:25 AM |
|

Joined: Jul 04, 2009
Posts: 36
Location: Brisbane, Australia
|
|
|
clawson wrote:
I assume you'll be implementing a similar API?
I guess this is the bit I'm unsure about!
Stew. |
|
|
| |
|
|
|
|
|
Posted: Jun 06, 2012 - 10:42 AM |
|

Joined: Feb 12, 2005
Posts: 16328
Location: Wormshill, England
|
|
Regarding 'unsigned char' in bitfields, 'unsigned int' is the conventional type. With a byte-aligned cpu like AVR, any compiler will pack the bits into bytes anyway.
To be on the safe side, I would specify the structure and array of structures.
Then use the sizeof() operator to determine the amount of memory block used, and write this block to external eeprom.
SPI or I2C eeproms tend to be page orientated. So your 'write_block()' function will need to split the block into pages.
Bear in mind that writing serialised data in this way requires the equivalent read_block() function. The struct storage can vary between different compilers and architectures. e.g. big-endian, word-aligned, bitfield allocation order, ...
I am always happier with a portable storage scheme on an external device. After all, will it be read by an AVR, ARM, 68k, ... ?
David. |
|
|
| |
|
|
|
|
|
Posted: Jun 06, 2012 - 10:51 AM |
|


Joined: Jul 18, 2005
Posts: 62362
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
just how to keep track of the addresses that I'm storing the data to...
Well if your structs are n byes at a base address B then a particular Nth element is surely going to be at B + ( N * n) isn't it? You could get the C linker to do that calculation for you if you want by creating variables in a new __attribute__((section(".something"))) but then finally discard this section from the final output so you can use the linker to calculate element offsets but not actually create any data. But given that it really is just B + (N * n) I'd have thought you could just calculate it yourself with less fuss.
One issue for you is - how are you going to get the initial data into the external EEPROM in the first place? Are you planning to build it into the code flash image (PROGMEM) then eeprom_write_byte() it into the external EEPROM at startup (if it's not found to be there already)? |
_________________
|
| |
|
|
|
|
|
Posted: Jun 06, 2012 - 11:08 AM |
|

Joined: Feb 12, 2005
Posts: 16328
Location: Wormshill, England
|
|
I suggest that you don't try doing the math yourself.
Let the compiler decide where the Nth struct lives.
Let the compiler decide where an individual member lives.
Most if not all AVR compilers will pack structs and arrays of structs.
Even assemblers are liable to word align data.
Of course it really does not matter if you are reading and writing from a single application and the external data is never accessed by anything else.
David. |
|
|
| |
|
|
|
|
|
Posted: Jun 06, 2012 - 11:12 AM |
|


Joined: Jul 23, 2001
Posts: 2439
Location: Osnabrueck, Germany
|
|
|
clawson wrote:
yet when I do this in avr-gcc it builds without error. I haven#'t a clue why Pelles rejects this same code?
The standard says:
Quote:
A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or some other implementation-defined type.
GCC includes "unsigned char" into "some other implementation-defined type", Pelles not. |
_________________ Stefan Ernst
|
| |
|
|
|
|
|
Posted: Jun 06, 2012 - 11:33 AM |
|

Joined: Jul 04, 2009
Posts: 36
Location: Brisbane, Australia
|
|
|
clawson wrote:
One issue for you is - how are you going to get the initial data into the external EEPROM in the first place? Are you planning to build it into the code flash image (PROGMEM) then eeprom_write_byte() it into the external EEPROM at startup (if it's not found to be there already)?
The inital value of the data is not important. There will be a clear pattern function that will assign default valaues. The data will be entered by the end user, by using an interface of switches and LCD. One pattern will be edited at a time, with the changes stored in internal RAM. When a different pattern is selected (from EEPROM) the current pattern is saved to EEPROM.
Ideally the micro would have enough internal RAM to hold all the patterns so all I would have to do is store all of the patterns before power down and restore them on power up. I'll be using the XMEGA128A4U-AU (when available) which has 8kB of SRAM, which is not enough for all the data I want to store. I chose this micro because the 44 pin TQFP package can be easily soldered by hand. |
|
|
| |
|
|
|
|
|