Reputation: 141
The project I'm working on has to test the data memory of a dsPIC30F chip before the program runs. Due to industry requirements, we cannot utilize any pre-defined libraries that C has to offer. That being said, here is my methodology for testing the RAM:
Step 1 - Write the word 0xAAAA to a specific location in memory (defined by a LoopIndex added to the START_OF_RAM address)
Step 2 - increment LoopIndex
Step 3 - Repeat Steps 1-2 until LoopIndex + START_OF_RAM >= END_OF_RAM
Step 4 - Reset LoopIndex = 0
Step 5 - Read memory at LoopIndex+START_OF_RAM
Step 6 - If memory = 0xAAAA, continue, else throw RAM_FAULT_HANDLER
Step 7 - increment LoopIndex
Step 8 - Repeat Step 5 - 7 until LoopIndex + START_OF_RAM >= END_OF_RAM
Now, the weird part is that I can step through the code, no problem. It will slowly loop through each memory address for as long as my little finger can press F8, but as soon as I try to set up a breakpoint at Step 4, it throws a random, generic interrupt handler for no apparent reason. I've thought that it could be due to the fact that the for()
I use may exceed END_OF_RAM, but I've changed the bounds of the conditions and it still doesn't like to run.
Any insight would be helpful.
void PerformRAMTest()
{
// Locals
uint32_t LoopIndex = 0;
uint16_t *AddressUnderTest;
uint32_t RAMvar = 0;
uint16_t i = 0;
// Loop through RAM and write the first pattern (0xAA) - from the beginning to the first RESERVED block
for(LoopIndex = 0x0000; LoopIndex < C_RAM_END_ADDRESS; LoopIndex+= 2)
{
AddressUnderTest = (uint32_t*)(C_RAM_START_ADDRESS + LoopIndex);
*AddressUnderTest = 0xAAAA;
}// end for
for(LoopIndex = 0x0000; LoopIndex < C_RAM_END_ADDRESS; LoopIndex += 2)
{
AddressUnderTest = (uint32_t*)(C_RAM_START_ADDRESS + LoopIndex);
if(*AddressUnderTest != 0xAAAA)
{
// If what was read does not equal what was written, log the
// RAM fault in NVM and call the RAMFaultHandler()
RAMFaultHandler();
}// end if
}
// Loop through RAM and write then verify the second pattern (0x55)
// - from the beginning to the first RESERVED block
// for(LoopIndex = C_RAM_START_ADDRESS; LoopIndex < C_RAM_END_ADDRESS; LoopIndex++)
// {
// AddressUnderTest = (uint32_t*)(C_RAM_START_ADDRESS + LoopIndex);
// *AddressUnderTest = 0x5555;
// if(*AddressUnderTest != 0x5555)
// {
// // If what was read does not equal what was written, log the
// // RAM fault in NVM and call the RAMFaultHandler()
// RAMFaultHandler();
// }
// }
}// end PerformRAMTest
You can see that the second pass of the test writes 0x55
. This was the original implementation that was given to me, but it never worked (at least as far as debugging/running; the same random interrupt was encountered with this method of writing then immediately reading the same address before moving on)
UPDATE: After a few Clean&Builds, the code will now run through until it hits the stack pointer (WREG15), skip over, then errors out. Here is a new sample of the code in question:
if(AddressUnderTest >= &SPLIMIT && AddressUnderTest <= SPLIMIT)
{
// if true, set the Loop Index to point to the end of the stack
LoopIndex = (uint16_t)SPLIMIT;
}
else if(AddressUnderTest == &SPLIMIT) // checkint to see if AddressUnderTest points directly to the stack [This works while the previous >= &SPLIMIT does not. It will increment into the stack, update, THEN say "oops, I just hit the stack" and error out.]
{
LoopIndex = &SPLIMIT;
}
else
{
*AddressUnderTest = 0xAAAA;
}
Upvotes: 1
Views: 339
Reputation: 1967
Okay, so there are a number of things that we can look at to get a better understanding of where your problem may be. There are some things that I would like to point out - and hopefully we can figure this out together. The first thing that I noticed that seems a little out of place is this comment:
"...total RAM goes to 0x17FFE..."
I looked up the data sheet for the dsPIC30F6012A . You can see in Figure 3-8 (pg. 33), that the SRAM space is 8K and runs from 0x0800 to 0x2800. Also, there is this little tidbit:
"All effective addresses are 16 bits wide and point to bytes within the data space"
So, you can use 16 bit values for your addresses. I am a little confused by your update as well. SPLIM
is a register that you set the value for - and that value limits the size of your stack. I'm not sure what the value for your SPLIMIT
is, but W15
is your actual stack pointer register, and the value that is stored there is the address to the top of your stack:
"There is a Stack Pointer Limit register (SPLIM) associated with the Stack Pointer. SPLIM is uninitialized at Reset. As is the case for the Stack Pointer, SPLIM<0> is forced to ‘0’ because all stack operations must be word aligned. Whenever an Effective Address (EA) is generated using W15 as a source or destination pointer, the address thus generated is compared with the value in SPLIM. If the contents of the Stack Pointer (W15) and the SPLIM register are equal and a push operation is performed, a Stack Error Trap will not occur."
Finally, the stack grows from the lowest available SRAM address value up to SPLIM
. So I would propose setting the SPLIM
value to something reasonable, let's say 512 bytes (although it would be best to test how much room you need for your stack).
Since this particular stack grows upwards, I would start at 0x0800 plus what we added for the stack limit and then test from there (which would be 0x1000). This way you won't have to worry about your stack region.
Given the above, here is how I would go about doing this.
void PerformRAMTest (void)
{
#define SRAM_START_ADDRESS 0x0800
/* Stack size = 512 bytes. Assign STACK_LIMIT
to SPLIM register during configuration. */
#define STACK_SIZE 0x0200
/* -2, see pg 35 of dsPIC30F6012A datasheet. */
#define STACK_LIMIT ((SRAM_START_ADDRESS + STACK_SIZE) - 2)
#define SRAM_BEGIN_TEST_ADDRESS ((volatile uint16_t *)(STACK_LIMIT + 2))
#define SRAM_END_TEST_ADDRESS 0x2800
#define TEST_VALUE 0xAAAA
/* No need for 32 bit address values on this platform */
volatile uint16_t * AddressUnderTest = SRAM_BEGIN_TEST_ADDRESS
/* Write to memory */
while (AddressUnderTest < SRAM_END_TEST_ADDRESS)
{
*AddressUnderTest = TEST_VALUE;
AddressUnderTest++;
}
AddressUnderTest = SRAM_BEGIN_TEST_ADDRESS;
/* Read from memory */
while (AddressUnderTest < SRAM_END_TEST_ADDRESS)
{
if (*AddressUnderTest != TEST_VALUE)
{
RAMFaultHandler();
break;
}
else
{
AddressUnderTest++;
}
}
}
My code was a bit rushed so I am sure there are probably some errors (feel free to edit), but hopefully this will help get you on the right track!
Upvotes: 1
Reputation: 42554
I think you actually want (C_RAM_START_ADDRESS + LoopIndex) < C_RAM_END_ADDRESS
as your loop condition. Currently, you are looping from C_RAM_START_ADDRESS
to C_RAM_START_ADDRESS + C_RAM_END_ADDRESS
which I assume is writing past the end of the RAM.
You also should really factor out the repeated code into a separate function that takes the test pattern as a parameter (DRY).
Upvotes: 1