# PIC microcontroller memory limitations

I am trying to program a PIC10f202 using the XC8 compiler to compare the value of a timer to a variable which will be a function of a look-up table. Here is a sample code :

#include <xc.h>

#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config WDTE = OFF

Init(void){
TRIS=0;
GPIO=0;
TMR0 = 0;
OPTION = 0b00000011;
}

const unsigned char LUT[250] = {
0b00000000, 0b00000001, 0b00000001, 0b00000001, 0b00000001,
0b00000001, 0b00000001, 0b00000001, 0b00000001, 0b00000001,
0b00000001, 0b00000001, 0b00000001, 0b00000001, 0b00000001,
0b00000001, 0b00000001, 0b00000001, 0b00000001, 0b00000001,
0b00000001, 0b00000001, 0b00000001, 0b00000010, 0b00000010,
0b00000010, 0b00000010, 0b00000010, 0b00000010, 0b00000011,
0b00000011, 0b00000011, 0b00000011, 0b00000011, 0b00000100,
0b00000100, 0b00000100, 0b00000101, 0b00000101, 0b00000101,
0b00000110, 0b00000110, 0b00000110, 0b00000111, 0b00000111,
0b00001000, 0b00001000, 0b00001001, 0b00001001, 0b00001010,
0b00001010, 0b00001011, 0b00001100, 0b00001100, 0b00001101,
0b00001101, 0b00001110, 0b00001111, 0b00010000, 0b00010000,
0b00010001, 0b00010010, 0b00010011, 0b00010011, 0b00010100,
0b00010101, 0b00010110, 0b00010111, 0b00011000, 0b00011001,
0b00011010, 0b00011011, 0b00011100, 0b00011101, 0b00011110,
0b00011111, 0b00100000, 0b00100001, 0b00100010, 0b00100100,
0b00100101, 0b00100110, 0b00100111, 0b00101001, 0b00101010,
0b00101011, 0b00101100, 0b00101110, 0b00101111, 0b00110000,
0b00110010, 0b00110011, 0b00110101, 0b00110110, 0b00111000,
0b00111001, 0b00111011, 0b00111100, 0b00111110, 0b00111111,
0b01000001, 0b01000010, 0b01000100, 0b01000110, 0b01000111,
0b01001001, 0b01001011, 0b01001100, 0b01001110, 0b01010000,
0b01010001, 0b01010011, 0b01010101, 0b01010111, 0b01011000,
0b01011010, 0b01011100, 0b01011110, 0b01100000, 0b01100001,
0b01100011, 0b01100101, 0b01100111, 0b01101001, 0b01101010,
0b01101100, 0b01101110, 0b01110000, 0b01110010, 0b01110100,
0b01110110, 0b01111000, 0b01111001, 0b01111011, 0b01111101,
0b01111111, 0b10000001, 0b10000011, 0b10000101, 0b10000111,
0b10001000, 0b10001010, 0b10001100, 0b10001110, 0b10010000,
0b10010010, 0b10010100, 0b10010110, 0b10010111, 0b10011001,
0b10011011, 0b10011101, 0b10011111, 0b10100000, 0b10100010,
0b10100100, 0b10100110, 0b10101000, 0b10101001, 0b10101011,
0b10101101, 0b10101111, 0b10110000, 0b10110010, 0b10110100,
0b10110101, 0b10110111, 0b10111001, 0b10111010, 0b10111100,
0b10111110, 0b10111111, 0b11000001, 0b11000010, 0b11000100,
0b11000101, 0b11000111, 0b11001000, 0b11001010, 0b11001011,
0b11001101, 0b11001110, 0b11010000, 0b11010001, 0b11010010,
0b11010100, 0b11010101, 0b11010110, 0b11010111, 0b11011001,
0b11011010, 0b11011011, 0b11011100, 0b11011110, 0b11011111,
0b11100000, 0b11100001, 0b11100010, 0b11100011, 0b11100100,
0b11100101, 0b11100110, 0b11100111, 0b11101000, 0b11101001,
0b11101010, 0b11101011, 0b11101100, 0b11101101, 0b11101101,
0b11101110, 0b11101111, 0b11110000, 0b11110000, 0b11110001,
0b11110010, 0b11110011, 0b11110011, 0b11110100, 0b11110100,
0b11110101, 0b11110110, 0b11110110, 0b11110111, 0b11110111,
0b11111000, 0b11111000, 0b11111001, 0b11111001, 0b11111010,
0b11111010, 0b11111010, 0b11111011, 0b11111011, 0b11111011,
0b11111100, 0b11111100, 0b11111100, 0b11111101, 0b11111101,
0b11111101, 0b11111101, 0b11111101, 0b11111110, 0b11111110,
0b11111110, 0b11111110, 0b11111110, 0b11111110, 0b11111111};

unsigned char cnt1=0;

void main(){
Init();
for(;;){
cnt1 = LUT[100];
while(TMR0 > 100){
GPIO=0b00000001;
}
GPIO=0b00000000;
}
}


The look-up table is 250 characters because this is the maximum size that was allowed by the compiler before it gave me an error "Can't find x0FF words (x0ff withtotal) for psect "stringtext1" in class "Entry"". The code compiles fine, with MPLAB X stating 55% flash memory usage and 0% RAM usage. If I change the "while" condition to this :

while(TMR0 > cnt1)


The compiler will again give me a similar error : "Can't find x0FA words (x0fa withtotal) for psect "stringtext1" in class "Entry"". I understand the compiler can't find enough memory to write the code, but I don't see how 45% free space is not enough for this task. Also, why am I not able to create an array with 255 elements? The PIC10f202 has 512 words of memory, it should be possible.

Why is the compiler giving those errors?

• It is answerable with facts. Edited the question to make it clear. – jul059 Sep 3 '13 at 18:06
• And my opinion (and fact) is that the PIC you chose is not suitable for what you are trying to do. This is also why I refuse to use PIC's anymore. Doing any sort of data structure larger than about 16 bytes is too painful, and there are many other MCU's that are as inexpensive and much more capable. – user3624 Sep 3 '13 at 18:11

This is a perfect example of how blindly using a compliler on a small resource-limited system without actually understanding the limitations of the machine will get you into trouble.

First, look at how a table of constants in program memory would need to be implemented. Go read the datasheet. No, really, go read it. How would this need too be done? Do you see any way of reading program memory, like a table read mechanism that some other PICs have? The only way to get constants out of program memory is with instructions that contain literals. How do you implement a table with that? No, actually think about it before reading on. Take a look at the list of instructions. The only way to implement a lookup table is with the RETLW instruction. That means you basically do a subroutine call to the table entry, which returns the value for that entry in W. Now look at the subroutine call mechanism. After you've done the reading you should have before writing the first line of code, it should be obvious why you can't possibly have more than 256 table entries with some of those possible table entries needing to be used for code.

Show that you've done some reading of the datasheet and I can go into more details.

• If one wanted to be tricky, I think one could use a 256-byte table if one read out the calibration word at 0x1FF and moved it elsewhere, then put a GOTO at that spot. Then use something like lp: call retAddr/retAddr: btfsc temp,7/goto gotValue/decfsz temp/goto lp to force all stack slots to known retAddr. Setting bit 7 of temp and writing to PCL would then read a value into W and jump to gotValue. Not what I'd expect from a compiler, but possible. – supercat Sep 3 '13 at 19:26

As the numbers in the LUT aren't unique, the numbers are monotonic increasing, and the changes in fact look fairly sparse, is it possible to write a small function to replace the LUT?

e.g., y= x>=1 + x>=23 + .....

I'll leave it up to you to figure out how much memory, if any, can be saved this way.

There are perhaps other algs that use sparse techniques that might help as well, perhaps storing the unique different values and the values of x where the transitions occur.

PIC10f202 has 24 bytes of RAM and 750 bytes of flash, according to this summary from Microchip. If it's possible to keep and run with a table in flash you may be able to fit a small program using the remainder of the program memory. But I don't see anything in your table declaration that looks like a directive to use flash, and the table is now about 12X the size of the available RAM even if there were zero other demands on it (such as stack...).

• const unsigned char typically places it in flash. – Erik Friesen Sep 3 '13 at 18:20
• The LUT is declared as const. In some C compilers for PIC, this puts the constant into Flash. But, I don't know if this applies to XC8, because I've never used it. – Nick Alexeev Sep 3 '13 at 18:21
• No, this is wrong. He did use the CONST keyword, which gives the compiler permission to put the values into program memory (which can't be altered at run time). Saying 750 bytes of flash is misleading since program memory words are not bytes. Still, your logic doesn't hold since this machine has 512 program memory words. – Olin Lathrop Sep 3 '13 at 18:40
• @olin I accept that it MAY be wrong, but the const keyword does not (per the standard) carry linkage implications. See f/ex The C Book, section 8.4.1, 1st paragraph, re: declaring a port 'const'. If you know that this compiler steers consts to ROM - a non standard usage, however useful - then offering a source would be somewhat more helpful than pat declaration of wrongness. – JRobert Sep 3 '13 at 21:18
• @JRobert: As I said, CONST gives the compiler permission to put the data in read-only memory. Of course this is on a small system, and this compiler uses CONST to allow you to specify that data goes into program memory in this case. The standard is only a rough guide for C on architectures C was never designed for, like the harvard-architecture PICs. On such small systems, you need to know what the compiler actually does, not what the standard says it may or should do. The fact that it worked up to 250 bytes is proof the compiler put the data into program memory. – Olin Lathrop Sep 3 '13 at 21:36

I haven't checked all the entries in the table, but it appears that the entries only change by 1 (after several entries in a row that are the same). I believe you could instead reorganize the table as follows, which each tnery is the point at which the valuein the old table increments.

const unsigned char LUT[nn] = {
0, 23, 29, 34, ...


The index into the new table is the value that you would have matched against before (now it is a table lookup), and the value returned from the table is the same as the index that would have been in the old table.

Should be a lot faster, and the table will be much shorter.