View previous topic :: View next topic |
Author |
Message |
Matthias Guest
|
PIC24 "Not enough RAM for all variables"? |
Posted: Thu Dec 11, 2008 8:47 am |
|
|
Hi,
I have a PIC24HJ128GP306 with a total of 16KB RAM. The compiler I am using is CCS C PCD for PIC24 devices.
My problem:
I want to use a 16bit integer-array with 7000 entries which should lead to approximately 14KB of RAM usage. The rest of my variables is very small.
If I try to compile my Code the compiler returns "Not enough RAM for all variables". After reducing the size of my array to 3000 entries compilation worked. The compiler returned a total usage of RAM of 37%. So 7000 entries should use about 87% of my RAM. I use 16bit pointers for full RAM access ( #device *=16 ).
The next step I tried was to split my array into 70 arrays with 100 entries each. Same result after compiling --> "Not enough RAM for all variables".
So I tried to bring the 70 arrays step by step into my code. Up to 40 arrays my compiler can compile. This leads to a RAM usage 50% - 51%. Trying to compile my code with 41 arrays I get "Not enough RAM for all variables".
What am I doing wrong?
Thanks for your help. Best regards,
Matthias |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Dec 11, 2008 9:35 am |
|
|
Post the line of code that declares the array with 7000 entries.
Post your compiler version. |
|
|
Ttelmah Guest
|
|
Posted: Thu Dec 11, 2008 9:52 am |
|
|
Couple of quick comments.
Get rid of the device*=16. This is for 14bit parts _only_. Shouldn't cause a problem, but it cerainly is not helping....
Are you using DMA with anything?. If so, there is a big 'lump' in the middle of the address range useable by the DMA cntroller, and your problem seems to be occurring at almost exactly the point where the array would cross this.
Best Wishes |
|
|
Guest
|
|
Posted: Thu Dec 11, 2008 10:04 am |
|
|
My code:
Code: |
//-----------setup------------------------------------------------------------------
#include <24HJ128GP306.h>
#device *=16 //16bit Pointer
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOWRTB //Boot block not write protected
#FUSES NOBSS //No boot segment
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOWRT //Program memory not write protected
#FUSES PR_PLL //Primary Oscillator with PLL
#FUSES NOCKSFSM //Clock Switching is disabled, fail Safe clock monitor is disabled
#FUSES OSCIO //OSC2 is clock output
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES WINDIS //Watch Dog Timer in non-Window mode
#FUSES WPRES128 //Watch Dog Timer PreScalar 1:128
#FUSES WPOSTS16 //Watch Dog Timer PostScalar 1:32768
#FUSES PUT128 //Power On Reset Timer value 128ms
#FUSES NOTEMP //Temparature protection disabled
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES NORSS //No secure segment RAM
#FUSES NOSSS //No secure segment
#FUSES NOWRTSS //Secure segment not write protected
#FUSES NORBS //No Boot RAM defined
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOCOE //Device will reset into operational mode
#FUSES NOJTAG //JTAG disabled
#FUSES ICS0 //ICD communication channel 0
#use delay(clock=16000000) //16MHz Oscillator used
#use rs232(UART2,baud=1920,parity=N,bits=8)
//define register bits for clock setup
#BYTE OSCCON = 0x742
#BYTE CLKDIV = 0x744
#BYTE PLLFBD = 0x746
#BIT CLKDIV6 = CLKDIV.6
#BIT CLKDIV12 = CLKDIV.12
#BIT CLKDIV13 = CLKDIV.13
#BIT PLLFBD1 = PLLFBD.1
#BIT PLLFBD5 = PLLFBD.5
//------------------main------------------------------------------------------------
void main()
{
int16 i = 0;
unsigned int16 tab[7000]; //<-------------- This is where i declare my array
//setup for 80MHz clk
CLKDIV6 = 0;
CLKDIV12 = 0;
CLKDIV13 = 0;
PLLFBD1 = 1;
PLLFBD5 = 0;
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_4);
setup_spi2(SPI_SS_DISABLED);
setup_wdt(WDT_OFF);
setup_timer1(TMR_DISABLED);
enable_interrupts(INTR_CN_PIN|PIN_C14); |
The compiler version is:
IDE: 4.082
PCD: 4.082
Perhaps there is a problem with the 16bit pointer because it seems to me that there is no difference having it in my code or not. |
|
|
Matthias Guest
|
|
Posted: Thu Dec 11, 2008 10:15 am |
|
|
edit:
This is my whole code excepting a while(true){} at the end of main().
As you see, i am using only basics no DMA or something else. It is just the beginning of my project.
I updated my compiler to version 4.083 but the problem is still there. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Thu Dec 11, 2008 11:10 am |
|
|
This isn't a bug, but a restriction of PIC24 data memory layout. You can see why, when you define two arrays and examine the symbol file.
Code: | unsigned int16 tab[3000];
unsigned int16 tab2[4000];
800-1F6F tab
1F80-1FFF Stack
2000-3F3F tab2 |
PIC24 has a reserved stack area in mid of the data area, dividing the near and far data area. You have to design your application reflecting these facts.
Best regards,
Frank |
|
|
Ttelmah Guest
|
|
Posted: Thu Dec 11, 2008 3:53 pm |
|
|
Except he said he had tried splitting into multiple arrays?.
However I wonder if he had not actually split into multiple arrays, but into multiple lines in a single 2D array.....
Best Wishes |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Thu Dec 11, 2008 4:38 pm |
|
|
By chance, I found a memory layout, that fits the PIC24F requirements on first attempt, so I didn't try any more. I don't understand, which splitted variant had failed, cause it isn't shown explicitly.
As an additional remark, I would always define global data, if it's intended as such, otherwise you get CCS typical blurred memory size reports. |
|
|
Matthias Guest
|
|
Posted: Fri Dec 12, 2008 7:48 am |
|
|
Thanks for your help.
Sadly up to now it is not working as i want. This is the other code i tried instead of setting up one array with 7000 entries:
Code: |
unsigned int16 tab1[100];
unsigned int16 tab2[100];
unsigned int16 tab3[100];
unsigned int16 tab4[100];
unsigned int16 tab5[100];
unsigned int16 tab6[100];
unsigned int16 tab7[100];
unsigned int16 tab8[100];
unsigned int16 tab9[100];
unsigned int16 tab10[100];
unsigned int16 tab11[100];
unsigned int16 tab12[100];
unsigned int16 tab13[100];
unsigned int16 tab14[100];
unsigned int16 tab15[100];
unsigned int16 tab16[100];
unsigned int16 tab17[100];
unsigned int16 tab18[100];
unsigned int16 tab19[100];
unsigned int16 tab20[100];
unsigned int16 tab21[100];
unsigned int16 tab22[100];
unsigned int16 tab23[100];
unsigned int16 tab24[100];
unsigned int16 tab25[100];
unsigned int16 tab26[100];
unsigned int16 tab27[100];
unsigned int16 tab28[100];
unsigned int16 tab29[100];
unsigned int16 tab30[100];
unsigned int16 tab31[100];
unsigned int16 tab32[100];
unsigned int16 tab33[100];
unsigned int16 tab34[100];
unsigned int16 tab35[100];
unsigned int16 tab36[100];
unsigned int16 tab37[100];
unsigned int16 tab38[100];
unsigned int16 tab39[100];
unsigned int16 tab40[100];
unsigned int16 tab41[100];
unsigned int16 tab42[100];
unsigned int16 tab43[100];
unsigned int16 tab44[100];
unsigned int16 tab45[100];
unsigned int16 tab46[100];
unsigned int16 tab47[100];
unsigned int16 tab48[100];
unsigned int16 tab49[100];
unsigned int16 tab50[100];
unsigned int16 tab51[100];
unsigned int16 tab52[100];
unsigned int16 tab53[100];
unsigned int16 tab54[100];
unsigned int16 tab55[100];
unsigned int16 tab56[100];
unsigned int16 tab57[100];
unsigned int16 tab58[100];
unsigned int16 tab59[100];
unsigned int16 tab60[100];
unsigned int16 tab61[100];
unsigned int16 tab62[100];
unsigned int16 tab63[100];
unsigned int16 tab64[100];
unsigned int16 tab65[100];
unsigned int16 tab66[100];
unsigned int16 tab67[100];
unsigned int16 tab68[100];
unsigned int16 tab69[100];
unsigned int16 tab70[100];
|
It looks ugly and isn't working, too.
Another option i tried was (thanks to your ideas):
Code: |
unsigned int16 tab[50][35][4];
|
or
Code: |
unsigned int16 tab[25][35][8];
|
But that code is also not compiling.
I am quite sure it has something to do with the size of my datapointer. I tested following code:
Code: |
volatile int16 *tabpointer;
tabpointer = 0x4500;
*tabpointer = 15;
printf("value: %d",*tabpointer);
|
According to the datasheet of the PIC24HJ128GP306 data memory is organized the following way:
address: 0x0000 - 0x07FF --> Special Function Register Space (SFR Space)
address: 0x0800 - 0x3FFF --> X Data RAM
address: 0x4000 - 0x4800 --> DMA RAM
The 16KB of useable RAM are spreading from address 0x0800 to 0x4800. DMA is off so this memory works as "normal" memory. Using the last code above (the one with the pointer) I can write to the address 0x4500 and print that value.
So accessing high memory addresses is possible, but it doesn't explain why my array isn't working. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Fri Dec 12, 2008 9:11 am |
|
|
I previously explained, why it's not possible to define a 14kB continuous array. I don't understand why your 70*100 int16 example doesn't compile, it's working for me with PCD V4.083 and 24HJ128GP306. You may post a complete example code to make the issue understandable.
unsigned int16 tab[50][35][4] in contrast can't work, cause it needs also 14 kB continuous memory space. The stack memory allocation isn't shown in the datasheet data memory map unfortunately, but needed anyway. |
|
|
Matthias Guest
|
|
Posted: Mon Dec 15, 2008 3:14 am |
|
|
I tried to build my project again. Instead of using
i used
Code: | int16 tab1[1000];
int16 tab2[1000];
int16 tab3[1000];
int16 tab4[1000];
int16 tab5[1000];
int16 tab6[1000];
int16 tab7[1000]; |
and suddenly it compiled.
Thanks for all your answers. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Mon Dec 15, 2008 3:53 am |
|
|
Yes, check the location of arrays in *.sym to understand the issue. |
|
|
Matthias Guest
|
|
Posted: Mon Dec 15, 2008 4:51 am |
|
|
But now is have another problem.
my code:
main.h
Code: |
#include <24HJ128GP306.h>
#device *=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOWRTB //Boot block not write protected
#FUSES NOBSS //No boot segment
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOWRT //Program memory not write protected
#FUSES PR_PLL //Primary Oscillator with PLL
#FUSES NOCKSFSM //Clock Switching is disabled, fail Safe clock monitor is disabled
#FUSES OSCIO //OSC2 is clock output
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOWINDIS //Watch Dog Timer in Window mode
#FUSES WPRES128 //Watch Dog Timer PreScalar 1:128
#FUSES WPOSTS16 //Watch Dog Timer PostScalar 1:32768
#FUSES PUT128 //Power On Reset Timer value 128ms
#FUSES NOTEMP //Temparature protection disabled
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES NORSS //No secure segment RAM
#FUSES NOSSS //No secure segment
#FUSES NOWRTSS //Secure segment not write protected
#FUSES NORBS //No Boot RAM defined
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOCOE //Device will reset into operational mode
#FUSES NOJTAG //JTAG disabled
#FUSES ICS0 //ICD communication channel 0
#use delay(clock=16000000)
#use rs232(UART2,baud=1920,parity=N,bits=8)
#BYTE OSCCON = 0x742
#BYTE CLKDIV = 0x744
#BYTE PLLFBD = 0x746
#BIT CLKDIV6 = CLKDIV.6
#BIT CLKDIV12 = CLKDIV.12
#BIT CLKDIV13 = CLKDIV.13
#BIT PLLFBD1 = PLLFBD.1
#BIT PLLFBD5 = PLLFBD.5
|
main.c
Code: | #include "main.h"
#include <stdio.h>
#int_CNI //Interrupt for switch
void CN_PIN_C14_isr(void)
{
static int8 a = 0;
disable_interrupts(INTR_CN_PIN|PIN_C14);
delay_ms(125);
if (a == 0) {
output_high(PIN_D3);
a = 1;
}
else {
output_low(PIN_D3);
a = 0;
}
enable_interrupts(INTR_CN_PIN|PIN_C14);
}
void main()
{
int16 tab1[1000];
int16 tab2[1000];
int16 tab3[1000];
int16 tab4[1000];
int16 tab5[1000];
int16 tab6[1000];
int16 tab7[1000];
CLKDIV6 = 0;
CLKDIV12 = 0;
CLKDIV13 = 0;
PLLFBD1 = 1;
PLLFBD5 = 0;
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_4);
setup_spi2(SPI_SS_DISABLED);
setup_wdt(WDT_OFF);
setup_timer1(TMR_DISABLED);
enable_interrupts(INTR_CN_PIN|PIN_C14); //Interrupt for switch
output_high(PIN_D1);
while(true){}
} |
Now it is compiling but if i release the PIC Pin D1 is not on high state. Deleting the if-check at the isr makes Pin D1 work as intended. With my former code (which was not compiling with my arrays) it worked properly. I didn't change something else at the code...
Any ideas? My RAM usage is at 87%. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Mon Dec 15, 2008 1:28 pm |
|
|
It may be the case, that code execution never reaches the said line.
I see at least two requirements from Microchip not met in your code:
- You don't reset the CNxIF (may not be absolutely necssary, I think)
- You don't reset the mismatch condition by reading the Port C. This causes infinite re-triggering of the interrupt, I fear.
Quote: | The CN pins are configured as follows:
1. Ensure that the CN pin is configured as a digital input by setting the associated bit in the TRISx register.
2. Enable interrupts for the selected CN pins by setting the appropriate bits in the CNENx registers.
3. Turn on the weak pull-up devices (if desired) for the selected CN pins by setting the appropriate bits in the CNPUx registers.
4. Clear the CNxIF interrupt flag.
5. Select the desired interrupt priority for CN interrupts using the CNxIP<2:0> control bits.
6. Enable CN interrupts using the CNxIE control bit.
When a CN interrupt occurs, the user should read the PORT register associated with the CN pin(s). This will clear the mismatch condition and set up the CN logic to detect the next pin change. The current PORT value can be compared to the PORT read value obtained at the last CN interrupt to determine the pin that changed. |
Furthermore, your interrupt service function looks somewhat dubios. Interrupt disable/enable has no effect, cause global interrupts are disabled during execution of the interrupt, if not reenabled explicitely. For the same reason, you should not have longer (or any, to my opinion) delays in ISR. |
|
|
Matthias Guest
|
|
Posted: Wed Dec 17, 2008 8:59 am |
|
|
Thanks for your advice.
With #BUILD(STACK=0x0802:0x881) I was able to move my stack into another position. Now my whole array has enough space within the RAM.
Problem solved. |
|
|
|