I have successfully made an IAP write and read call to flash memory with a simple data type like char or int. Now I am trying to do the same with a structure that I have defined.
Currently, I simply initialize and set the variables within the structure, then I pass the address of the struct as the source address for the IAP call. Do I have to copy it into a specific RAM location first? I didn't have to do that when I simply wrote a string like "HELLO WORLD\n" to and from Flash. Here is my current code:
struct exercise{ char ex_name[30]; int pic_ID; // Picture reference ID int ex_info; // Exercise reference ID int goal_set; // Goal exercise variables int goal_weight; int goal_rep; int act_set; // Actual exercise variables int act_weight; int act_rep; }; struct day{ int numExercises; char name[15]; struct exercise* exercises[15]; }; struct workout{ int numDays; struct day* days[7]; };
All IAP calls return status code 0, and nothing is printed with the write command, meaning the information was not returned correctly.
// Set up a test workout in Flash void setUpTestWorkout() { struct exercise ex1, ex2, ex3; struct day day1; struct workout workout_send, workout_receive; char buffer[500], text[20]; unsigned int *source, *destination, i; unsigned int command_iap[5], result_iap[3]; unsigned long int enabled_interrupts; IAP iap_bypointer; // Set and initialize exercises strcpy(ex1.ex_name, "Bench Press"); ex1.pic_ID = PIC_CHEST; // Picture reference ID ex1.ex_info = EX_BENCHPRESS; // Exercise reference ID ex1.goal_set = 3; // Goal exercise variables ex1.goal_weight = 150; ex1.goal_rep = 10; ex1.act_set = 0; // Actual exercise variables ex1.act_weight = 0; ex1.act_rep = 0; strcpy(ex2.ex_name, "Closed Grip Press"); ex2.pic_ID = PIC_CHEST; // Picture reference ID ex2.ex_info = EX_BENCHPRESS; // Exercise reference ID ex2.goal_set = 3; // Goal exercise variables ex2.goal_weight = 100; ex2.goal_rep = 8; ex2.act_set = 0; // Actual exercise variables ex2.act_weight = 0; ex2.act_rep = 0; strcpy(ex3.ex_name, "Crunches"); ex3.pic_ID = PIC_CHEST; // Picture reference ID ex3.ex_info = EX_BENCHPRESS; // Exercise reference ID ex3.goal_set = 5; // Goal exercise variables ex3.goal_weight = 0; ex3.goal_rep = 20; ex3.act_set = 0; // Actual exercise variables ex3.act_weight = 0; ex3.act_rep = 0; // Set and initialize day day1.numExercises = 3; for(i=0; i<MAX_EXERCISES; i++) day1.exercises[i] = 0; strcpy(day1.name, "Chest"); day1.exercises[0] = &ex1; day1.exercises[1] = &ex2; day1.exercises[2] = &ex3; // Set and initialize workout for(i=0; i<MAX_DAYS; i++) workout_send.days[i] = 0; workout_send.numDays = 7; workout_send.days[0] = &day1; iap_bypointer = (IAP) 0x7FFFFFF1; // IAP function location clearScreen(); destination = (unsigned int*)0x00040000; // Dest Flash location source = (unsigned int*)&workout_send; // Source RAM location writeText("here1\n"); command_iap[0]=50; //prepare sectors 15-17 for erase call command_iap[1]=15; command_iap[2]=17; iap_bypointer(command_iap,result_iap); if(result_iap[0] != 0) writeText("error preparing\n"); writeText("here2\n"); command_iap[0]=52; //erase sectors 15-17 command_iap[1]=15; command_iap[2]=17; command_iap[3]=60000; iap_bypointer(command_iap,result_iap); if(result_iap[0] != 0) writeText("error erasing\n"); writeText("here3\n"); command_iap[0]=50; //prepare sector 15 for workout command_iap[1]=15; command_iap[2]=15; iap_bypointer(command_iap,result_iap); if(result_iap[0] != 0) writeText("error preparing sector 15\n"); writeText("here4\n"); // strcpy(text, "HELLO WORLD\n"); command_iap[0]=51; //copy RAM to flash command_iap[1]=(unsigned int) destination; // Flash destination command_iap[2]=(unsigned int) source; // RAM source command_iap[3]=256; command_iap[4]=60000; iap_bypointer(command_iap,result_iap); if(result_iap[0] != 0) writeText("error copying\n"); writeText("here5\n"); enabled_interrupts = VICIntEnable; //disable all interrupts VICIntEnClr = enabled_interrupts; memcpy(&workout_receive, destination, sizeof(struct workout)); //memcpy(buffer, destination, strlen(text)); VICIntEnable = enabled_interrupts; //restore interrupt enable register i2cMasterSendNI(TW_MR_DATA_ACK, (u08)strlen(buffer), (u08*)buffer); }
So let me know if I'm wrong, but I think you're saying that I have something like this:
unsigned char raw_buffer[500]; for(i=0; i<sizeof(struct workout); i++) { // copy each variable byte by byte } // Send the raw_buffer instead of workout_send
As for the disabling interrupts, I moved it up before my IAP calls. I have been doing a lot of just static testing to try and make it work before I implement functions that will automate this task. That's why my code is pretty ugly right now.
No, that is what you are doing right now. It works, but is very problematic if you upgrade your software with more/different fields or if you upgrade your compiler.
What I am saying is:
char tmpbuf[CONFIG_SIZE]; char *p = tmpbuf,*size_pos; uint16_t used_size; p = insert_u16(p,CONFIG_VERSION); size_pos = p; p = insert_u16(p,0); p = insert_u16(p,data.field1); p = insert_u32(p,data.field2); ... used_size = p - tmpbuf; // "patch" block with consumed size. insert_u16(size_pos,used_size);
Program this block into flash.
When reading, copy from flash into this raw buffer before extracting.
p = read_u16(p,&version); if (version >= 3) { printf("Unsupported version - exiting\n"); return -1; } p = read_u16(p,&data_size); switch (version) { case 0: expected_size = SIZE_VERSION1; break; case 1: expected_size = SIZE_VERSION2; break; case 2: expected_size = SIZE_VERSION3; break; ... default: printf("Unsupported version!\n"); return -1; } if (data_size != expected_size) { printf("Incorrect size of saved data\n"); return -1; } p = read_u16(p,&data.field1); p = read_u32(p,&data.field2); if (version >= 2) { p = read_u16(p,&data.field3); ... } else { // Old config - use default for new field(s) data.field3 = FIELD3_DEFAULT; ... } if (version >= 3) { p = read_block(p,data.name,32); p = read_u32(p,data.flags); ... } else { strcpy(data.name,"missing"); data.flags = FLAGS_DEFAULT; ... } used_size = p - tmpbuf; if (used_size != expected_size) { printf("Internal error extracting configuration\n"); return -1; } return 0;