Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
stewpye
PostPosted: Jun 06, 2012 - 09:20 AM
Rookie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jun 06, 2012 - 09:25 AM
10k+ Postman


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!)

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
stewpye
PostPosted: Jun 06, 2012 - 09:51 AM
Rookie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
stewpye
PostPosted: Jun 06, 2012 - 10:07 AM
Rookie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jun 06, 2012 - 10:12 AM
10k+ Postman


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));
}

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jun 06, 2012 - 10:12 AM
10k+ Postman


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?

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
stewpye
PostPosted: Jun 06, 2012 - 10:13 AM
Rookie


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...
 
 View user's profile Send private message  
Reply with quote Back to top
stewpye
PostPosted: Jun 06, 2012 - 10:25 AM
Rookie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: Jun 06, 2012 - 10:42 AM
10k+ Postman


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.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
clawson
PostPosted: Jun 06, 2012 - 10:51 AM
10k+ Postman


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)?

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: Jun 06, 2012 - 11:08 AM
10k+ Postman


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.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
sternst
PostPosted: Jun 06, 2012 - 11:12 AM
Raving lunatic


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
 
 View user's profile Send private message  
Reply with quote Back to top
stewpye
PostPosted: Jun 06, 2012 - 11:33 AM
Rookie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits