|
|
View previous topic :: View next topic |
Author |
Message |
aldina
Joined: 09 Oct 2009 Posts: 26
|
Flash write and read functions - 16F526 |
Posted: Wed Jan 06, 2016 5:21 am |
|
|
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: 19517
|
|
Posted: Wed Jan 06, 2016 6:15 am |
|
|
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
|
|
Posted: Wed Jan 13, 2016 9:07 am |
|
|
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
|
|
Posted: Wed Jan 13, 2016 9:22 am |
|
|
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: 19517
|
|
Posted: Wed Jan 13, 2016 3:51 pm |
|
|
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.
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: 19517
|
|
Posted: Thu Jan 14, 2016 3:39 am |
|
|
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
|
Flash write on 16F1508 |
Posted: Thu Mar 10, 2016 2:06 pm |
|
|
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
|
|
Posted: Thu Mar 10, 2016 2:11 pm |
|
|
I'm using PCWHD 5.015 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19517
|
|
Posted: Thu Mar 10, 2016 3:20 pm |
|
|
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
|
|
Posted: Thu Mar 10, 2016 3:33 pm |
|
|
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: 9229 Location: Greensville,Ontario
|
|
Posted: Thu Mar 10, 2016 3:43 pm |
|
|
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
|
|
Posted: Thu Mar 10, 2016 3:45 pm |
|
|
You are right apology. |
|
|
|
|
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
|