CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

PIC12f529T39A read flash memory

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
ralph79



Joined: 29 Aug 2007
Posts: 87

View user's profile Send private message

PIC12f529T39A read flash memory
PostPosted: Thu Oct 12, 2017 10:15 am     Reply with quote

Hi,

I'm having a problem trying to write/read flash memory on PIC12F529T39A, so I'm trying to follow the datasheet instructions but no success. I tried some functions for similar pic's (like pic12f519), from this forum, but again without luck.
The code i have is this:

Code:

#include <12F529T39A.h>

#use delay(internal=4000000)

#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOPROTECT                  //Code protected from reads
#FUSES NOPROTECTDF

#byte EEADR=getenv("SFR:EEADR")
#byte EECON=getenv("SFR:EECON")
#byte EEDATA=getenv("SFR:EEDATA") //EE registers
#bit RD=getenv("BIT:RD")
#bit WR=getenv("BIT:WR")
#bit FREE=getenv("BIT:FREE")
#bit WREN=getenv("BIT:WREN") //EE control bits


#define port_b_dir                      0b001011
//The 'flash data memory' on this chip behaves like a sort of hybrid between
//flash program memory, and EEPROM. The erase size if just 8bytes (so not
//a terribly large 'page', and the control only has a simple 'unlock' sequence

//Implements four routines:
// write_byte_flash(address, value) - writes 'value' to 'address'
// read_byte_flash(address) - returns the byte at 'address'
// erase_row_flash(address) - erases the eight byte row containing 'address'
// write_as_eeprom(address, value) - this is the complex one
//it reads the byte at 'address' and if bits only have to turn 'off' (1->0)
//simply writes the byte. If however any bit has to turn 'on', this cannot
//be done without erasing the page. In this case it reads the whole page
//into a RAM buffer, erases the page, changes the one byte needed, and
//writes the page back. Allows the data flash to be 'written' as if it was
//EEPROM (hence the name), and will not erase if it is not required to do so.

void write_byte_flash(unsigned int8 address, unsigned int8 value)
{
   //write a single byte to an address. This does not erase, so a bit cannot
   //be set to '1' by this routine.
   EEADR=address; //select address
   EEDATA=value; //data to write
   WREN=TRUE; //trigger a write
   WR=TRUE;
}

unsigned int8 read_byte_flash(unsigned int8 address)
{
   //read a single byte from the flash
   unsigned int8 temp;
   EEADR=address; //select address
   RD=TRUE; //trigger a read
   temp=EEDATA;
   return temp;
}

void erase_row_flash(unsigned int8 address)
{
   //The erase uses the top three bits of the specified address as the page to erase
   EEADR=address; //select address
   FREE=TRUE;
   WREN=TRUE;
   WR=TRUE; //trigger the erase
}

//
void write_as_eeprom(unsigned int8 address, unsigned int8 value)
{
   //this allows a single byte to be written to any address and automatically
   //erases if necessary.
   unsigned int8 low3; //low 3 bits of address
   //unsigned int8 buffer[8];
   unsigned int8 temp;
   low3=address&7; //index into the buffer
   //Now I need to determine if the row has to be erased.
   
   temp=read_byte_flash(address);
   //Now if writing the byte would only set bits to zero, an erase is not needed
   if ((value & temp) == value)
   {
      //Just write
      write_byte_flash(address,value);
      return;
   }
   otherwise we need to erase the row.
   First read the row.
   for (temp=0;temp<8;temp++)
   {
      buffer[temp]=read_byte_flash((address&0x38)+temp);
   }
   //Now update the byte to change
   buffer[low3]=value;
   //erase the row
   erase_row_flash(address);
   //and write back all eight bytes
   for (temp=0;temp<8;temp++)
   {
      write_byte_flash((address&0x38)+temp, buffer[temp]);
   }
}

