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 support@ccsinfo.com

Flash write and read functions - 16F526

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



Joined: 09 Oct 2009
Posts: 26

View user's profile Send private message Send e-mail

Flash write and read functions - 16F526
PostPosted: Wed Jan 06, 2016 5:21 am     Reply with quote

Hi,

I'm looking for help about flash memory write and read functions. I'm trying to implement a kind of LED flash light with 4 diferent frequencies. I choose the frequency with input B2 port and it should be in memory in the next turn on of the LED light. At this moment when I turn on my system the last frequency selected is lost.

Anyone can help me with flash write and read funtions?
Code:

// Control LED light

#include <16f526.h>
#device ADC=8
#fuses INTRC,NOWDT,NOMCLR,PROTECT
#use delay(clock=8000000)
#include <math.h>

int8 flag_system=0;

// Function - System A
void Sistema_A(){
 flag_system=0;
 //write_eeprom(0,0);
 write_bank(0,0,0);
}

// Function System B
void Sistema_B(){
 flag_system=1;
 //write_eeprom(0,1);
 write_bank(0,0,1);
}

// Function System C
void Sistema_C(){
 flag_system=2;
 //write_eeprom(0,2);
 write_bank(0,0,2);
}

// Function System D
void Sistema_D(){
 flag_system=3;
 //write_eeprom(0,3);
 write_bank(0,0,3);
}

// Function to select system
void SelectSystem()
{
 int8 flag;
 //flag=read_eeprom(0);
 //flag=read_bank(0,0);
 flag=flag_system;

 if(flag==0)
 {
 Sistema_A();
 delay_ms(1);
 }
 else if(flag==1)
 {
 Sistema_B();
 delay_ms(1);
 }
 else if(flag==2)
 {
 Sistema_C();
 delay_ms(1);
 }
 else if(flag==3)
 {
 Sistema_D();
 delay_ms(1);
 }

 while(true)
 {
 if(input(PIN_B2))
 {
 delay_ms(20);
 if(input(PIN_B2))
 {
 if(flag_system==0)
 {
 delay_ms(50);
 Sistema_B();
 break;
 }
 else if(flag_system==1)
 {
 delay_ms(50);
 Sistema_C();
 break;
 }
 else if(flag_system==2)
 {
 delay_ms(50);
 Sistema_D();
 break;
 }
 else if(flag_system==3)
 {
 delay_ms(50);
 Sistema_A();
 break;
 }

 }
 }
 break;
 }
 delay_ms(10);
}

