|
|
View previous topic :: View next topic |
Author |
Message |
newby125
Joined: 17 Mar 2010 Posts: 4
|
PIC24 Program memory re-write issue |
Posted: Wed Mar 17, 2010 3:50 pm |
|
|
I am using PCDIDE 4.097 and PIC24FJ64GA002.
I am reserving space within the program memory to store parameters and have been having an issue with re-writing to the program memory. It writes/reads correctly only the first time through. I've tried numerous options with no success. Can anyone help?
Code: |
#include <24fj64ga002.h>
#PIN_SELECT U1TX = PIN_B5 // UART1 transmit
#PIN_SELECT U1RX = PIN_B7 // UART1 receive
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#fuses NOPROTECT,WDT,HS,NODEBUG,NOWRT
#use delay(clock=11.0592M, oscillator=11.0592M)
#use rs232(UART1,BAUD=57600,parity=N,bits=8,ERRORS,stream=test)
typedef unsigned int8 uint8_t;
typedef signed int8 int8_t;
typedef unsigned int16 uint16_t;
typedef signed int16 int16_t;
typedef unsigned int32 uint32_t;
typedef signed int32 int32_t;
//defines for internal flash memory
#define PROGRAM_MEMORY_SIZE getenv("PROGRAM_MEMORY")
//so define the total amount of memory I want
#define FLASH_DATA_SIZE 12
//Define the end point of my block of flash (the very last byte of flash available)
#define FLASH_DATA_END PROGRAM_MEMORY_SIZE-1
//Now define where the start of my data will be by subtracting the amount I want from the
//size of the memory
#define FLASH_DATA_START (PROGRAM_MEMORY_SIZE - FLASH_DATA_SIZE)
#define OFFSET_FOR_NUMBER1 0
#define OFFSET_FOR_NUMBER2 4
#define OFFSET_FOR_NUMBER3 8
//Now tell the compiler to reserve this for me
#org FLASH_DATA_START, FLASH_DATA_END {}
int writeToFlash(uint32_t location, char *buffer, uint16_t count);
int readFromFlash(uint32_t location, char *buffer, uint16_t count);
/*********
* Main
*********/
void main(void) {
uint8_t write_num = 0;
uint8_t read_num = 0;
printf("\r\nCompiled on %s at %s", __DATE__, __TIME__);
setup_wdt(WDT_ON);
setup_rtc(RTC_ENABLE, 0x00);
enable_interrupts(int_rtc);
enable_interrupts(INTR_GLOBAL);
while(TRUE)
{
write_num++;
restart_wdt(); // restart watchdog timer
writeToFlash(FLASH_DATA_START + OFFSET_FOR_NUMBER1, &write_num, sizeof(write_num));
delay_ms(500);
ReadFromFlash(FLASH_DATA_START + OFFSET_FOR_NUMBER1, &read_num, sizeof(read_num));
delay_ms(500);
writeToFlash(FLASH_DATA_START + OFFSET_FOR_NUMBER2, &write_num, sizeof(write_num));
delay_ms(500);
ReadFromFlash(FLASH_DATA_START + OFFSET_FOR_NUMBER2, &read_num, sizeof(read_num));
delay_ms(500);
writeToFlash(FLASH_DATA_START + OFFSET_FOR_NUMBER3, &write_num, sizeof(write_num));
delay_ms(500);
ReadFromFlash(FLASH_DATA_START + OFFSET_FOR_NUMBER3, &read_num, sizeof(read_num));
delay_ms(500);
}
}
/*******************************************************************************
* Writes buffer to flash for storage. The flash on the PIC24 was designed to
* hold 24bit instructions, and therefore converts every 4th byte to NULL
* when being written to. This function compensates for that to prevent data
* loss/corruption.
* @param buffer char pointer to the data to be written
* @param count int16 number of bytes to write to flash.
* @returns number of bytes written to flash
******************************************************************************/
int writeToFlash(uint32_t location, char* buffer, uint16_t count)
{
int16 write_count = 0;
char write_buffer[640] = {0};
int16 i = 0;
if (location < FLASH_DATA_START || location > FLASH_DATA_END)
{
fprintf(test, "\r\nwriting to internal flash failed due to out of boundary check");
return 0;
}
disable_interrupts(INTR_GLOBAL);
for(i = 0; i < count; i++)
{
/* skip every 4th byte starting with buffer[3] */
if(write_count != 0 && ((write_count + 1) % 4 == 0))
{
write_count++;
}
write_buffer[write_count++] = buffer[i];
}
write_count++;
if(write_count < 4)
{
write_count = 4;
}
write_program_memory(location, write_buffer, write_count);
fprintf(test, "\r\nwriting %d bytes to flash", write_count);
// Display write_buffer
fprintf(test, "\r\nwrite_buffer: ");
for(i = 0; i < write_count; i++)
fprintf(test, "%X ", write_buffer[i]);
fprintf(test, "\n\r");
fprintf(test, "\n\r");
enable_interrupts(INTR_GLOBAL);
return write_count;
}
/*******************************************************************************
* Reads from flash storage, skips every 4th byte to remove the NULL byte
* written by the hardware when writing to the flash memory.
* @param buffer char pointer for the data to be written into
* @param count int16 number of bytes to read from the flash.
* NOTE: This number is the number of bytes written to the flash
* INCLUDING the NULLs, not the number of bytes of data given
* to the writeToFlash call.
* @returns number of bytes read without the NULL bytes.
******************************************************************************/
int readFromFlash(uint32_t location, char* buffer, uint16_t count)
{
char read_buffer[640] = {0};
int16 i = 0, j = 0;
disable_interrupts(INTR_GLOBAL);
fprintf(test, "reading %d bytes from flash\r\n", count);
read_program_memory(location, read_buffer, count);
// Display read_buffer
printf("read_buffer: ");
for(i = 0; i < count; i++)
printf("%X ", read_buffer[i]);
printf("\n\r");
printf("\n\r");
for(i = 0; i < count; i++)
{
/* skip every 4th byte starting with 3 */
if(i != 0 && ((i + 1) % 4 == 0))
{
continue;
}
buffer[j++] = read_buffer[i];
delay_ms(1);
}
enable_interrupts(INTR_GLOBAL);
return j;
}
|
Output:
Compiled on 17-Mar-10 at 17:19:29
writing 4 bytes to flash
write_buffer: 01 00 00 00
reading 1 bytes from flash
read_buffer: 01
writing 4 bytes to flash
write_buffer: 01 00 00 00
reading 1 bytes from flash
read_buffer: 01
writing 4 bytes to flash
write_buffer: 01 00 00 00
reading 1 bytes from flash
read_buffer: 01
writing 4 bytes to flash
write_buffer: 02 00 00 00
reading 1 bytes from flash
read_buffer: 00
writing 4 bytes to flash
write_buffer: 02 00 00 00
reading 1 bytes from flash
read_buffer: 00
writing 4 bytes to flash
write_buffer: 02 00 00 00
reading 1 bytes from flash
read_buffer: 00
.........
|
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Thu Mar 18, 2010 12:52 am |
|
|
Obviously, your code ignores the fact, that write_program_memory() only erases the flash, when the write
starts at a page boundary.
The PCD manual clarifies:
Quote: | In order to get the desired results while using write_program_memory(), the block of memory being written to needs to first be read in order to save any other variables currently stored there, then erased to clear all values in the block before the new values can be written. This is because the write_program_memory() function does not save any values in memory and will only erase the block if the first location is written to. If this process is not followed, when new values are written to the block, they will appear as garbage values. |
Microchips AN1095 Emulating Data EEPROM for PIC18 and PIC24 shows a method to use PIC24 internal
flash for parameter storage effectively and without exhausting the memory early by frequent erase actions. |
|
|
newby125
Joined: 17 Mar 2010 Posts: 4
|
|
Posted: Thu Mar 18, 2010 7:53 am |
|
|
Thanks for the info FvM.
In the end I only plan on writing my parameters when they are manually changed which won't be that often. Since I'm not overly concerned with exhausting the memory I would like to modify my existing functions to allow the reads/re-writes to work properly. I did read that an erase is performed on the whole block when the write is about to happen to a location that is a multiple of FLASH_ERASE_SIZE. Is there an easy way that I can lay out my parameters in memory so that they can be erased individually as separate blocks and all be multiples of FLASH_ERASE_SIZE?
Thanks... |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Thu Mar 18, 2010 12:19 pm |
|
|
Page size respectively FLASH_ERASE_SIZE of PIC24 is 0x800 Bytes. A resaonable method is to assign a memory structure
in RAM for your parameters and read and write it as a whole. |
|
|
newby125
Joined: 17 Mar 2010 Posts: 4
|
|
Posted: Thu Mar 18, 2010 1:53 pm |
|
|
That sounds like a great idea. I'll give that a try.
Thanks again.... |
|
|
dtaulbee
Joined: 18 Jun 2008 Posts: 2
|
|
Posted: Thu Apr 28, 2011 2:45 pm |
|
|
Newby, did you ever solve this issue? I have a similar situation where I only need to write data a maximum of 5 or 10 times in the entire life of the product. I think using the #org directive and write_program_memory I can accomplish this, but I just haven't gotten it to work quite right yet. Your method was pretty elegant, so I thought I'd ask if you'd made progress. Thanks! _________________ Everything should be made as simple as possible, but not simpler. -Albert Einstein |
|
|
newby125
Joined: 17 Mar 2010 Posts: 4
|
|
Posted: Fri Apr 29, 2011 7:08 am |
|
|
It's been quite a while since I've looked at this code, but I believe my issue was with my memory location. I did get this working though and used the code in this topic as a template for my final implementation. Here is some code that may help:
Code: |
#define WRITE_SIZE getenv("FLASH_WRITE_SIZE")
#define BUFFER_START 0x9800 // closest location in available program memory (PROGRAM_MEMORY - FLASH_ERASE_SIZE)
// which is a multiple of FLASH_ERASE_SIZE (to auto erase the page properly before writing)
//struct used to store parameters to internal program memory
struct{
unsigned int32 parameter1;
unsigned int32 parameter2;
unsigned int32 parameter3;
unsigned int32 parameter4;
unsigned int32 parameter5;
unsigned int32 parameter6;
unsigned int32 parameter7;
unsigned int32 parameter8;
unsigned int32 parameter9;
unsigned int32 parameter10;
unsigned int32 parameter11;
unsigned int32 parameter12;
unsigned int32 parameter13;
unsigned int32 parameter14;
unsigned int16 parameter15;
}params;
//now use the following lines to write and read the parameters
write_program_memory(BUFFER_START, ¶ms, WRITE_SIZE); // save parameter struct to internal flash
read_program_memory(BUFFER_START, ¶ms, WRITE_SIZE); // read all parameters into the parameter struct
|
Hope this helps. Let me know if you get it working and maybe a coding example of how you accomplished this. |
|
|
|
|
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
|