|
|
View previous topic :: View next topic |
Author |
Message |
tesla80
Joined: 23 May 2007 Posts: 81
|
12F1572 write program memory issue |
Posted: Thu Oct 30, 2014 4:06 am |
|
|
Hello everybody,
I have problem by writing __OR__ reading the flash program memory.
I need to store 4 bytes into the device and the device has not internal eeprom, so I decided to store them into the flash memory. Also I've read that it has HEF memory but there is no details about that type of memory.
I've tested it with 5.008 and the 5.030 versions, just downloaded from the ccs' web site as demo and the result is the same.
I've tried to explain the problem in code section.
Simple I write 4 bytes into 0x7FC0 and I read different values.
for example I write 0xFFFFFFFF, I read 0xFF3FFF3F
OR I write 0xFF0000FF, I read 0xFF00FF3F
I've also tried to add disable/enable_interrupts before/after read/write calls.
Please help to manage this issue.
Code: | #include <12F1572.h>
#FUSES INTRC_IO
#FUSES NOMCLR
#FUSES BROWNOUT
#FUSES WDT //Watch Dog Timer
#FUSES PUT //Power Up Timer
#FUSES PROTECT //Code protected from reads
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#define CLK 4000000
#use delay(internal=CLK, restart_wdt)
#use FIXED_IO(A_outputs=PIN_A2,PIN_A1,PIN_A0)
#define Storage 0x07C0 // end of program memory is 0x7FF for 12F1572
#rom int8 Storage = {0xFF, 0xFF, 0xFF, 0xFF}
#byte porta = getenv("SFR:PORTA")
int8 Duty[4] = {0};
void main()
{
setup_oscillator(OSC_4MHZ);
setup_wdt(WDT_1S);
set_tris_a(0b00100000);
porta = 0b00001000;
setup_comparator(NC_NC);
setup_dac(DAC_OFF);
setup_adc(ADC_OFF);
set_adc_channel(NO_ANALOGS);
setup_adc_ports(NO_ANALOGS);
setup_cwg(CWG_DISABLED, 0, 0, 0);
delay_ms(500);
enable_interrupts(GLOBAL);
Duty[0] = 0xFF;
Duty[1] = 0xFF;
Duty[2] = 0xFF;
Duty[3] = 0xFF;
write_program_memory(Storage, Duty, sizeof(Duty));
read_program_memory(Storage, Duty, sizeof(Duty));
// here the Duty[1] and the Duty[3] are 0x3F !!!
// they cannot be more than 3F
// if I skip these cells and write somewhere else, the behaviour is different, but I cannot read what I wrote.
for(;;)
{
restart_wdt();
}
}
|
Thanks in advence
BR |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19587
|
|
Posted: Thu Oct 30, 2014 4:25 am |
|
|
Exactly what you would expect.....
The PIC 12 program memory, is only 14bits wide.
You can only store 14bits, into each location.
So FFFF
Will only get FF3F stored (top two bits missing).
To store 4 _bytes_, you have to use 4 words of storage (8 bytes), and just ignore the extra 6bits in each word, just using the low byte of each location. |
|
|
tesla80
Joined: 23 May 2007 Posts: 81
|
|
Posted: Thu Oct 30, 2014 5:10 am |
|
|
Hello Mr Ttelmah,
I've tried the following code, but still there is inconsistency between reads and writes.
Code: |
int8 a[8];
a[0] = Duty[0];
a[2] = Duty[1];
a[4] = Duty[2];
a[6] = Duty[3];
write_program_memory(Storage, a, sizeof(a));
read_program_memory(Storage, a, sizeof(a));
Duty[0] = a[0];
Duty[1] = a[2];
Duty[2] = a[4];
Duty[3] = a[6];
|
Still similar results as before.
What is wrong here? |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Thu Oct 30, 2014 5:27 am |
|
|
all i can do is reiterate what MR, T explained.
Quote: |
So FFFF
Will only get FF3F stored (top two bits missing). |
what part of the above do you not get ? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19587
|
|
Posted: Thu Oct 30, 2014 5:51 am |
|
|
Start by moving down to an address that exists. You chip only has 4KB of ROM.
0x1000 maximum address. |
|
|
tesla80
Joined: 23 May 2007 Posts: 81
|
|
Posted: Thu Oct 30, 2014 6:58 am |
|
|
Hello,
According to the datasheet the last address is 7FF
I use the following definition for address
#define Storage 0x07C0 // end of program memory is 0x7FF for 12F1572
Also pointed my use of write program memory function.
I guess the #rom line is wrong. There are 4 bytes, but I need 4 words.
But I've tried to write it as a[8], why it didn't work then? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19587
|
|
Posted: Thu Oct 30, 2014 8:23 am |
|
|
This line was what worried me:
"into 0x7FC0"
Now, start with what the int8 declaration does for #rom. This says I want to treat the rom as int8 values. So the first value has 8bits, then the second is an int8, with only 6bits present. Get rid of the int8 declaration here.
Then declare your Data variable as int16.
So you now have 'duty' occupying 8bytes, and 'Storage' also occupying 8bytes both as four 16bit values.
However storage only has 14bits present from each.
Then some comments:
Never, _ever_ enable interrupts without a handler present. Pointless, and if an interrupt flag happens to get set, will crash the system.
Then 'NO_ANALOGS', is _not_ a define for set_adc_channel. The defines must only be used for the functions they are meant for. In this case it won't cause a problem, but it is an approach asking for problems.
Then you specify fixed_io, and also use a TRIS. Use one or the other, not both.
Then, before adding watchdog lines, a) get your code working, and b) learn how to use the watchdog. All you are currently doing, is making the code larger, for no gain. A watchdog, only really works, if the restart, can _only_ be reached if the code is running properly. |
|
|
tesla80
Joined: 23 May 2007 Posts: 81
|
|
Posted: Thu Oct 30, 2014 8:31 am |
|
|
Dear Ttelmah,
Thanks for the valued suggestions.
I'm going to try all of them to make the program bug-free.
If I meet another problem, I'll notice |
|
|
tesla80
Joined: 23 May 2007 Posts: 81
|
|
Posted: Tue Dec 09, 2014 6:34 am |
|
|
I think this chip has not flash address like 0x7FC0..
I need to write image of my struct consists of int16 and int8 values and also need an area for 300 bytes data which will be written by 3 bytes. But I do not know how to know the row start addresses to erase etc..
I need to store the int8[100][3] array in the flash and I'll change the array like [80][0] = 200; [80][1] = 250; [80][2] = 150; and overwrite the values without losing other information.
So my code compiles to 0x6AF address, between 6AF and 7FF are empty. I need 29 bytes for the struct.
I'm confused.. How to calculate the row start addresses to erase or get image of whole 16 words?
I don't understand that chip |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19587
|
|
Posted: Tue Dec 09, 2014 8:05 am |
|
|
You were the one who talked about 7FC0
Quote: |
Simple I write 4 bytes into 0x7FC0
|
As I then said:
Quote: |
This line was what worried me:
"into 0x7FC0"
|
You need to get your head round the difference between words, bytes, and pages.
Your chip has 1024 words of ROM.
Each word is just 14bits long.
So to store 300 bytes, and not lose any of them, you need to use 300 _words_ or start packing the bits in complex formats...
Similarly with your 'structure'. This is going to need to use 29 words, or again start packing things in complex formats (which will involve relatively large amounts of code to access).
Any attempt to change a byte, has to read the entire page, erase this page, modify the byte required, and write the whole thing back.
Then there is the second problem. Reading a single byte from this ROM is quite complex and slow. So to avoid the problems of packing, and the difficulties with reading, the compiler 'cheats'. It uses the same system that it has to use on the chips that have no ROM access, and codes the array as a list of RETLW instructions. It then implements a simple table 'call'' to the required instruction, which then returns the expected byte. Where the table is, can be found with 'label_address'. So if I declare a const array like:
const int8 array[100][3] = {.........};
Then "label_address(array)" will be the address in ROM where the first instruction of the table is stored. The table will use 300+9 words of the instruction memory. With the individual bytes coded as RETLW instructions. To change an entry, you will have to calculate where the page boundary below this entry is stored. Retrieve all the data in the page, erase the page, change the byte required, and write the whole page back. In all honesty, I doubt if you are going to have enough space in your chip to add the code to do this. The structure and the array between them, will use over 1/6th of the program memory before you start...
If I wanted the array to be at (say) 0x500, then I could code as:
#ORG 0x500,0x7FF default
const int8 array[100][3] = {.........};
and the array will be at address 0x500. The first entry will be 9 bytes above this though.
You seem to be trying to pack things into this chip, which it really doesn't have the space to cope with.... |
|
|
tesla80
Joined: 23 May 2007 Posts: 81
|
|
Posted: Tue Dec 09, 2014 8:46 am |
|
|
Hello, thanks for the answer.
I think 12f1572 has 2048 words of ROM.
I can implement this with const array. But how to change only 3 words of that array? If I write directly, the 16 words will be erased.
So where is the address of the Row start?
For example I need to rewrite the 5th index of array, so I need to read first 16 words and edit that and rewrite. What is the address of the 16 words image place?
Where does the 9 bytes u mentioned come from? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19587
|
|
Posted: Tue Dec 09, 2014 10:02 am |
|
|
The 9 words (not bytes) is the header that the compiler puts in front of the array. Contains the code it uses to access it.
If you force an array at a location, and then get the 'label_address', the address will be this much higher than where you store it.
You have to calculate the page address. Simply 'and' the address you want to access with a mask to give the high bits.
You are still not getting the layout.
Storing an array going 1,2,3,4,5,6,7,8,9,0,1,2,..... at 0x500
Code: |
0500: MOVWF 7B //This is the access header
0501: MOVLW 05
0502: ADDWF 7A,W
0503: MOVWF 0A
0504: MOVF 7B,W
0505: ADDLW 09
0506: BTFSC 03.0
0507: INCF 0A,F
0508: MOVWF 02
0509: RETLW 01 //This is the start of the data '1'
050A: RETLW 02
050B: RETLW 03
050C: RETLW 04
050D: RETLW 05
050E: RETLW 06
050F: RETLW 07
0510: RETLW 08
0511: RETLW 09
0512: RETLW 00
0513: RETLW 01
0514: RETLW 02
0515: RETLW 03
0516: RETLW 04
0517: RETLW 05
0518: RETLW 06
0519: RETLW 07 //This is then the 17th element in the array (+16)
|
Now the instruction address is in words. Note how it goes up one for each instruction.
So to access element 16 (say), you have to add '16' (0x10) to 0x509. The instruction for the byte you want is at address 0x519.
The page address (in words) is 0x510 - you 'and' the word address with 0xFF0. The byte you want to access in the byte storage array you read from memory, is then 0x9*2 'up' the array (since the array is byte indexed). The instruction is stored in the upper byte, so you can change the low byte without affecting the code. You need a 32byte temporary array.
Now seriously, you talked about the code already using up to 0x6AF. If so, this just isn't going to fit. You'd only got 336 words left. By the time you have the routines to access the flash, maths to calculate the addresses etc., you are just not going to get it into the ROM. This is a big task. It's miles more complex on these chips than on their bigger brother's.
Your smaller array is easy. Just have the array in RAM, and load it from the EEPROM. Job done. RAM needed, less than the temporary array needed for the flash access. Also access is faster than from ROM. Handling the big array is a different kettle of fish.
Currently I have the feeling of somebody trying to use a nut to crack a sledgehammer. Very unlikely to work....
If you are only ever going to change a very few entries (3 say), then store just these changes in EEPROM, and have the code look at these, before accessing the const array. Again much easier. |
|
|
tesla80
Joined: 23 May 2007 Posts: 81
|
|
Posted: Tue Dec 09, 2014 2:15 pm |
|
|
Hello Ttelmah, thanks, the explanation is very clear.
I'm trying this.
12f1572 does not have built-in EEPROM, AFAIK.
I need to try it with ROM.
The "+9 words" is useful trick, thanks also.
Say that my const is located at 0x500 and its start address is 0x509. OK
What if I need to change the first 3 values (1,2,3)? The page address is 0x500, right? I'll read from 0x500 to 0x510 and I'll edit it in RAM, then I'll write again. But I have 1 word at 0x509 and the others are in another page which is 0x510. So I need to change the next page too, right?
If I locate the const to 0x501, my data will start from 0x510 (page start), it is more useful, correct?
Do I need to watch the data seperated by 2 pages or the write_program_memory function does that instead of me?
Thanks in advence.
BR |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9269 Location: Greensville,Ontario
|
|
Posted: Tue Dec 09, 2014 2:50 pm |
|
|
OK, I have to ask WHY are you using that PIC ? I know it's only a buck and has 8 pins,limited memory, some peripherals. With only 6 I/O pins you're probably going to run out real fast ! Or you'll have to get very 'creative' to cut code to fit everything in...though we don't know your application.
Normal(?) entry PIC would be an 18 pin device, say the 16F648A. A fairly useful device overall....maybe the 16F886 for a 28 pin PIC?
Just curious..
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19587
|
|
Posted: Tue Dec 09, 2014 3:10 pm |
|
|
Moving the array will only affect that very first access. Problem is that for every higher byte you want to access you still have to do the calculations.
Don't rely on +9, this changes with different chip types. This is what label_address is for, working this out for you.
I reckon it'd probably take about 1/3rd of the entire ROM to do a 'universal' set of code that would allow you to change any location in the array. This is what you just don't have.
I'd only use these very small PIC's for a tiny project, where you don't expect to actually do very much. For more, you are just making a lot of work for yourself, and may well not achieve the results you want.
If you really must fit it in a PIC12, then look at something like the 1840, which has twice as much ROM, and 256bytes of EEPROM. If you need the extra peripherals, then look at one of the newer PIC16's.
These are designed for small applications. A 300byte data table which you want to modify is 'ringing bells' as not really suitable for this chip. |
|
|
|
|
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
|