Hello,
Could you help to install the ST timer on the AT91Rm9200? I don't know how to setup the AIC registers correct. Maybe there are more than one big mistake.
void initialize_pit() { unsigned int flag, period, irq_id, mask, oldHandler, src_type, priority; volatile int status; void *newHandler; //period Timer0->ST_PIMR = period << 5; AT91F_ST_SetPeriodInterval(Timer0, period); //state //status = Timer0->ST_SR; //enable interrupt flag=1; Timer0->ST_IER = flag; AT91F_ST_EnableIt( Timer0, flag); //enable PMC AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, 1 << AT91C_ID_IRQ0); //config AIC irq_id = 0; oldHandler = pAic->AIC_SVR[irq_id]; mask = 0x1 << irq_id; pAic->AIC_IDCR = mask ; pAic->AIC_SVR[irq_id] = (unsigned int) newHandler ; //* Store the Source Mode Register pAic->AIC_SMR[irq_id] = src_type | priority ; AT91F_AIC_ConfigureIt(pAic, irq_id, priority, src_type, newHandler); //enable AIC AT91F_AIC_EnableIt(pAic, 1); }
I hope somebody could help me with this problem...
best regards johannes
yes I read the datasheet about thumb and arm code...
ok - that means that without __irq the prozessor don't run in the right mode (irq mode which can only be in arm mode). I thought that when I create a irq that the prozessor knows that he has to run this code in arm mode... ok but that was the mistake...
johannes
I thought that when I create a irq that the prozessor knows that he has to run this code in arm mode... <p>
The __irq keyword does some other things besides telling the compiler that the function needs to be compiled in ARM mode. Any of these things might have caused the problem - without knowing what your compilers settings were, there's no way to know. Since your program sat in the while() loop after executing the ISR once, I would assume that it wasn't a problem related to the processor mode - if the processor encounters code that doesn't fit the mode the processor is in, the program will crash in various horrible ways instead of quietly sitting in a while loop.
And yes, the processor "knows" that it needs to switch to ARM mode when it vectors to an ISR. However, the compiler doesn't know which functions are ISRs (or are called by ISRs - remember that bit for later) unless you tell it. If the function you tell the AIC to use as an ISR is compiled in THUMB mode by the compiler, and the processor vectors there and expects code in ARM mode, then exactly one thing will happen: garbage.
I just use the RealView Compiler and I only select using RealView Compiler in the components, enviroment and books menue.. that's all.. so I will read the manual for the realview compiler - maybe I will find a solution for this problem...
I understand - __irq tells the compiler which manner of function that is... to know what to do...
Is it a very good and common way to write only the initialisation and the while(1) loop in the main routine, so that the processor is always in idle mode, only when a interrupt occurs?
That means that the main routine is very small. and everything is working with interrupts.
To be in idle mode, your while loop must specifically put the processor to sleep. If it doesn't, then the processor will always run at full power.
that's sounds good.
UND_Stack_Size EQU 0x00000000 SVC_Stack_Size EQU 0x00000008 ABT_Stack_Size EQU 0x00000000 FIQ_Stack_Size EQU 0x00000000 IRQ_Stack_Size EQU 0x00000080 USR_Stack_Size EQU 0x00000400
in the startup-code, there are mentioned the size of the memory for each interrupt type. How can I calculate the storage I need for the interrupts I programm?
e.g. in the code above; it's a irq interrupt (IRQ_Stack_Size). Why is the USR_Stack_Size so big and when will I use this mode?
Almost. The usual way to write uC/DSP programs is to only use ISRs for doing the things that are absolutely necessary when an interrupt occurs, and have them use flags to signal to the main endless loop that there is further processing to be done.
At least that's the way for programs that do not use an operating system. Things get a bit more complex when an operating system is involved and you need to deal with tasks, software interrupts, preemption and the like.
What you should avoid is putting any longer processing (especially any loops that wait for events) into ISRs. A good rule to follow is KISS - Keep ISRs Short and Simple.
However, sitting in a while(1); loop does not put the processor into an acutal idle (i.e. power-saving) state. How to do this can be found (as usual) in the datasheet (on page 271, to be precise).
How can I calculate the storage I need for the interrupts I programm?
That depends on many factors - but the most important are the number of local variables that your ISRs use (they shouldn't use all that many if you stick with the KISS guideline) and whether you allow nesting of ISRs (i.e. one higher-priority ISR can interrupt lower-priority ISRs).
USR_Stack_Size is the stack size available in USER mode - which is basically all of your program except for ISRs (FIQ/IRQ), operating-system like parts (SVC), and handlers for specific errors (ABT/UND). You will find more about processor modes in the datasheet, on page 36, in the ARM920T Technical Reference Manual, and the ARM9TDMI Technical Reference Manual (which you should all have a copy of, and read, if you want to do any serious development on that chip).
void ST_interrupt(void) __irq { AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_ST->ST_SR; while( !(COM1_1->US_CSR & AT91C_US_TXRDY) ) continue; AT91F_US_PutChar (COM1_1,'n'); //the end of interrupt durch lesen dieses Registers - letzte Aktion AT91C_BASE_AIC->AIC_EOICR = 0x0; }
It's not the best idea to read the AIC_EOICR register in the first line of the ISR, isn't it?
Therefore is it a good solution to install a variable status and read both registers ST_SR und AIC_EOICR with status = AT91C_BASE_ST->ST_SR at the beginning of the ISR and status = AT91C_BASE_AIC->AIC_EOICR at the end of the ISR
The AIC_EOICR is being written to in this line. And since the process of writing to AIC_EOICR ends the interrupt function, this line should be the last line of the ISR.
Using an intermediate variable is not necessary. AIC_EOICR needs to be written to in order to end the interrupt, and ST_SR needs to be read in order to clear the ST interrupt. The one line, placed at the end of the ISR, takes care of both.
and there's no problem if a interrupt occured when the processor is working in the ISR of the same typ of interrupt - but the ST_SR register is not read in the actual ISR?
1. Interrupt1 occured 2. ISR_interrupt1 --> second interrupt occured 3. ST_SR interrupt1 is read
The second interrupt is safed in a register (I don't know it by heart)- although the ST_SR is not read - and waits until the AIC_EOICR register is read.
No, you can safely wait with reading ST_SR until the last line of the ISR.
An ISR can only be interrupted (leading to interrupt nesting) by an interrupt of higher priority. This excludes the possibility of an ISR being interrupted by its own interrupt signal.
However, you should not create an ISR that is takes enough CPU time for the ST_SR interrupt to occur again while the ISR is still running. This would cause you to miss one "tick" of the PITS. Since the PITS runs quite slowly, any ISR that runs long enough should be considered bloated and trimmed down to an acceptable running time immediately.