Hello, I developed an emmbedded application for a C167CR-LM. In this application I've some very big data structures stored in internal RAM (IDATA) and some dynamic list managed using malloc and free. For dynamic allocation I define the pool:
unsigned char far equivalence_pool[0x4000]; init_mempool (equivalence_pool, sizeof (equivalence_pool));
In my application there is a IRQ routine on a Timer T6 with a period of 0.5 ms.
In some situations the ILLOPA exception is trapped an the application crashes. It generally happens when many digital input (linked to port P2 pins) are active together.
I tried to increase the user stack with no effect.
Adding 2 calls to printf in the IRQ routine, ILLOPA is not generated.
Have you some suggestions for help me how to investigate this problem?
Testing with Mon166 the trap routines are not available, and using Simulator is too complex cause the hardware and input sequences to generate.
Thanks, Marco
Using the calls to _pop_ function I will insert them in a function called by ILLOPA trap in my traps.c
Be careful, though. Each function call pushes more data onto the stack. You have to account for that when trying to extract the saved PSW, CSP, IP. The three simple pops will not do.
You are correct, it's a problem. I will try to find a solution.
Thanks!
If a ILLOPA represents an 'Illegal Word Operand Access', then I recommend that you test your trap handler by intentionally doing an incorrect access, and verify that the data you get do point to the correct position in the code. You may loose a lot of time if your trap handler is buggy and prints the wrong address, and you then spend time trying to figure out why a completely different location contains a problem...
Ok, thanks.
one more important thing:
#pragma NOFRAME // gain full control over stack push/pop instructions of the interrupt handler static void task_switch() interrupt 0x20
notice the #pragma. placed before a function, it will prevent the compiler from automatically generating code that saves your registers onto the stack thereby not polluting it.
Ok. I've updated my Class_B_trap function in the customised file traps.c with the red code below.
#pragma NOFRAME void Class_B_trap (void) interrupt 0x0A { volatile UINT reg_ip; volatile UINT reg_csp; volatile UINT reg_psw; reg_ip = _pop_(); reg_csp = _pop_(); reg_psw = _pop_(); printf("IP: %X, CSP: %X, PSW: %X\n\n", reg_ip, reg_csp, reg_psw); if (ILLBUS) puts("Accesso a bus esterno non valido"); if (ILLINA) puts("Accesso ad istruzione non valido"); if (ILLOPA) puts("Accesso ad operando non valido"); if (PRTFLT) puts("Istruzione di protezione non valida"); if (PRTFLT) puts("Codice istruzione non definita"); ERRF = 1; while (1); /* end-less loop */ }
So the value of reg_ip combined with the reg_csp value will be the address of the instruction following the one which caused the trap. Is it correct?
Why do you declare your variables volatile? Are you expecting them to be changed by memory corruption or?
The keyword volatile should be used for a global variable that may asynchronously changed by someone else, such as an interrupt handler or a a different thread.
An auto variable should never be changed asynchronously unless you have a memory corruption somewhere, allowing an interrupt or thread to play with stack memory they do not own.
By the way: Think about using an unified intentation strategy. Your code has three different indent levels and/or mixings of space and tab. That doesn't help readability.
Why do you declare your variables volatile?
Oh please! Obviously, the guy is only interested in fixing this particular bug. He's got a fair share of advice on programming style already in this thread. Apparently, volatile comes from here: http://www.keil.com/support/man/docs/c166/c166__pop_.htm
So blame Keil for this. I, too, cannot see why they would declare the variable volatile. Except, perhaps, 'just in case'...
Mike, I think Per's latest comment are very much appropriate. The OP (assuming he is not aware of the impact of volatile, of course) might have gotten the false impression that volatile is somehow required, and start using it regularly (thanks to a weird example by Keil, indeed). That will have a negative impact on the performance and size of his code. And who knows, if somebody ever proved him wrong, he would have given us a bad name :-)
Why do you declare your variables volatile? Are you expecting them to be changed by memory corruption or? I copied it from the C166 User Manual.
By the way: Think about using an unified intentation strategy. Your code has three different indent levels and/or mixings of space and tab. That doesn't help readability. I's a problem of copy and paste ...
Thanks.
I'm not blaming anyone. I just know that volatile is a often misunderstood keyword. A volatile too much hurts optimization a lot. A volatile too little can result in totally unexplainable errors.
In a single-tasking PC program, it is possible to ignore this keyword, but in an embedded environment with interrupts and possibly RTOS tasks, it is important to realize the the meaning of it, and that includes both when to use it, and when not to use it.
Well, using the lower 8 bits of CSP and the 16 bits of IP I've an address. Looking at the Disassembly window it seems that it's not the address of the offending instruction, and it's not the instruction following the one which caused the trap, because looking at the conditions of my test, the routine containing these instructions cannot be called. Have you any suggestions? Thanks!
I'll repeat myself:
"f a ILLOPA represents an 'Illegal Word Operand Access', then I recommend that you test your trap handler by intentionally doing an incorrect access, and verify that the data you get do point to the correct position in the code. You may loose a lot of time if your trap handler is buggy and prints the wrong address, and you then spend time trying to figure out why a completely different location contains a problem..."
If you know exactly where you came from, it is easier to verify what data you have on the stack and what your trap handler produces.
I recommend that you test your trap handler by intentionally doing an incorrect access, and verify that the data you get do point to the correct position in the code.
I'm not able to do this operation. Have you a possible example? Thanks!
What happens if you do the following: - Have an array of two int. - Let a byte pointer get the address of the first int. - Increment the byte pointer one step. - Typecast the byte pointer to an int pointer and try to read.
This should perform a word access from an odd address.
Thanks! It's easiest than I had imagined