Engineer To Engineer Note EE-188
Technical Notes on using Analog Devices' DSP components and development tools
a
Using C To Implement Interrupt-Driven Systems On ADSP-219x DSPs
Contributed by Joe B March 19, 2003
Contact our technical support by phone: (800) ANALOG-D or e-mail: dsp.support@analog.com
Or visit our on-line resources http://www.analog.com/dsp and http://www.analog.com/dsp/EZAnswers
Introduction
(timer_on, timer_off, and timer_set), which were
created to make life for the C developer a little
This Engineer-to-Engineer note will
describe the process for implementing a timer
routine for the ADSP-219x family of DSPs using
the C programming language. Please refer to
chapter 12 of the “ADSP-219x DSP Hardware
Reference” for further details regarding the
timers.
The referenced code in this application
note was verified using VisualDSP++™ 3.0 for
ADSP-21xx DSPs and revision 2.0 of the
ADDS-2191-EZLITE development board.
easier. In an ADSP-219x-based project, these
functions no longer apply because now there are
THREE possible sets of timer registers to
associate these functions to, the registers for
programming the timers are different, and the
register memory space is also changed
significantly from the ADSP-218x family of
DSPs. Additionally, the 32-bit period, width,
and count timer registers are now broken into
low and high words, giving the ADSP-219x
timers 65536 times the duration that the ADSP218x timer had.
ADSP-219x Family Timers
Contrary to the ADSP-218x family of
Digital Signal Processors (DSPs), the ADSP219x family has three timers, each of which can
be configured in any of three modes. On the
assembly level, configuration of the timers and
use of interrupts is fairly straightforward.
However, in C, using interrupts and accessing
the timer registers requires knowledge of some of
the system header files and an understanding of
how the C run-time environment works with
embedded DSP programs. The process
explained herein describes how to implement an
interrupt-driven timer routine in C but the
methods used can be applied to any C-coded
interrupt routines.
The ADSP-218x C libraries defined three
C-callable functions for timer management
Copyright 2003, Analog Devices, Inc. All rights reserved. Analog Devices assumes no responsibility for customer product design or the use or application of
customers’ products or for any infringements of patents or rights of others which may result from Analog Devices assistance. All trademarks and logos are
property of their respective holders. Information furnished by Analog Devices Applications and Development Tools Engineers is believed to be accurate and
reliable, however no responsibility is assumed by Analog Devices regarding the technical accuracy and topicality of the content provided in all Analog Devices’
Engineer-to-Engineer Notes.
Using Features In VisualDSP++
VisualDSP++ 3.0 comes equipped with
several built-in, or intrinsic, functions designed
to make programming a DSP in a C environment
even more user-friendly.
Formerly, memory-mapped registers
were accessed by a referencing-dereferencing
scheme using casted pointers (*(int *)). Access
to non-memory-mapped registers in C was a
tedious task, requiring embedded assembly
source code. Now, the intrinsic functions
sysreg_read and sysreg_write are available for
manipulating these registers. In addition to these
system register functions, the ADSP-219x tools
feature two other intrinsic functions,
io_space_read and io_space_write, which
provides access to all the memory-mapped I/O
space registers as well.
a
These four functions are defined in the
header file sysreg.h. In this header, there is also
an enumerated type, listing the system registers
that can be accessed using sysreg_read and
sysreg_write. One will also find all the bit
manipulation instructions here as well
(sysreg_bit_clr, sysreg_bit_set, sysreg_bit_tgl).
The io_space_read and io_space_write
intrinsic functions require the architecture
definition header file, def2191.h, be included
also. This header details the addresses for all of
the I/O space registers. It should be noted that
the addressing scheme utilized in this header
assumes that the user has already set the IO Page
(IOPG) register appropriately, which is one of
the system registers detailed in the enumerated
type in sysreg.h (sysreg_IOPG). The IO Pages
are also given convenient names in def2191.h.
For example, if the user wanted to
configure their ADSP-2191 EZ-KIT to have
LEDs 8-11 as outputs, this routine would do the
trick:
#include <sysreg.h>
#include <def2191.h>
main( )
{
sysreg_write (sysreg_IOPG, General_Purpose_IO);
io_space_write (DIRS, 0x000F);
}
LEDs 8-11 map to the Programmable Flag Pins
0-3. Therefore, we want to configure PF0-3 to
be outputs. This information is contained in the
DIRS register, where a 1 means that the PFx pin
is an output. The first thing we need to do is to
make sure that we are on the correct IO Page for
accessing the DIRS register. Because IOPG is a
system register, this is accomplished using the
sysreg_write intrinsic with the correct arguments.
The first argument is the register to be written to,
sysreg_IOPG (as defined in the enumeration in
sysreg.h). The second argument is the value to
be written to the IOPG register,
General_Purpose_IO, which is #defined in
def2191.h to be 0x06 (the page offset required to
access the GPIO register set).
Now that the IOPG register is set
appropriately to access the GPIO registers, we
have access to the DIRS register. The second
line of code uses the io_space_write intrinsic
because DIRS is an IO space register. Here, the
arguments are the address to be written to, DIRS,
which is
physical I/O address on IO page 6 of the DIRS
register) and the value to be written to that
address, 0x000F, where bits 0-3 are set to 1 to
enable the corresponding PF pins 0-3 to be
outputs.
the same fashion, as you will see in the attached
code. First, you must set the IOPG register using
the sysreg_write intrinsic to have the offset for
the Timer_Page. Then you’ll have access to the
timer register addresses and must use the
io_space_write intrinsic to configure the
associated registers as appropriate (see lines 2734 of the attached source).
#defined in def2191.h to be 0x001 (the
Accessing the Timer0 registers is done in
Interrupt Handling In C
The interrupt handling in C is unchanged
from the ADSP-218x family tools from a coding
perspective. Users still utilize the header-defined
interrupt(signal, subroutine) module to take care
of everything. First and foremost, this function
associates a specific ISR module to be run for
any given signal that could be received during
run-time. The list of possible signals is detailed
in the signal.h header file. This function also
sets the correct bit in IMASK to enable servicing
for that interrupt. In addition to this interruptregistering scheme, the user will have to globally
enable interrupts by using the intrinsic function
enable_interrupts().
Prior to version 6.1.1 of the ADSP-219x
L
Compiler, global enabling of interrupts
was automatically performed by the
interrupt(signal, subroutine) module.
From version 6.1.1 on, explicit use of the
Using C To Implement Interrupt-Driven Systems On ADSP-219x DSPs (EE-188) Page 2 of 5