PIC12f1571 Assitance - Reading/Writing to Flash

Thread Starter

cl10Greg

Joined Jan 28, 2010
52
Hello,
I am working on a project that is using a PIC12F1571 to run the operation. The goal is to have the microcontroller store the LED state in memory and read it.

At start up, the default state is set and the microcontroller goes asleep. When the buttom is pressed, the state is read, the LEDs are turned on, the state is incremented and stored back into memory. This is repeated until it hits the last address and then it resets back to the default state. If the button is held, the microcontroller is put back to sleep.

Here are the various functions to read/write and update the state.

C:
void updateStateMachine(void){
    uint16_t machineState;
    readLEDMemory();
    machineState = PMDATH;
    machineState = (machineState << 8) | PMDATL;
    //Read the state address
    updateLEDs(LEDSOFF);
    updateLEDs(machineState);
    machineState = machineState + 0x0001;
    if(machineState == 0x00BD){
        machineState == BLUE;
    }
    writeLEDMemory(machineState);
}

void readLEDMemory(){
    uint8_t tempVal;
    PMCON1bits.CFGS = 0;
    tempVal = LEDSTATELOCATION;
    PMADRL = tempVal;
    tempVal = (LEDSTATELOCATION >> 8);
    //tempVal = tempVal & 0x7F;
    PMADRH = tempVal;
    PMCON1bits.RD = 1;
    NOP();
    NOP();
}

void writeLEDMemory(uint16_t stateVal){
    INTCONbits.GIE = 0;
    eraseFlash();
    PMCON1bits.CFGS = 0;
    uint8_t tempVal;
    tempVal = LEDSTATELOCATION;
    PMADRL = tempVal;
    tempVal = (LEDSTATELOCATION >> 8);
    PMADRH = tempVal;
    PMCON1bits.FREE = 0;
    PMCON1bits.LWLO = 1;
    PMCON1bits.WREN = 1;
    tempVal = stateVal;
    PMDATL = tempVal;
    tempVal = (stateVal >> 8);
    PMDATH = tempVal;
    PMCON1bits.LWLO = 0;
    writeUnlockSequence();
    PMCON1bits.WREN = 0;
    INTCONbits.GIE = 1;
}

void eraseFlash(){
    PMCON1bits.CFGS = 0;
    uint8_t tempVal;
    tempVal = LEDSTATELOCATION;
    PMADRL = tempVal;
    tempVal = (LEDSTATELOCATION >> 8);
    PMADRH = tempVal;
    PMCON1bits.FREE = 1;
    PMCON1bits.WREN = 1;
    writeUnlockSequence();
    PMCON1bits.WREN = 0;
}

void writeUnlockSequence(void){
    PMCON2 = 0x55;
    PMCON2 = 0xAA;
    PMCON1bits.WR = 1;
    NOP();
    NOP();
}
When I debug, it looks like the update state does read and increment but when it write the incremented state, it doesn't stick. So it is always reading the default state over and over again and not getting to the next state.

Thoughts?
 
Last edited by a moderator:

Thread Starter

cl10Greg

Joined Jan 28, 2010
52
Hello,
Not at my pc so I can't copy the exact call but it is roughly.

WriteLEDMemory(blue)
UpdateLED (LEDSOFF)
While (1){
UpdateStateMachine ()
__delay_ms (1000)
}

Just testing the writing essentially.
Using xc8 pro and mplab
 

ErnieM

Joined Apr 24, 2011
8,058
I don't see anything in the read routine that actually reads the value placed in PMDAT.

Generally it is best to break a problem into smaller pieces. Write a rock solid read and write functions, debug those completely, then call these from where you need to access the data.
 

Thread Starter

cl10Greg

Joined Jan 28, 2010
52
Hello,

My understanding is that when you set the RD bit, it performs the read operation and populates the register for the data.

The routines both follow the datasheet on the execution on how to do these. It writes the first state correctly (0x00B0 in this case), reads it and sets the LEDs, and even increments but for some reason it just doesn't write it again correctly in the machine state. The only thing I can think of is maybe I have to write the whole row with the latches rather than just one element?
 

spinnaker

Joined Oct 29, 2009
7,835
I don't see anything in the read routine that actually reads the value placed in PMDAT.

Generally it is best to break a problem into smaller pieces. Write a rock solid read and write functions, debug those completely, then call these from where you need to access the data.

Ernie is 100% correct. You are coupling your project's code with a function that is very common. These should be their own standalone reusable functions. It makes your code more readable by others plus you will be able to reuse the code at a later date for another project.

Once you get those functions written, write a test program that does nothing but writes a value then reads that value back. You will want to test the read after you cycle the power to the chip.


Here is an example of functions I wrote years ago and have used many times since. It won't work for your chip but should give you some ideas.


eeprom.h
Code:
#ifndef __EEPROM_H
#define __EEPROM_H


void EEPROM_Write(unsigned char address, unsigned char databyte);
unsigned char EEPROM_Read(unsigned char address);



#endif
eeprom.c
Code:
#include <p18cxxx.h>
#include "eeprom.h"


void EEPROM_Write(unsigned char address, unsigned char databyte)
{ // writes the "databyte" value to EEPROM at the address given
  // location in "address".
  EECON1bits.EEPGD = 0;  // Set to access EEPROM memory
  EECON1bits.CFGS = 0;  // Do not access Config registers

  EEDATA = databyte;  // Load EEDATA with byte to be written
  EEADR = address;  // Load EEADR with address of location to write.

  EECON1bits.WREN = 1;  // Enable writing
  
  // NOTE: as a protective measure to prevent accidental writes, the following
  // sequence must be completed without interruption to write a byte to EEPROM.
  // Therefore, if interrupts are used they should be disabled during the sequence
  // as it would not work if an interrupt was received during the sequence.

  //INTCONbits.GIE = 0;  // Disable interrupts
  EECON2 = 0x55;  // Begin Write sequence
  EECON2 = 0xAA;
  EECON1bits.WR = 1;  // Set WR bit to begin EEPROM write
  //INTCONbits.GIE = 1;  // re-enable interrupts
  
  while (EECON1bits.WR == 1)
  {  // wait for write to complete.  WR bit will be cleared when write finishes
  // EEPROM write completion will also set the EEIF flag bit in PIR2, which
  // may be used to generate an interrupt when the EEPROM write completes.
  };

  EECON1bits.WREN = 0;  // Disable writing as a precaution.
}

unsigned char EEPROM_Read(unsigned char address)
{ // reads and returns the EEPROM byte value at the address given
  // given in "address".

  EECON1bits.EEPGD = 0;  // Set to access EEPROM memory
  EECON1bits.CFGS = 0;  // Do not access Config registers

  EEADR = address;  // Load EEADR with address of location to write.

  // execute the read
  EECON1bits.RD = 1;  // Set the RD bit to execute the EEPROM read

  // The value read is ready the next instruction cycle in EEDATA.  No wait is
  // needed.

  return EEDATA;
}
 
Top