void main()
{
   int8 temp;
   set_tris_b(port_b_dir);     
   setup_wdt(PIN_CHANGE_FROM_SLEEP);
   write_as_eeprom(0,0xAA);
   write_as_eeprom(5,0xAA);
   write_as_eeprom(15,0xAA);
   write_as_eeprom(25,0xAA);
   write_as_eeprom(35,0xAA);

   while (TRUE)
   {
      output_high(PIN_B4);
      delay_ms(200);
      output_low(PIN_B4);
      delay_ms(200);
   }
}


As you can see i'm writing 1 byte in 5 different positions of flash memory. When i try to read the flash memory using MPLAB X IDE or IPE i only see 0xFF, and this way i see that i can't really write in flash.
Do you have any thoughts on how to access to read and write the flash?

This code was compiled with the CCS 5.070.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Oct 12, 2017 8:33 pm     Reply with quote

I don't have vs. 5.070 or any current version of the PCB compiler so I
can't check if the compiler is working properly.

But the first thing I would do is look at the .LST file and make sure
that CCS has all the register addresses and bit positions correct.
Consult the PIC data sheet to see the correct addresses.
Code:

#byte EEADR=getenv("SFR:EEADR")
#byte EECON=getenv("SFR:EECON")
#byte EEDATA=getenv("SFR:EEDATA") //EE registers
#bit RD=getenv("BIT:RD")
#bit WR=getenv("BIT:WR")
#bit FREE=getenv("BIT:FREE")
#bit WREN=getenv("BIT:WREN") //EE control bits


The 2nd thing is, I wouldn't trust MPLAB or the IPE to show me the results.
I would setup a serial port connection and use printf to show the results
on a serial terminal.
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Fri Oct 13, 2017 2:21 am     Reply with quote

I'd also start testing in parts. Put something into an address in the memory at compile time #ROM 0x600=xxxx
Then test your read routine, and see if this reads OK.

You then 'know' you have a working read, so have a starting point to test the writes.

Your code as posted won't compile (remarks missing off lines 83 & 84, and 'buffer' is remmed out).

0xFF is the 'I am erased' state, so I'd be then looking at the write routine.

A quick check with the bugs above corrected, shows the correct code being generated. The compiler is using the bit sets required, and on the correct bits.

The CCS write_eeprom routine does access the registers for this area of memory. However they have omitted an option to erase. So you can substitute their write_eeprom routine for the write_byte_flash routine. I notice that they do perform two NOP's after setting the WR bit. Most chips require this so it is worth trying. Their read_eeprom routine also seems to correctly encode the read_byte_flash, with them again waiting one clock cycle after initiating the read.

Now I can't get the current MPLAB-X to actually accept simulating on the chip. It gives odd errors. So can't try, but:
Code:

#include <12F529T39A.h>

#use delay(internal=4000000)

#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOPROTECT                  //Code protected from reads
#FUSES NOPROTECTDF
#FUSES NOWDT

#byte EEADR=getenv("SFR:EEADR")
#byte EECON=getenv("SFR:EECON")
#byte EEDATA=getenv("SFR:EEDATA") //EE registers
#bit RD=getenv("BIT:RD")
#bit WR=getenv("BIT:WR")
#bit FREE=getenv("BIT:FREE")
#bit WREN=getenv("BIT:WREN") //EE control bits


#define port_b_dir                      0b001011
//The 'flash data memory' on this chip behaves like a sort of hybrid between
//flash program memory, and EEPROM. The erase size if just 8bytes (so not
//a terribly large 'page', and the control only has a simple 'unlock' sequence

//Implements four routines:
// write_byte_flash(address, value) - writes 'value' to 'address'
// read_byte_flash(address) - returns the byte at 'address'
//substituted the CCS routines for these. Slightly smaller.
// erase_row_flash(address) - erases the eight byte row containing 'address'
// write_as_eeprom(address, value) - this is the complex one
//it reads the byte at 'address' and if bits only have to turn 'off' (1->0)
//simply writes the byte. If however any bit has to turn 'on', this cannot
//be done without erasing the page. In this case it reads the whole page
//into a RAM buffer, erases the page, changes the one byte needed, and
//writes the page back. Allows the data flash to be 'written' as if it was
//EEPROM (hence the name), and will not erase if it is not required to do so.


