Question

I want to store a number to PIC18 then retain it even if the power is lost or the unit is reset. I think my writing code portion looks fine, just the reading portion of it looks strange after the unit is reset.

I am using the following code which I got from Microchip.

Code:

unsigned int value;
unsigned int DEEdata = 1;
unsigned int  DEEaddr = 0x04;

DataEEInit();
dataEEFlags.val = 0;

DataEEWrite(DEEdata,DEEaddr);
value = DataEERead(DEEaddr);
Nop();
printf("%d",value);

The ouput: 1

However when I reset the unit and only use the reading code I always get 255.

Code to read:

DataEEInit();
value = DataEERead(DEEaddr);
printf("%d",value);

The output: 255

Why is this happening? I am assuming maybe the value is not being saved or the reading portion is incorrect. Thank you!

Was it helpful?

Solution 5

Some PIC18 micros have an internal EEPROM in addition to the internal flash. The 18F87J11 does not have this so you have 2 options:

1) Write to the flash memory - this is where your program is stored. make sure the number of write/read cycles is ok for your application.

2) Use an external i2c or spi memory for your configuration settings

The DataEEWrite you are using are from an 'eeprom emulation' library from microchip (linked in the comments below. There are a couple of things to be careful of:

  • Watch out when reprogramming the flash! you might overwrite your settings
  • Remember it isn't really eeprom! The write cycles are limited and you have to erase big sections of memory - you can't erase a single byte

OTHER TIPS

Two functions: write to flash using 64-byte buffer @ 8-byte blocks and a read/compare flash function.

For device: PIC18F46K80

Stuff for a header file:

#define PRGM_BUFFER_SIZE 8
#define TABLE_WRITE_SIZE 64

#define LOAD_TBL_PTR(x) { TBLPTRU = ((((x)>>8)>>8)&0xff);\
                      TBLPTRH = (((x) >> 8) & 0xff);\
                      TBLPTRL = ((x) & 0xff);\
                    }

Write to flash function:

/******************************************************
 * Function     : write_block
 * Input        : uint16_t position in destination flash
 * Global       : uint8_t buffer[64] - Location of source data
 * Output       : None
 * Description  : Writes the contents of the 64 byte
 * data buffer to program flash space.  Only 64 bytes
 * can be written at once.   The process of writing
 * to flash is: Erase->Write.
 ******************************************************/
static void write_block(uint16_t addr)
{
    int r, c;

    // Erase flash block first.  Erases a 64 byte block at a time.

    LOAD_TBL_PTR(addr);

    EECON1bits.EEPGD = 1;   // Point to flash program memory
    EECON1bits.CFGS = 0;    // Access flash memory
    EECON1bits.WREN = 1;    // Enable write to memory
    EECON1bits.FREE = 1;    // Enable Erase operation

    EECON2 = 0x55;
    EECON2 = 0xAA;

    EECON1bits.WR = 1;      // Clear the flash

    asm("NOP");             // Stall

    // Write buffer to internal buffer.  This process writes 8 bytes at a time
    // so we need to loop 8 times (8*8 = 64).)

    for (r = 0; r < 8; r++)
    {
        LOAD_TBL_PTR((addr + (r * 8)));

        for (c = 0; c < PRGM_BUFFER_SIZE; c++)
        {
            TABLAT = buffer[(r * 8) + c];

            asm("TBLWT*+");      // Push byte and then inc to next internal buffer cell
        }

        // Write the block to flash

        asm("TBLRD*-");         // Point back to original row

        // Write internal buffer to flash

        EECON1bits.EEPGD = 1;   // Point to flash program memory
        EECON1bits.CFGS = 0;    // Access flash program memory
        EECON1bits.WREN = 1;    // Enable write to memory
        INTCONbits.GIE = 0;     // Disable interrupts

        EECON2 = 0x55;
        EECON2 = 0xAA;

        EECON1bits.WR = 1;      // Start programming flash
        INTCONbits.GIE = 1;     // Re-enable interrupts
        EECON1bits.WREN = 0;    // Disable write to memory
    }
}

Verify written data (demonstrates flash read)

/******************************************************
 * Function     : compare_block
 * Input        : uint16_t position in destination flash
 * Global       : uint8_t buffer[64] - Location of previous written data
 * Output       : bool true=successful, false=did not match
 * Description  : Reads a 64 byte block of flash memory and
 * compares it to the data found in the global buffer.
 ******************************************************/
static bool compare_block(uint16_t addr)
{
    bool retVal = true; // succeeds
    uint8_t i = 0;

    INTCONbits.GIE = 0;     // Disable interrupts

    LOAD_TBL_PTR(addr);

    for (i = 0; i < TABLE_WRITE_SIZE && retVal == true; i++)
    {
        asm("TBLRD*+");

        if (buffer[i] != TABLAT)
            retVal = false;
    }

    INTCONbits.GIE = 1;     // Enable interrupts

    return retVal;
}

Yours, Bryan Wilcutt

The device you're using doesn't have internal non-volatile memory apart from its Flash, generally used for storing code.