void main() {

 set_tris_c(0x00);

 SETUP_ADC(ADC_OFF);
 SETUP_ADC_PORTS(NO_ANALOGS);
 setup_comparator(NC_NC_NC_NC);

 while(true)
 {
 SelectSystem();

 if(flag_system==0)
 { // Sistema A
 output_high(PIN_C0); // Leds on 50ms
 delay_ms(50); // Ton
 output_low(PIN_C0);
 delay_ms(50);

 output_high(PIN_C0); // Leds on
 delay_ms(50); // Ton
 output_low(PIN_C0);
 delay_ms(50);

 output_high(PIN_C0); // Leds on
 delay_ms(150); // Ton
 output_low(PIN_C0);
 delay_ms(450);
 }

 else if(flag_system==1)
 {
 output_high(PIN_C0); // Leds on 50ms
 delay_ms(50); // Ton
 output_low(PIN_C0);
 delay_ms(50);

 output_high(PIN_C0); // Leds on
 delay_ms(150); // Ton
 output_low(PIN_C0);
 delay_ms(450);
 }

 else if(flag_system==2)
 {
 output_high(PIN_C0);
 delay_ms(350);
 output_low(PIN_C0);
 delay_ms(350);
 }

 else if(flag_system==3)
 { // Sistema D
 output_high(PIN_C0); // Leds on 50ms
 delay_ms(50); // Ton
 output_low(PIN_C0);
 delay_ms(50);

 output_high(PIN_C0); // Leds on
 delay_ms(150); // Ton
 output_low(PIN_C0);
 delay_ms(150);

 output_high(PIN_C0); // Leds on
 delay_ms(50); // Ton
 output_low(PIN_C0);
 delay_ms(50);

 output_high(PIN_C0); // Leds on 50ms
 delay_ms(150); // Ton
 output_low(PIN_C0);
 delay_ms(750);
 }
 }
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19394

View user's profile Send private message

PostPosted: Wed Jan 06, 2016 6:15 am     Reply with quote

Your chip does not have eeprom. This is why 'write_eeprom' didn't work.

Write_bank, is a command to write to the _RAM_ bank directly. Won't save the data in the flash.

The flash is accessed by 'write_program_memory'.

This is relatively complex to use. It'll only erase if you write to the first byte in a page. Then on your chip only alternate bytes can actually store a 'byte', The next location only stores 6 bits, and you need to be using an area above the code.
The example for this is ex_intfl.c
Look at this first.

For you, choose the top row in memory. The row is 64 bytes on your chip, so use:
Code:

#define start_addr getenv("PROGRAM_MEMORY") - 64
#org start_addr,start_addr+64 {}


Which will reserve the top 64 bytes of memory to use.
aldina



Joined: 09 Oct 2009
Posts: 26

View user's profile Send private message Send e-mail

PostPosted: Wed Jan 13, 2016 9:07 am     Reply with quote

Hi Ttelmah,

Thank you for you help.

I've tried but now I'm compiling and I have the following error: Invalid ORG range
My code now is:
Code:

#include <16f526.h>
#device ADC=8
#fuses INTRC,NOWDT,NOMCLR,PROTECT
#use delay(clock=8000000)
#include <math.h>
#include <stdio.h>
#include <stdlibm.h>

#define start_addr getenv("PROGRAM_MEMORY") - 64
#org start_addr,start_addr+64 {}

//#define Storage 0x43C // end of program memory is 0x43F for 16F526
//#rom int8 Storage = {0x00, 0x01, 0x02, 0x03}


int8 flag_system = 0x00;

// Function - System A
void Sistema_A(){
   flag_system = 0x00;
   //write_eeprom(0,0);
   //write_bank(0,0,0);
   write_program_memory(start_addr, &flag_system, sizeof(flag_system));
}

// Function System B
void Sistema_B(){
   flag_system = 0X01;
   //write_eeprom(0,1);
   //write_bank(0,0,1);
   write_program_memory(start_addr, &flag_system, sizeof(flag_system));
}

// Function System C
void Sistema_C(){
   flag_system = 0X02;
   //write_eeprom(0,2);
   //write_bank(0,0,2);
   write_program_memory(start_addr, &flag_system, sizeof(flag_system));
}

// Function System D
void Sistema_D(){
   flag_system = 0X03;
   //write_eeprom(0,3);
   //write_bank(0,0,3);
   write_program_memory(start_addr, &flag_system, sizeof(flag_system));
}

// Function to select system
void SelectSystem()
{
   int8 flag;
   //flag=read_eeprom(0);
   //flag=read_bank(0,0);
   flag=flag_system;
   
   if(flag==0)
   {
      Sistema_A();
      delay_ms(1);
   }
   else if(flag==1)
   {
     Sistema_B();
     delay_ms(1);
   }
   else if(flag==2)
   {
    Sistema_C();
    delay_ms(1);
   }
   else if(flag==3)
   {
      Sistema_D();
      delay_ms(1);
   }

   while(true)
   {
      if(input(PIN_B2))
      {
         delay_ms(20);
         if(input(PIN_B2))
         {
            if(flag_system==0)
            {
               delay_ms(50);
               Sistema_B();
               break;
            }
            else if(flag_system==1)
            {
               delay_ms(50);
               Sistema_C();
               break;
            }
            else if(flag_system==2)
            {
               delay_ms(50);
               Sistema_D();
               break;
            }
            else if(flag_system==3)
            {
               delay_ms(50);
               Sistema_A();
               break;
            }
 
         }
      }
      break;
   }
   delay_ms(10);
}

void main() {

   set_tris_c(0x00); 
   
   SETUP_ADC(ADC_OFF);
   SETUP_ADC_PORTS(NO_ANALOGS); 
   setup_comparator(NC_NC_NC_NC);
 
   while(true)
   {
       SelectSystem();
   
       if(flag_system==0)
       {   // Sistema A
          output_high(PIN_C0); // Leds on 50ms
          delay_ms(50);  // Ton
          output_low(PIN_C0);
          delay_ms(50);
         
          output_high(PIN_C0); // Leds on
          delay_ms(50);  // Ton
          output_low(PIN_C0);
          delay_ms(50);
         
          output_high(PIN_C0); // Leds on
          delay_ms(150);  // Ton
          output_low(PIN_C0);
          delay_ms(450);
       }
       
       else if(flag_system==1)
       {
          output_high(PIN_C0); // Leds on 50ms
          delay_ms(50);  // Ton
          output_low(PIN_C0);
          delay_ms(50);
         
          output_high(PIN_C0); // Leds on
          delay_ms(150);  // Ton
          output_low(PIN_C0);
          delay_ms(450);
       }
           
       else if(flag_system==2)
       {
          output_high(PIN_C0);
          delay_ms(350);
          output_low(PIN_C0);
          delay_ms(350);
       }
           
       else if(flag_system==3)
       {   // Sistema D     
          output_high(PIN_C0); // Leds on 50ms
          delay_ms(50);  // Ton
          output_low(PIN_C0);
          delay_ms(50);
         
          output_high(PIN_C0); // Leds on
          delay_ms(150);  // Ton
          output_low(PIN_C0);
          delay_ms(150);
         
          output_high(PIN_C0); // Leds on
          delay_ms(50);  // Ton
          output_low(PIN_C0);
          delay_ms(50);
         
          output_high(PIN_C0); // Leds on 50ms
          delay_ms(150);  // Ton
          output_low(PIN_C0);
          delay_ms(750);
       }
    }
}

My idea is:
I have a switch connected to the B2 input port. When we push it, input B2 go high and the LED flash mode changes. if we turn off the system, the actual flash mode should be reserved in memory and next time we turn on, that mode should be the mode working.

If I comment: //#org start_addr,start_addr+64 {} and compile I have other error: undifined identifier -- write_program_memory.

I think I'm doing something so bad, I never used the flash memory before, so I have some dificulties. I saw the exemple you have recommended but I think I don't understand.
Someone that know how use write_program_memory function can help me.
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Wed Jan 13, 2016 9:22 am     Reply with quote

This PIC is unusual in that it doesn't have EEPROM but DOES have a 64byte area of flash set aside (not in program memory space) for data storage. This area is arranged as eight rows of eight bytes each. The datasheet suggests it accessed through SFRs similar to, but not the same as the EEPROM would be as a row has to be erased before it is written to, much like program memory. EEPROMs, of course, are byte writable.

I have not used these PICs and I don't know if CCS C has support for this unusual (for PICS) memory arrangement.
Ttelmah



Joined: 11 Mar 2010
Posts: 19394

View user's profile Send private message

PostPosted: Wed Jan 13, 2016 3:51 pm     Reply with quote

Take a step back here.

RF_Developer is right. This PIC is unusual, in the layout of it's memory.
It has a 'flash data area', that is designed for storage with a high life like an EEPROM, but works in small (8 byte) pages and is operated like the flash program memory.

Now CCS have elected to implement the only routines they offer under the names 'write_eeprom', and 'read_eeprom'. However they have got the routines completely wrong....
They talk to the wrong registers, in the wrong sequence. The read routine makes no attempt to access the data returned, and the write routine does not use the correct access sequence. There is also no erase. Sad

I'll try tomorrow, to code some 'hand built' routines to match the code given by MicroChip in the data sheet.

So it is not your fault that things haven't worked for you Aldina. The code is completely screwed with the compiler (5.053). I've not seen another chip with the memory quite like this, and obviously nobody has previously tried this chip and realised that things are wrong. The memory is similar to that used on the 12F519, and it is this that CCS have flagged in their settings as the code to use, but parts of the routines are wrong. So they load the EEDATA register, set the bit to read, but then don't read the data back.

Code:

....................    temp-read_eeprom(0);
0016:  BSF    FSR.5
0017:  CLRF   EEADR
0018:  BSF    EECON.0
0019:  NOP
//then no read at this point....


There are other similar faults in the write routine.

So if you can wait a while I'll publish routines tomorrow.
Ttelmah



Joined: 11 Mar 2010
Posts: 19394

View user's profile Send private message

PostPosted: Thu Jan 14, 2016 3:39 am     Reply with quote

OK. working write/read code for this chip. Lots of notes inside:

526flash.h
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 '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.
   
   buffer[0]=read_byte_flash(address);
   //Now if writing the byte would only set bits to zero, an erase is not needed
   if ((value & buffer[0]) == 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]);
   }
}