void erase_row_flash(unsigned int8 address)
{
   //The erase uses the top three bits of the specified address as the page to erase
   EEADR=address; //select address
   FREE=TRUE;
   WREN=TRUE;
   WR=TRUE; //trigger the erase
}

//
void write_as_eeprom(unsigned int8 address, unsigned int8 value)
{
   //this allows a single byte to be written to any address and automatically
   //erases if necessary.
   unsigned int8 low3; //low 3 bits of address
   unsigned int8 buffer[8];
   unsigned int8 temp;
   low3=address&7; //index into the buffer
   //Now I need to determine if the row has to be erased.
   
   temp=read_eeprom(address);
   //Now if writing the byte would only set bits to zero, an erase is not needed
   if ((value & temp) == value)
   {
      //Just write
      write_eeprom(address,value);
      return;
   }
   //otherwise we need to erase the row.
   //First read the row.
   for (temp=0;temp<8;temp++)
   {
      buffer[temp]=read_eeprom((address&0x38)+temp);
   }
   //Now update the byte to change
   buffer[low3]=value;
   //erase the row
   erase_row_flash(address);
   //and write back all eight bytes
   for (temp=0;temp<8;temp++)
   {
      write_eeprom((address&0x38)+temp, buffer[temp]);
   }
}

void main()
{
   int8 temp;
   set_tris_b(port_b_dir);     
   setup_wdt(PIN_CHANGE_FROM_SLEEP);
   write_as_eeprom(0,0xAA);
   write_as_eeprom(5,0xAA);
   write_as_eeprom(15,0xAA);
   write_as_eeprom(25,0xAA);
   write_as_eeprom(35,0xAA);
   temp=read_eeprom(0); //test if a byte has been saved.

   while (TRUE)
   {
      output_high(PIN_B4);
      delay_ms(200);
      output_low(PIN_B4);
      delay_ms(200);
   }
}


Looks to be generating sensible assembler for all the functions, with your compiler version.
If you have got the debugger running, test the value in 'temp', to see if it is working.
ralph79



Joined: 29 Aug 2007
Posts: 87

View user's profile Send private message

PostPosted: Fri Oct 13, 2017 8:25 am     Reply with quote

Hi, thanks for your answer.

So i've been testing around with the code you showed and i found out that it doesn't really work the way its intended.
Code:

void main()
{
   set_tris_b(port_b_dir);     
   setup_wdt(PIN_CHANGE_FROM_SLEEP);

   
   while (TRUE)
   {
      if(!input(PIN_B3))
      {
         write_as_eeprom(0x15,0xEA);
         //write_byte_flash(0x15,0xEA);
         delay_ms(500);
      }
     
      if(0xEA == read_eeprom(0x15))
      {
         output_high(PIN_B4);
         delay_ms(500);
         output_low(PIN_B4);
         delay_ms(500);
      }
      else
      {
         output_high(PIN_B4);
         delay_ms(100);
         output_low(PIN_B4);
         delay_ms(100);
      }
   }
}


So i made a LED blink (PIN_B4) with the frequency depending in the condition "if(0xEA == read_eeprom(0x15))", for debug.
Whenever PIN_B3 gets value 0, the PIN_B4 will toggle faster and it actually does.
I tried with write_as_eeprom and write_byte_flash, but everytime i remove the power and insert again the flash gets erased. The only change made to the program was the main function, any thoughts why this is happening?
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Fri Oct 13, 2017 9:27 am     Reply with quote

Try something silly.
Try setting the PROTECTDF fuse and have another go.

I have seen a few PIC's where fuses are reversed from the data sheet...
Now it is unusual to have the 'protection off' state being the erased 'default'. Normally protection defaults to 'on' on erased chips and has to be turned off. Just wonder if this bit is actually reversed and nobody has noticed!....
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Fri Oct 13, 2017 11:25 am     Reply with quote

