Hi, Good Day.
I am working on ARM7TDMI core processor from Analog Devices family (ADuC703x). I developed a preemptive scheduler on the same in ARM environment. The functionality of the same is fine and its working well. For the purpose of optimization, i migrated into thumb mode using Keil RV compiler option (by changing the code generation option to THUMB mode and the optimization level option to 3 in C/C++ tab of the target settings option).
After changing the settings my code size is reduced by 2 KB. But, the complete functionality of the software got changed.
Can anybody help me out to get out of this problem? Also, I would like to know why this kind of behavior is occurring... Please let me know your valuable suggesions.
Thanking you in anticipation, Ravi Kumar Desaraju.
I'm not sure how intelligent the 'ARM/THUMB interworking' facility is. Hopefully, it detects all function calls and converts them appropriately. I would check the ISR, though. I don't know how interrupts are handled in ADuC703x, but in the MCU I'm dealing with the interrupt handling code enters the ISR in ARM mode.
- mike
Hi Mike,
Yes, you are right. The same thing is happening with ADuC703x. think its the architecture of ARM7TDMI. I read sme where in the ARM core architecture document saying that, the first instruction of your exception handling (FIQ/IRQ/DATA ABORT/PABORT/SWI) should be written with ARM instruction. The ISR exit will automatically switching the ARM mode into THUM mode in my case. The problem is, in context switching code (independent to ISR), I am invoking the THUMB mode using branch instruction which is not happening properly. The other point is, with in ISR and context switching code I am using few 32-bit move instructions for condition checking. Is there any impact for the same, while working on THUMB architecture (THUMB mode doesn't have any 32-bit move instructions)?
if you are writing a safety critical system you are probably much better off with a real RTOS rather than writing you own scheduler. Your expectations of having no interrupt latency are not realistic, I am afraid, as there is usually a trade-off between interrupt latency, throughput, and processor utilization. One way of the other, high system load will cause some delays and there is no way around it. As to your final question - have you seen this link? http://www.keil.com/forum/docs/thread12635.asp
Hmm... I'm afraid the system in question cannot qualify as 'safety critical': it appears some basic problems have not been sorted out yet. I agree with Tamir, why not look around for a 'tried and true' third-party RTOS? After all, you are not trying to develop your own compiler, shouldn't the same apply to an RTOS?
Hi Mike and Tamir,
I do agree with you ppl about using the IRQ handler instead of FIQ. As I explained earlier, my system is a safety critical thats the only point which forced me to work with FIQ. Moreover, my scheduler is working fine with all the timing considerations in ARM mode. I am facing the problem with THUMB mode only.
The reason why we did not prefer to go with already available RTOS is memory consideration... This particular chip is having 30KB of FLASH and 4 KB of SRAM. So.. we are developing our own scheduler with minimum functionality (viz., we don't have resource sharing concept in this project, so no need to develop mutex and seam phore etc... In a broad way we are implementing the RM algorithm in our scheduler).
In ARM mode the size of my code is 3 KB. When I convert and build the code in THUMB mode, I observed that the scheduler code is occupying just 1.8KB. So, I thought its better to go for THUMB mode to reduce the code size further (worst case, it would become 2 KB. which saves 1 KB of FLASH memory....).
Tamir,
I referred the link which you have provided. Its really useful... thanks a lot.
Keil's RTL has all the features you want, plus more that you do not need AND meets your tight space requirements. (That if 2K or less of ROM space for the kernel is a requirement) It also works in ARM or Thumb Mode. You can also buy the source code so that you can modify it if you need too (I believe it is still under $5k US to buy). One of the ways they keep the code size small is that if you do not use a feature, it will not link in that feature (i.e. Semaphores, Mailboxes, Mutexes...). You can just use the Real Time Task Scheduler... that works. If nothing else by buying the source that works, you might be able to figure out what you are doing wrong. It never hurts to understand more.
Make that $5k for each user who need to be able to work with the project.
(30k of Flash + 4k of RAM) == ($5k * 1)
Sorry, I can parse - but not understand - that equation. $5k * 1 for the RTXC source if only a single user needs to compile the project.
It was a Joke.
It meant to fill up 30K of Flash and 4k of RAM would only require 1 developer, especially if that developer did not have to develop the RTOS from scratch.
I agree. 30k ROM implies a quite small application.
Buying - or settling for the pre-compiled version - of RTXC saves a lot of time.
Not just time to write the code, but also to verify that the scheduler really works. Better to spend that time on debugging the final application.
The saved time could possibly be used to write tighter code for the actual application. That would probably affect the total flash and RAM requirements way more than the size difference between the two scheduler implementations.
Hi All,
I found the solution for my problem and able to fix the same. My scheduler is functioning as expected and meeting all our timing requirements. Currently the code size for the scheduler is 2 KB.
Please tell us - what was the problem?
The context switching code was developed in ARM mode and the same is performing out side the FIQ handler. The context switching code will be invoked from the FIQ handler. While entering into the FIQ handler the processor mode was stored in the SPSR register as THUMB mode and the same was restored while leaving the FIQ handler.
At this point of time, the code was in ARM mode and the processor mode was in THUMB which is the major problem caused to enter into PABORT exception. Also, my earlier code (in ARM mode)contains the context switching code within the FIQ handler. I am retrieving and storing the context of a particular task within the FIQ service handler (which requires to change the processor Stack pointer). The processor will remember the current SP value while exiting from the FIQ handler. Therefore, after performing the context switching, FIQ handler is using the SP which was restored last time. This was the reason why I moved my contextswitching code out side the FIQ handler.
I have gone through the link u provided last time. In your code u defined an element in the TCB for each register. In my code, TCB doesn't contain any info abt the registers. It just contain the SP, LR, TAsk ID and the next element/previous elemnt. I am taking the SP value from the TCB and retrieving the context using a POP instruction. I think this was the difference between your code and mine.
In my code, TCB doesn't contain any info abt the registers. It just contain the SP, LR, TAsk ID and the next element/previous elemnt.
...
I am taking the SP value from the TCB and retrieving the context using a POP instruction.
Fine, but the drawback is that you consume some stack space that can be used by the task itself.
Hi Michel,
Yes, you are right. I am consuming some stack space of the user. But, if you have the register contents in the TCB, the same will be allocated in the RAM memory... user stack is also resides in the RAM memory only.... so if the size of the TCB gets reduced and the other hand the size of the user stack will be increased by a significant amount.
Also, execution time will be higher if we perform store and restore operations in case of TCB containing the register elements. If the contents of registers are stored in the user stack itself, the same (Storing and restoring the register contents) can be done with the help of PUSH and POP instructions. Which will speedup the context switching code. This is the only point for which I made my design in that way.....
If the contents of registers are stored in the user stack itself, the same (Storing and restoring the register contents) can be done with the help of PUSH and POP instructions. Which will speedup the context switching code
Both approaches write to RAM, using similar instructions (PUSH/POP vs. LDMIA/STMIA). Why is writing to memory pointed by SP any faster? Besides, using PUSH/POP assumes your stacking is always descending, while STM/LDM do not.
Sorry for my late reply.
Yes, you are correct. I designed my user stack in such a way to keep the register contents in the bottom of the stack.
have you remembered to reset your R13 to the IRQ stack pointer (as acquired at startup - you may have to make the linker place the variable that keeps the address into a section that is not set to zero by _main.) after your context switch has finished? I have fallen into that trap...
Sorry, I forgot that you use the FIQ. If you have a stack defined for that mode - then my previous comment applies. Actually, doing a context switch in FIQ might be slightly faster as you have registers R8-R12 (in addition to R13-R14) banked, which means you don't have to back then up of you want to do something (because the user mode registers R8-R14 won't be affected). on the other hand, you might not be able cannot call functions without a stack...
Hi,
Yes michel, you are right. performing context switching using FIQ is faster. To execute any scheduler related functions, I specified a stack of 20 bytes as the OS stack..... therefore, for the execution of any scheduler related stack, I am using the smae. Therefore, your task stack/FIQ handler stack wouldn't be distrubed.
Coming to youe previous scrap, I didn't understand about the reset issue. Could you please explani me in detail.
doing the context switch in FIQ can be faster. the thing is that if you do it in IRQ, none of the registers except R13 and R14 is banked so you have to push then into the stack when you want to do something, and then use R13 as a variable at the critical stages when you actually backup the context. This is why you need to point R13 to the IRQ stack once you are done: R13 for the IRQ mode is set in your startup file and retains its value throughout the program execution. If you use R13 as a variable, you lose your IRQ stack! or in your case, the FIQ stack. you may not need to do this, as you have more registers to work with.
View all questions in Keil forum