# PIC12f1571 Assitance - Reading/Writing to Flash

#### 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;
machineState = PMDATH;
machineState = (machineState << 8) | PMDATL;
updateLEDs(LEDSOFF);
updateLEDs(machineState);
machineState = machineState + 0x0001;
if(machineState == 0x00BD){
machineState == BLUE;
}
writeLEDMemory(machineState);
}

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

void writeLEDMemory(uint16_t stateVal){
INTCONbits.GIE = 0;
eraseFlash();
PMCON1bits.CFGS = 0;
uint8_t tempVal;
tempVal = LEDSTATELOCATION;
tempVal = (LEDSTATELOCATION >> 8);
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;
tempVal = (LEDSTATELOCATION >> 8);
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:

#### shteii01

Joined Feb 19, 2010
4,644
Main?

#### 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){
__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.

#### 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);

#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
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

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.
}

{ // reads and returns the EEPROM byte value at the address given

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

}