Just been doing a bit more reading.

It is interesting to look at the PIC16F526 which is another chip with the flash data memory. This specifically says:
Quote:

2: For reads, erases and writes to the Flash
data memory, there is no need to insert a
NOP into the user code as is done on midrange
devices. The instruction immediately
following the “BSF EECON,WR/RD” will be
fetched and executed properly

Now, the PIC12F529T39A, doesn't say this, though the code included leaves these NOP's out. I'm wondering if it does need these?.
So try with:
Code:

void write_byte_flash(unsigned int8 address, unsigned int8 value)
{
   //write a single byte to an address. This does not erase, so a bit cannot
   //be set to '1' by this routine.
   EEADR=address; //select address
   EEDATA=value; //data to write
   WREN=TRUE; //trigger a write
   WR=TRUE;
   delay_cycles(1);
}

unsigned int8 read_byte_flash(unsigned int8 address)
{
   //read a single byte from the flash
   unsigned int8 temp;
   EEADR=address; //select address
   RD=TRUE; //trigger a read
   delay_cycles(1);
   temp=EEDATA;
   return temp;
}

void erase_row_flash(unsigned int8 address)
{
   //The erase uses the top three bits of the specified address as the page to erase
   EEADR=address; //select address
   FREE=TRUE;
   WREN=TRUE;
   WR=TRUE; //trigger the erase
   delay_cycles(1);
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Fri Oct 13, 2017 2:28 pm     Reply with quote

Just had a reply back from CCS. They have got an erase_eeprom function in the code (not documented in the header...). They have sent me a little demo, which I have modified to match your original code:
Code:

//
void write_as_eeprom(unsigned int8 address, unsigned int8 value)
{
   //this allows a single byte to be written to any address and automatically
   //erases if necessary.
   unsigned int8 temp; //single temp variable
   unsigned int8 buffer[8];
   unsigned int8 low3; //low part of address

   //Now I need to determine if the row has to be erased. 
   temp=read_eeprom(address);
   //Now if writing the byte would only set bits to zero, an erase is not needed
   if ((value & temp) == value)
   {
      //Just write
      write_eeprom(address,value);
      return;
   }
   
   low3=address&7; //index into the buffer - no point in doing this earlier
   address &=0xF8; //and the high bits
   
   //otherwise we need to erase the row.
   //First read the row.
   for (temp=0;temp<8;temp++)
   {
      buffer[temp]=read_eeprom(address+temp);
   }

   //Now update the byte to change
   buffer[low3]=value;
   
   //erase the row
   erase_eeprom(address);
   
   //and write back all eight bytes
   for (temp=0;temp<8;temp++)
   {
      write_eeprom(address+temp, buffer[temp]);
   }
}


As you can see I've just slightly optimised things which will save a little space and a few machine cycles.

See if this works. Smile

If it doesn't, it has to be the fuse, or an issue with your chip/hardware (what voltage are you running? - though the data sheet lists Vmin as the minimum voltage for an erase, I have seen several PICs where an erase doesn't work near the bottom of the supply range...).
ralph79



Joined: 29 Aug 2007
Posts: 87

View user's profile Send private message

PostPosted: Mon Oct 16, 2017 9:03 am     Reply with quote

Thanks for the answers but i had no sucess even with that function. I'm running at +/-3V.
I changed the fuses as you suggested but the result was worse, in run time it stopped work (not only when i removed the power).

So i tried some things with XC8 and looking to the .lst file, i was able to make it work in ccs, without erasing after reset.

The code i made to read was:
Code:
      #asm
     
      MOVLW 21
      MOVLB 1
      MOVWF 6
      BSF 1,0
      MOVF 5,w
      MOVLB 0
      MOVWF test
     
      #endasm

And it's working with SQTP.
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Mon Oct 16, 2017 10:47 am     Reply with quote

That's the same as 'test=read_eeprom(33);' (depending on what bank 'test' is in).
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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