![]() |
|
ADSP 21xx
Have you found this site useful? Did we save you time? Did we cure your head-ache? Is your hair growing back now? Please make a donation to help with maintenance. |
Objective Real-Time Software on the ADSP21XXInterrupt Service Routines and Reset InitializationGeneralInterrupt Service Routines (ISR) are nearly synonimous with real-time systems, as an interrupt is the preferred way for a processor to respond to real world stimuli. The ADSP21XX family architecture provides a few helpful features, to achieve very fast ISR context switching, but one needs to be aware of the limitations thereof. In this chapter, we shall create a couple of useful macros, to alleviate some of these limitations. As the initialization of the processor is intimately tied to the reset interrupt, I included a short discussion of efficient processor initialization. Reaction TimeReaction time is an important parameter in most real-time systems and in some systems, such as frequency hopping spread spectrum radios, the amount of interrupt response jitter may also be important. If the processor has only one interrupt enabled, the response time to an interrupt would typically be a maximum of one instruction. A problem arises when there are multiple interrupts enabled. The ADSP 21XX family has some special features that apply to non-nested interrupt mode and if this is the mode being used, then any new interrupt would be delayed by the current interrupt being executed. Therefore, when using non-nested mode, it is important to keep all ISRs as short as possible.
When writing in a high level language, a good ISR should not exceed about 10 lines of code in length. In assembler, let us just say that the routine should be as short as possible. In essence, a data receive ISR should only grab the data and plonk it into a buffer. When the buffer nears the halfway full mark, it should set a flag to signal to a foreground process to go and do something with the data. The ISR itself should do as little work as possible. The circular buffering abilities of the DAG registers were specially created for this purpose - use them!
Jitter arises due to the random nature of the interrupts. It means that in non-nested mode, any interrupt can be delayed by any other interrupt and in nested mode when interrupts are prioritized, a low level interrupt can be delayed by any higher level interrupt activity. The result is that the interrupt response time can vary wildly, evident as jitter in the timing of an output control signal. If you need to minimize interrupt response jitter, you need to make all interrupts as short as possible, allow interrupts to be nested and make the sensitive interrupt the highest priority. Thereby the sensitive interrupt will be able to interrupt the other interrupts and the jitter will be a maximum of one instruction, provided that interrupts are not disabled anywhere in the code! NestingThe ADSP21XX provides a set of shadow registers for most frequently used registers, which can enable very fast ISR context switching, provided that the non-nested interrupt mode is used. When interrupts are nested, shadowing cannot be used, since a higher priority interrupt can overwrite the shadow registers, which can cause the context of a lower priority interrupt to get lost. Therefore all registers would need to be laboriously saved on the stack. Due to the architectural advantage of non-nested mode, the use of nested interrupts is discouraged. (If you really want to use nested mode, the trick is to remember to save the m7 register also...). It is important to note that the Data Address Generator (DAG) registers are NOT shadowed.
This is good motivation to allocate the DAG registers in a certain way during the design phase and not to change it ever, during program execution. Thereby, one can minimize the number of DAG registers that are required to be saved/restored upon ISR entry/exit. Here is a set of macros that can be used to shadow the DAG registers:
These macros can be used the same way as the procedure macros discussed elsewhere in this book, but remember to end the ISR with a rti instruction and not a rts! This is however not the full story. Firstly, the macros should be optimized by deleting all references to index registers that need not be saved. This is simple, since all DAGs that are not used inside the ISRs, need not be saved, but remember to inspect whatever macros you use inside the ISRs, for index register usage, before you start to prune the lists. Secondly, there is some initialization to be done. Interrupt Vector TableBefore we look at the interrupt vectors, bear in mind that with this processor family, interrupts are enabled after a hardware reset. This is a bit weird, since with all other processors I know, interrupts are disabled after reset, this being the safest position. In this case, the only thing saving you from a startup disaster, is the interrupt mask register. Therefore, it is a good idea to make a dis ints your very first instruction. This has the added benefit that you can perform a warm boot, by executing a jump to the reset vector and be assured that interrupts will be disabled immediately. The interrupt vectors differ depending upon the exact processor type used. The following example is based upon the 2185. Please consult a data book on the specific processor you want to use. The one interrupt which is always the same though, is the reset interrupt, which is at address zero. The interrupts are spaced four addresses apart. This allows one to write a few instructions right in the vector table. Here is an example of the 2185 interrupt vector table. Note the ENA SEC_REG instruction used to switch to the shadow registers upon timer interrupt entry. The processor will automatically switch back to the regular registers upon execution of rti at the end of the ISR.
After defining the vector table, we have to initialize the processor registers, create a parameter stack and then we are up and going. The Reset InterruptThe processor can vector to the reset interrupt following a power up reset, BDMA boot reset, or because of a warm boot executed by a fatal error handler. Nowadays, people prefer to call error handlers exception handlers - same thing, but four more characters to type, hence my aversion to the name. Let us continue with file ini.dsp which resides in the work\dbugger directory:
First of all, we explicitly zero all the buffer length registers. This ensures that all DAG registers will behave linearly, unless otherwise initialized somewhere. This is important, since their startup values are undefined. Then, we define the user stack, object which is simply a reserved block of memory defined as an array. An Initialization ObjectThe memory mapped registers are initialized from a table object, using a loop. This ensures that we can easily change the contents of any register in one convenient place. This is an example of a two dimensional table object, handled in a linear fashion. In a high level language, the table would have been defined as a structure, something like this:
In the assembly language loop, since we have to alternately read the address, then the value, then the next address and so on, we still need only increment the DAG pointer by one, for each access, which makes handling this two dimensional object very simple indeed. Note the multiply by 0x0100 in the table definition in file ini_loc.h. Since this table is saved in 24 bit wide PM, all 16 bit data values need to be shifted left by 8 bits.
Finally, we zero the data memory, but take care not to overwrite all the meticulously initialized memory mapped registers again and then copy the initialization data to the initialized variables. Saving initialized variables in PM may seem wasteful, but usually there are very few such variables and it allows us to avoid the added complexity of handling DM with our BDMA loader in addition to the PM. It is a tradeoff, but you would have to have a very large amount of initialization data, before it would be worth while creating a more complex loader. Since loaders are hard to debug, I prefer to keep them as simple as possible. That's it! Your DSP is ready to go! Hmm, remember to enable interrupts after initialization... |
|
Copyright © 1995-2010, Aerospace Software Ltd., GPL. |