|
|
View previous topic :: View next topic |
Author |
Message |
eskimobob
Joined: 07 Feb 2009 Posts: 40
|
problem with arrays in structs V4.129 |
Posted: Thu Feb 23, 2012 5:22 pm |
|
|
Compiler V4.129
Working example program below. I've tried to keep this very simple - the code is taken from a very large program but only enough is shown here to describe my problem.
Probably faster to start reading at the bottom of the main function before trawling through the eeprom writing or reading stuff.
Code: | #include <18F6722.h>
// DEFINES ==========================================================
#define TRISC 0b10111011
#define SCL0_PIN PIN_C3
#define SDA0_PIN PIN_C4
#define WP_EEPROM PIN_C5
#define EEPROM_ADDR 0xA0
#define TEST_LOCATION_LENGTH 21
#define MAX_TESTS 20
// END DEFINES ======================================================
// FUSES ============================================================
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //Crystal osc
#FUSES NOCPD //No EE protection
#FUSES NOPROTECT //Code not protected from reading
#FUSES MCLR //Master Clear pin used for I/O
#FUSES PUT //Power Up Timer
#FUSES NOBROWNOUT //Reset when brownout detected - //check this
#FUSES NOLVP //No Low voltage programming
// END FUSES ========================================================
// HELPERS ==========================================================
#device ICD=true
#device adc=10
#device PASS_STRINGS=IN_RAM
#use delay(clock=10000000)
#use i2c(stream=RTCC_MEM, MASTER, scl=SCL0_PIN, sda=SDA0_PIN, SLOW=100000)
// END HELPERS ======================================================
// TYPE DEFINES =====================================================
typedef unsigned int8 u8bit;
typedef unsigned int16 u16bit;
typedef struct
{
u8bit checksum;
char default_location[5];
u8bit last_test_result;
}TESTS_INFO_STRUCT;
// END TYPE DEFINES =================================================
// GLOBALS ==========================================================
TESTS_INFO_STRUCT test_info;
// END GLOBALS ======================================================
//-------------------------------------------------------------------
void memory_write(u8bit base_address, u16bit address, u8bit * data, u16bit length)
//-------------------------------------------------------------------
{
BOOLEAN nack;
BOOLEAN boundary;
u16bit start_address;
start_address = address;
while (length > 0)
{
boundary = FALSE; //we can start anywhere
i2c_start(RTCC_MEM);
i2c_write(RTCC_MEM, base_address);
i2c_write(RTCC_MEM, make8(address, 1));
i2c_write(RTCC_MEM, make8(address, 0));
while ((length > 0) && (!boundary))
{
//check if we are crossing a 64 byte boundary
boundary = (((start_address + 1) % 64) == 0);
i2c_write(RTCC_MEM, *data);
data++;
length--;
start_address++;
}
i2c_stop(RTCC_MEM);
//We try addressing it and wait for it to acknowledge - we then know we can continue
nack = TRUE;
while (nack)
{
delay_ms(10);
i2c_start(RTCC_MEM);
nack = i2c_write(RTCC_MEM, base_address);
}
}
}
//-------------------------------------------------------------------
void memory_read(u8bit base_address, u16bit address, u8bit * data, u16bit length)
//-------------------------------------------------------------------
{
i2c_start(RTCC_MEM);
i2c_write(RTCC_MEM, base_address);
i2c_write(RTCC_MEM, make8(address, 1));
i2c_write(RTCC_MEM, make8(address, 0));
i2c_start(RTCC_MEM);
i2c_write(RTCC_MEM, base_address + 1);
while (length > 0)
{
*data = i2c_read(RTCC_MEM, length > 1);
data++;
length--;
}
i2c_stop(RTCC_MEM);
}
//-------------------------------------------------------------------
void main(void)
//-------------------------------------------------------------------
{
set_tris_c(TRISC);
disable_interrupts(INT_RDA);
disable_interrupts(INT_SSP);
disable_interrupts(INT_EXT);
output_high(WP_EEPROM);
//initialise values in struct to 0
memset(&test_info, 0, sizeof(TESTS_INFO_STRUCT));
//read the memory to see what has stuck during a power down
memory_read(EEPROM_ADDR, 60, &test_info, sizeof(TESTS_INFO_STRUCT));
//initialise values in struct to 0 again
memset(&test_info, 0, sizeof(TESTS_INFO_STRUCT));
//store the values in eeprom
output_low(WP_EEPROM);
memory_write(EEPROM_ADDR, 60, &test_info, sizeof(TESTS_INFO_STRUCT));
output_high(WP_EEPROM);
//initialise values in struct to something obviously wrong
memset(&test_info, 0xA5, sizeof(TESTS_INFO_STRUCT));
//read the memory to see if they have stuck this time...
memory_read(EEPROM_ADDR, 60, &test_info, sizeof(TESTS_INFO_STRUCT));
//ok, here we see the problem, the data that is now read out is as follows:
//checksum = 0 as expected
//default_location[5] = 5 x null as expected
//last_test_result = 255 which is not as expected
//arghh!
}
// ==================================================================
|
If I move the array to the last element of the struct then all works - at least for this specific example.
Quote: | typedef struct
{
u8bit checksum;
u8bit last_test_result;
char default_location[5];
}TESTS_INFO_STRUCT;
|
It looks to me like something odd is happening in the eeprom reading code once it encounters an array in the data structure.
After reading around the forum, I have tried the (int8 *) cast in case that helps but it doesn't.
Am I making any obvious errors?? |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Fri Feb 24, 2012 12:30 am |
|
|
Why you're not telling the observed problem clearly instead of hiding it in the file comments?
If I understand right, you are saying that the last byte of the structure is read incorrectly (0xff instead of 0x00). You didn't perform a test that shows if it's a read or write problem.
P.S.: I see, that the problem is by design. The write function is stopping byte write purposeful after address 63, so it's only writing 4 of 7 bytes. |
|
|
eskimobob
Joined: 07 Feb 2009 Posts: 40
|
|
Posted: Fri Feb 24, 2012 2:20 am |
|
|
Hi FvM,
Thanks for your reply
FvM wrote: | P.S.: I see, that the problem is by design. The write function is stopping byte write purposeful after address 63, so it's only writing 4 of 7 bytes. |
It is supposed to ensure that I do not cross a 64 byte boundary without issuing an I2C_STOP and then starting again. It does continue to write after address 63 however now you have caused me to look at it more closely, I can see that I am not incrementing the address variable so that when it goes around the loop again to write bytes after a 64 byte boundary, it actually overwrites the earlier bytes again. I can actually get rid of start_address.
This now works:
Code: | while ((length > 0) && (!boundary))
{
//check if we are crossing a 64 byte boundary
boundary = (((address + 1) % 64) == 0);
i2c_write(RTCC_MEM, *data);
data++;
length--;
address++;
} |
Thanks for helping me to spot my mistake |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|