And a basic test program to use this
Code:

#include <16f526.h>
#device ADC=8
#device *=8
#fuses INTRC,NOWDT,NOMCLR
#use delay(clock=8000000)
#use rs232 (XMIT=PIN_B0, baud=9600)
//simple output for debugging

//Simple test program to demonstrate the internal data flash
#include "526flash.h" //code to access this memory
//Now key to understand with this memory, is that when erased all the bits
//are'1'. A write can change a bit from '1' to '0', but cannot change a bit from
//'0' to '1'. To change a bit to '1', the row has to be erased. So if when
//writing a value, a bit needs to change to '1', the page containing the byte
//has to be erased first. This means all the other bytes in this page, need to
//be read, and then the whole page written back.
//I've 'encapsulated' this in a routine that checks which way the bits have
//to change and automatically performs the read and erase if needed.
//This is 'write_as_eeprom'. Notes in the include file.

void main()
{
   int8 temp;

   SETUP_ADC(ADC_OFF);
   SETUP_ADC_PORTS(NO_ANALOGS);
   setup_comparator(NC_NC_NC_NC);

   //Minimum test program
   //This will store a byte, then read it, but then write a second byte to the
   //same page, then write to this location a second time, requiring bits to
   //be set, and then read the both locations and verify the erase/'auto save'
   //has worked.
   write_as_eeprom(0,0xAA); //write a byte
   temp=read_byte_flash(0); //read it
   printf("Byte at zero %2x\n\r",temp); //diagnostic
   write_as_eeprom(1,0x50); //now write to address 1
   //second write forcing an erase..
   write_as_eeprom(1,0x55); //Needs two bits in the low nibble set to '1'
   //so the page has to erase if it is to work...
   temp=read_byte_flash(0); //now check if byte 0 is still OK
   printf("Byte at zero %2x\n\r",temp); //diagnostic byte 0
   temp=read_byte_flash(1); //and do the same for byte 1
   printf("Byte at one %2x\n\r",temp); //diagnostic byte 1
 
   while (TRUE)
      ; //stop and do nothing else
}