You have two options that I can see:

  1. Use some external Flash or EEPROM and interface it to the External Memory Bus that's available on this PIC (see page 97 of the Family Datasheet).
  2. Remap the internal Flash to reserve a small portion that can be used for storing your data (so that it doesn't interfere with the memory area used exclusively for code) and write your data into this region (page 87).

I haven't worked with PICs for years, so can't offer you much in the way of implementation detail but I suspect there are many examples you can source from Microchip's website.

In essence, the reason your code doesn't work is because you're trying to access memory that isn't there. If it is there, then the interface is not correct.

EDIT:

I've had a look through the code examples page for the PIC18 on Microchip's website and can't find any C examples for writing to the program memory. Unfortunately, it looks like you'll have to implement it in assembler. I don't know the semantics for the MPLAB compiler but, generally, it'll be something like this if you're going to do it inline:

void my_assembler_function(void)
{
    // Inline assembler code, actioned via C.
    asm("MOV x y");
    asm("MOV y z");
}

Alternatively, many C compilers for microprocessor's allow you to call an external .s file with a C function call, saving you from doing it inline.

I think you can follow the example I found here to actually implement the functionality you're after.

SRAM can not be used to store Non-volatile data...

SRAM will loose data during power cycle...

Options: 1. Use internal EEPROM if available. 2. External EEPROM through I2C or SPI. 3. PIC18 Data Emulation Library.

This is an explanation of the PIC18:

/* EEPROM Read and Write Functions -- WORKING
 * Used PIC18F45K22 and MPLAB and C18
 * Read and Write functions work.
 * EEPROM has 256 bytes of memory (256 distinct characters)
 * Select "Window" -> "PIC Memory Views" -> "EE Data Memory"
 * Download program to PIC18
 * Hold PIC in Reset (circle arrow with pause button)
 * Open EE Data Memory Tab and click "Read Device Memory" button (Top left of EE Data tab) while PIC is held in Reset
 */

This is helpful code:

#include <p18cxxx.h>
#include <p18f45k22.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

#pragma config FOSC = INTIO67, PLLCFG = OFF, PRICLKEN = ON, FCMEN = ON,     PWRTEN = OFF
#pragma config BOREN = SBORDIS, BORV = 250, WDTEN = OFF, WDTPS = 2048,    PBADEN = OFF, WRTD = OFF
#pragma config HFOFST = OFF, MCLRE = EXTMCLR, STVREN = ON, LVP = OFF, DEBUG = ON, CPD = OFF

void EE_Write(unsigned char addr, unsigned char value);
unsigned char EE_Read(unsigned char addr);

unsigned char test;

void main(void){
    OSCTUNEbits.PLLEN = 1;
    OSCCON = 0x4C; //Set to use internal clock.
    OSCCON2 = 0x00; // No 4x PLL

    TRISB = 0x00;
    ANSELB = 0x00;
    PORTB = 0x00;

    EE_Write(05, 0x5A);
    Delay10KTCYx(50);
    test = EE_Read(05);

    Delay10KTCYx(50);
    PORTB = 0xFF;

    Delay10KTCYx(50);
    PORTB = 0x00;

}

void EE_Write(unsigned char addr, unsigned char value)         
{         
    unsigned char SaveGIE = 0;         

    // Set EEPROM address                
    EEADR  = addr%256;         
    // Set EEPROM data         
    EEDATA = value;         
    // Select Data         
    EECON1bits.EEPGD = 0;         
    // Select EEPROM         
    EECON1bits.CFGS = 0;         
    // Enable write         
    EECON1bits.WREN = 1;         
    // Save current global interrupt enable state         
    SaveGIE = INTCONbits.GIE;         
    // Disable interrupts         
    INTCONbits.GIE = 0;         
    // Write unlock sequence         
    EECON2 = 0x55;         
    EECON2 = 0xaa;         
    // Start write         
    EECON1bits.WR = 1;         
    // Restore previous interrupts enable state         
    INTCONbits.GIE = SaveGIE;         
    // Wait for write completion         
    while(EECON1bits.WR);        
    // Disable writes         
    EECON1bits.WREN = 0;         
}

unsigned char EE_Read(unsigned char addr){

    while(EECON1bits.RD || EECON1bits.WR); // check the WR&RD bit to see    if a RD/WR is in progress
    EEADR = addr; // Write the address to EEADR.
    EECON1bits.CFGS = 0;
    EECON1bits.EEPGD = 0;
    EECON1bits.RD = 1; // Set the RD bit to trigger the eeprom read  operation.
    return(EEDATA);
}

The value of 255 is default value for EEPROM memory. I think after changing the code, you program microcontroller IC again. So, your EEPROM memory will be erased and return to its default value. If you use MPLAB as compiler, you can go to 'Programmer'tab > Settings.. > Program Memory > Program Options and click on Preserve EEPROM on Program. Hope it works.

To retain the values on power cycle, SRAM memory should be used. Please confirm if you have SRAM memory available first.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top