This writes a byte to address 0, then reads this and verifies that the read and write are working, then writes a second byte to address 1, then writes to this a second time, using a value that now cannot be written without an erase. It then reads both byte 0 and byte 1, to verify that the write has occurred, and that the data has been updated without being destroyed by the erase.
edi



Joined: 22 Dec 2003
Posts: 82

View user's profile Send private message

Flash write on 16F1508
PostPosted: Thu Mar 10, 2016 2:06 pm     Reply with quote

Ttelmah thanks for your detailed example.
I'm using 16F1508 and need to store in the FLASH some bytes (1-2) for ID of the board and read them from time to time.

I tried to use your code but get the below errors on the getenv lines:
"Expecting an identifier Bad SFR name"
What is the problem? what do I need to change in the code?

Many thanks.
edi



Joined: 22 Dec 2003
Posts: 82

View user's profile Send private message

PostPosted: Thu Mar 10, 2016 2:11 pm     Reply with quote

I'm using PCWHD 5.015
Ttelmah



Joined: 11 Mar 2010
Posts: 19394

View user's profile Send private message

PostPosted: Thu Mar 10, 2016 3:20 pm     Reply with quote

Your chip has different access to the one being discussed. On yours it is conventional flash using word wide access, rather than the strange hybrid used on the 526.
Have you tested the CCS routines?. The only reason for this thread, was that the conventional CCS routines did not work on this different architecture.
edi



Joined: 22 Dec 2003
Posts: 82

View user's profile Send private message

PostPosted: Thu Mar 10, 2016 3:33 pm     Reply with quote

So what is the simplest way to write 1 byte (int8) to the flash of 16f1508?
What is the way to read this int8?
And what I need to do if I want to re-program this single byte with a new value.
temtronic



Joined: 01 Jul 2010
Posts: 9184
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu Mar 10, 2016 3:43 pm     Reply with quote

Edi
One way is to post your questions in YOUR post and NOT addon to someone elses,especially when it's NOT the same PIC.

You could also look at the examples that CCS supplies.....

Jay
edi



Joined: 22 Dec 2003
Posts: 82

View user's profile Send private message

PostPosted: Thu Mar 10, 2016 3:45 pm     Reply with quote

You are right apology.
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