Professional Documents
Culture Documents
George Terzakis
ii
iii
iv
vi
Contents
Preface.............................................................................................................................................................. xvi
Acknowledgements ...................................................................................................................................... xix
1. INTRODUCTION ..................................................................................................................... 1
1.1 The TMS320LF/LC240xA series of DSP Controllers by Texas Instruments .....................................................1
1.1.1
The TMS320LF2407A DSP Controller made by TI ...............................................................................1
1.1.2
Peripherals of the LF2407A Controller ..................................................................................................3
1.2
1.3
viii
ix
6.2. 13 Verifying expected time lapse between consecutive conversion sessions ........................................... 137
6.3 Using the ADC in Dual Sequencer Mode ......................................................................................................138
6.3.1 A new project for ADC operation in Dual Sequencer Mode.................................................................... 139
6.3.2 Configuring the ADC for Dual Sequencer Operation Mode .................................................................... 139
6.3.3 The ADC Interrupt Service Routine in Dual Sequencer Mode .................................................................140
6.3.4 The main() function ............................................................................................................................... 142
6.3.5 Executing the program .......................................................................................................................... 143
6.4 Summary/Conclusions .................................................................................................................................144
xi
xii
Bibliography ...................................................................................................................................................374
Sources ............................................................................................................................................................375
Appendix A: Header and C files for EVA, EVB .......................................................................................378
Structure Definitions (DSP24_Ev.h) ............................................................................................................. 378
Register Declarations (DSP24_Ev.c) ............................................................................................................. 388
xiii
xiv
xv
Preface
My first experience with the C2x generation of DSP controllers by Texas Instruments
was with the TMS320F2812 in the context of a graduate course related to digital signal
processing. The first impression, for someone who has an average amount of experience in
embedded programming, is that this product can be looked upon in two ways: Either as a hi-fi
microcontroller or as a very specialized CPU in terms of certain mathematical operations
commonly employed in DSP algorithms. My problem was to select a proper course of action
towards these two directions, in order to broaden my overall knowledge on the DSP
controller.
I realized that the best way to make a smooth start into understanding the F2812
was to initially face it as a typical microcontroller and program it in a high-level language (i.e.,
C) to perform simple or relatively elaborate tasks involving I/O operations. I downloaded the
tidcs set of C/C++ header file libraries by TI and used several available examples to break my
way through the preliminary steps. During that period, I came across the F2812s 16-bit fixedpoint counterpart by Texas Instruments, the TMS320LF2407A. The two controllers have an
almost identical set of peripherals and, to program them in C, was essentially a similar task.
Since the LF2407A did not have a corresponding set of C/C++ libraries, I used the tidcs header
files as templates to create a set of structures for its memory-mapped registers. During this
process, several architectural characteristics of the C24x CPU would gradually emerge and the
information found in application notes and technical manuals that initially seemed to be
scattered pieces of a puzzle would eventually start to fall into place.
This book is a compilation of methods and examples placed in an order that could take
a student without any prior knowledge on the TMS320 series by Texas Instruments through
a fast introduction to C programming with the controller, while several other concepts and
issues will be gradually addressed in the context of examples. Additionally, the text points to
certain technical manuals and application notes that provide the full extent of the information
required to comprehend the topic under examination. Assembly language is generally avoided
until Chapter 12. It is my opinion that one should be already acquainted with the essentials of
the controller before moving on to optimizing code by making use of the specialized
instruction set of the C24x CPU core.
The examples related to DSP (fast Fourier transform, digital filters) in Chapters 10 and
11 are all implemented in C. These examples merely intend to demonstrate the abilities of the
xvi
peripherals introduced in the previous chapters, as well as the possibility of optimizing their
performance by considering the advantages offered by the instruction set of the C24x core.
To conclude, this book is intended for students who wish to have a fast introduction
with the TMS320 series by Texas Instruments, using the TMS320LF2407A DSP controller. It
is a compilation of solutions to problems that usually appear during the first stages of ones
acquaintance with the DSP controller and its peripherals. Moreover, the code examples
presented throughout the text are intended to illustrate the basics and provide the incentive
for further investigation on the issue at hand, rather than to give a clean-cut solution to a
problem with specified parameters. In overall, this book is more-less the introductory course I
would have chosen for myself in order to understand the essentials of a DSP embedded
platform and I am hoping that it will serve as an equally useful guide to students and aspiring
engineers.
George Terzakis
terzakig@gmail.com
Bristol, United Kingdom
xvii
xviii
Acknowledgements
xix
xx
INTRODUCTION
Introduction
INTRODUCTION
INTRODUCTION
INTRODUCTION
controllers, or a PC. The designated lines for reception (RX) and transmission (TX) are not
level-shifted on the DSP board (i.e., they operate at 0-3.3V).
The Watchdog Timer. The watchdog is essentially a timer, acting as a safety precaution
against possible program locks in endless loops. When enabled, the watchdog increases an
internal 8-bit counter using a clocking signal running at a sub-multiple frequency of the CPU
clock signal. The program should be able to reset the counter before an overflow occurs; if, for
any reason (which may possibly be an execution hung), the program fails to reset the
watchdog in time, the counter will overflow and a system reset will be asserted.
The General bi-directional I/O pins. The LF2407A has a set of general I/O pins
organized in ports A, B, C, D, E and F. Most of the I/O pins on the LF2407A are multiplexed
with other devices (e.g., general I/O pin A6 is multiplexed with the PWM1 pin) and must be
configured prior to use, either for their primary (non - general I/O) or secondary (general I/O)
function. Moreover, general I/O pins can be configured either as input or output.
INTRODUCTION
only on the LF2407A, but on other DSPs, while building a useful set of code templates for
his/her programs.
The demonstration examples (fast Fourier transform, FIR and IIR filters) are all purely
implemented in C; they are intended to demonstrate merely a fraction of the issues that an
engineer/student may be faced with, when trying to implement the relative algorithms for
commercial use. Different approaches in the implementation are recommended and
discussed; including the use of C-callable assembly code to improve performance by taking
advantage of the LF2407A specialized instruction set in terms of typical DSP computations.
Regardless of whether the programs presented in this book are ideally suitable for solutions to
many problems in the field, they merely serve as an introduction to the relative topics. The
main goal is to suggest and discuss solutions in a comprehensive and coherent manner for the
reader, without expecting prior extensive knowledge, either on embedded programming or
signal processing in general.
INTRODUCTION
In the first step you will be asked to name the project, choose a suitable folder and a target.
Type a name (i.e. hello) and create a folder in windows explorer to store your project.
Preferably, create your folder without any spaces or special characters and make sure the
path does not include extended names (e.g., Documents and Settings); the linker version
may have an issue with these kinds of names and it may produce errors without any apparent
reason. Choose TMS320C24XX as target.
MCRA
PADATDIR
WDCR
SCSR2
(volatile
(volatile
(volatile
(volatile
unsigned
unsigned
unsigned
unsigned
int
int
int
int
*)0x7090
*)0x7098
*)0x7029
*)0x7019
void main() {
unsigned int i, temp, temp1;
*SCSR2 = (*SCSR2 | 0x000B) & 0x000F;
*WDCR
Seems incredible, but this little piece of code might be a nice first complete program to
download to the 2407A. Okay, I admit, you will not see the word hello anywhere, but in a
sense, the DSP will be signaling to you for the first time (I guess that is a hello for a DSP). Save
your file in the hello project folder and let us see what to do with it.
2.1.2 The missing details
Unfortunately, we are still not ready to give it a go. There are a couple of significant
details yet to be settled.
The linker command file. Unlike what you may be used to, the memory locations in
which the code and data of the program will eventually reside, must always be manually
8
defined inside a linker command file (extension, .cmd). The structure of a command file is
simple, but choosing the locations to store your code and variable sections can be very
tricky. Since no one has the spare time to go through technical manuals every time he/she
needs to develop a program, a good policy would be to save your first .cmd file and then
either reuse it verbatim, or make slight changes to fit your new projects requirements. Heres
a command file that will be used throughout many examples in this text.
MEMORY
{
PAGE 0:
/* Program Memory */
VECS:
org=00000h,
FLASH:
org=00044h,
PSARAM:
org=08000h,
EXTPROG:
org=08800h,
len=00040h
len=07FBCh
len=00800h
len=07600h
/*
/*
/*
/*
internal
internal
internal
external
FLASH
FLASH
SARAM
SARAM
*/
*/
*/
*/
PAGE 1:
/* Data Memory */
B2:
org=00060h,
B0:
org=00200h,
B1:
org=00300h,
DSARAM:
org=00800h,
EXTDATA:
org=08000h,
len=00020h
len=00100h
len=00100h
len=00800h
len=08000h
/*
/*
/*
/*
/*
internal
internal
internal
internal
external
DARAM
DARAM
DARAM
SARAM
SARAM
*/
*/
*/
*/
*/
}
SECTIONS
{
/* Sections generated by the C compiler
.text: >
EXTPROG
PAGE 0
.cinit: >
EXTPROG
PAGE 0
.const: >
B1
PAGE 1
.switch: >
EXTPROG
PAGE 0
.bss: >
EXTDATA
PAGE 1
.stack: >
DSARAM
PAGE 1
.sysmem: >
B1
PAGE 1
*/
/*
/*
/*
/*
/*
/*
/*
initialized */
initialized */
initialized */
initialized */
uninitialized */
uninitialized */
uninitialized */
>
VECS
PAGE 0
*/ /* initialized */
In File New Source File create a file named 2407_cmd.cmd and save it in folder hello.
Notice highlighted section vectors mapped to VECS in PAGE 0; the allocation is commentedout. As stated in the comments, this section is NOT created by the C compiler, still it should be
included in most applications, since it contains the core interrupt vector table of the 2407A;
for now, keep it cased in comments. We will be going through the details of this command file
shortly after we build and execute our project.
Library file rts2xx.lib. Although upon the creation of the project we specifically
stated a target (i.e., TMS320CXX), this is not enough for the compiler to produce targetspecific object files. File rts2xx.lib must always be added to the project when C language is
9
used, otherwise the compiler will not know how to generate assembly instructions, allocate
variables, emulate floating point arithmetic, perform data and program addressing, etc. You
should be able to locate rts2xx.lib in ./C2400/cgtools/lib starting from the Code Composer
Studio root directory (usually, C:\CCStudiocx.x).
2.1.3 Putting it all together
So, now we have a C file, a linker command file and a library file to add to the project.
Just go Project Add Files to Project, or right-click on the projects name in the project browser
window floating on the left side of the IDE and choose Add Files to Project.
Make sure to select the appropriate extension every time. The IDE will distribute .cmd and .c
(as well as .asm, if any) under the Source tree node, whereas the .lib can be found under
Libraries. If all went okay, your project browser window should look like the one in Figure 2-4.
Do not forget to save your project using menu Project Save.
Figure 2-4. Project hello browser window; .cmd, .c, .lib files added.
10
11
Now, let us try something new. Go Debug Reset CPU and check the disassembly
window again (Figure 3-2).
Something very strange happened! Although your program is still in memory, the DSP
chose to ignore the memory location of the cinit section; instead, the instruction pointer now
28
moved to address 0x0000 in program memory containing an ADD instruction. Try Debug Go
Main now. Oops! No main()? You can obviously tell that the program does not suspend
execution at the beginning of the main() function as you may have expected. In fact, the DSP is
still running! You can verify this by checking the Debug menu. All execution menu items are
inactive, except for Halt. Hit Halt and let us go through what just happened.
3.1.1 The Reset interrupt Vector
If no boot ROM is present, then, following a reset, the DSP loads address 0x0000
(program memory) to the instruction pointer. If you take a good look at Figure 2-15, this is the
first memory location corresponding to the core interrupt vectors. Address 0x0000 is the
location for the reset vector and it should contain a branching instruction (jump) to
whatever you want the DSP to do immediately after reset. I think you guessed right. It
should jump to the cinit section. Remember the line cased in comments in the SECTIONS
clause in 2407_cmd.cmd? By using the comments, we have excluded the vectors section
from being loaded to program memory; hence, when the DSP resets, it looks for a branching
instruction at 0x0000, but instead, it finds a random data residue interpreted as an instruction
(an ADD in this case); consequently, execution hangs since the DSP is executing random
instructions in memory.
Go File New Source File and create a new file. Save it as cvectors1.asm. Do not
worry, this is as much as you will be dealing with assembly. Unfortunately, this is the only way
to add a section to your C program; so type the following:
.ref _c_int0
.sect
rset:
B
"vectors"
_c_int0
;00h reset
Make sure you apply indentation as you see it above; the assembler may have problems if you
do not. The . prior to the ref and sect keywords, implies that these strings are assembler
directives, not instructions. The .ref directive is used to imply that symbol _c_int0 is
externally defined. Actually, this is the symbol created by the C compiler for the cinit
section. Keep always in mind that when referencing symbols created in C from an assembly
file, the _ character should be added prior to the symbol. The .sect directive creates a new
section. Notice now the first line in section vectors. It contains an assembly instruction for
an unconditional branch to the _c_int0 code (B _c_int0). That is exactly what we need! So
now, after a reset, the DSP will be executing a jump to the programs cinit section and things
can start all over again without any unwanted hangs.
29
Add cvectors1.asm file to the project. Then, open the command file and remove the
comments from the line loading the vectors section in memory as shown below:
vectors:
>
VECS
PAGE 0
/* initialized */
Your project browser window should look like the one shown in Figure 3-3. Save the updated
command file and build your project.
Load the program into the DSP and do a Go Main. Now, do a Reset CPU and observe what
happens. The debugger takes you to file cvectors1.asm and suspends execution right before
the jump to _c_int0 as shown in Figure 3-4.
30
If you now do a Go Main, you can rest assured that execution will be suspended right at the
beginning of the main() function. Do a few resets just to raise the spirit seeing how nicely it
works!
.sect
B
B
B
B
B
B
B
B
B
B
B
B
B
_c_int0
_INT1_GISR
_INT2_GISR
_INT3_GISR
_INT4_GISR
_INT5_GISR
_INT6_GISR
"vectors"
_c_int0
_INT1_GISR
_INT2_GISR
_INT3_GISR
_INT4_GISR
_INT5_GISR
_INT6_GISR
int7
int8
int9
int10
int11
int12
;00h
;02h
;04h
;06h
;08h
;0Ah
;0Ch
;0Eh
;10h
;12h
;14h
;16h
;18h
reset
INT1
INT2
INT3
INT4
INT5
INT6
reserved
INT8 (software)
INT9 (software)
INT10 (software)
INT11 (software)
INT12 (software)
31
B
B
B
B
B
B
B
B
B
B
B
B
B
B
B
B
B
B
B
int13
int14
int15
int16
int17
int18
int19
int20
int21
int22
int23
int24
int25
int26
int27
int28
int29
int30
int31
;1Ah
;1Ch
;1Eh
;20h
;22h
;24h
;26h
;28h
;2Ah
;2Ch
;2Eh
;30h
;32h
;34h
;36h
;38h
;3Ah
;3Ch
;3Eh
INT13 (software)
INT14 (software)
INT15 (software)
INT16 (software)
TRAP
NMI
reserved
INT20 (software)
INT21 (software)
INT22 (software)
INT23 (software)
INT24 (software)
INT25 (software)
INT26 (software)
INT27 (software)
INT28 (software)
INT29 (software)
INT30 (software)
INT31 (software)
Save the file now as cvectors.asm. Notice the first seven .ref directives. They inform the
compiler that symbols _c_int0, _INT1_GISR, _INT2_GISR, _INT3_GISR, _INT4_GISR, _INT5_GISR
and _INT6_GISR will be externally defined (meaning somewhere in your C code). Keep in mind
that if you refer to a symbol defined in C inside an assembly file, you should always add a
_ prefix to the reference (i.e., _c_int0 refers to c_int0, _INT1_GISR refers to INT1_GISR,
etc.). As mentioned earlier, the _c_int0 corresponds to a function named c_int0
automatically generated by the C compiler. The rest are yet to be implemented, but should be
defined and declared somewhere in the project code, otherwise the linker will not be able to
resolve them and eventually fill your output window with dreadful errors!
3.2.2. Adding Declarations for Core Interrupt Service Routines 1-6 in C
Create a new C header file named DSP24_DefaultISR.h and type the following:
#ifndef DSP24_DEFAULT_ISR_H
#define DSP24_DEFAULT_ISR_H
interrupt void INT1_GISR(void);
interrupt void INT2_GISR(void);
interrupt void INT3_GISR(void);
interrupt void INT4_GISR(void);
interrupt void INT5_GISR(void);
interrupt void INT6_GISR(void);
#endif
32
Save the changes you made. The compiler can resolve the symbols directly from the .c files;
therefore, the header file is not really required. However, it is best that you keep it, since it
could be used for constant definition and additional include directives. The interrupt keyword
informs the compiler that the function that follows is an Interrupt service function; thus, the
compiler adds context saving and retrieving specific code (storing/retrieving flags, register
values, etc.) at the beginning and the end of the function respectively. The C compiler makes
sure that you will not have to worry much about context saving, if you only remember to
use the interrupt keyword. Notice the names of the routines (INT1_GISR,,INT6_GISR). These
are the symbols referred to in the cvectors.asm file that we modified a while ago; now the
_ prefix is omitted since we are typing C code. Dont worry about the implementation of
these functions yet. As long as the linker can locate these symbols referred to in
cvectors.asm, your project building will be successful. Now, create a new file named
DSP24_DefaultISR.c for the declaration of the interrupt service routines referred in
cvectors.asm. Type the following:
#include "DSP24_DefaultISR.h"
interrupt void INT1_GISR(void) {
}
interrupt void INT2_GISR(void) {
}
interrupt void INT3_GISR(void) {
}
interrupt void INT4_GISR(void) {
}
interrupt void INT5_GISR(void) {
}
interrupt void INT6_GISR(void) {
}
Although it may seem unimportant for the time being, try to adopt the naming
conventions used in this text for your files. For example, DefaultISR is a name used
commonly in projects for other DSP models (such as TIs TMS320C2812/F2812). Most
developing principles and methods mentioned in this text may well apply with slight
modifications to other DSP products by Texas Instruments. Moreover, it is important that
you recognize the role of a file in a project simply by its name. You may find that most
programs are portable from one DSP model to another with much less effort than you
imagined.
33
46
TMS320LF/LC2407A DSP Controllers Reference Guide System and Peripherals (Texas Instruments)
47
timing source to synchronize events. Time awareness and periodic execution are
important factors to consider when controlling a motor, polling sensors or filtering signals.
4.2.1 Project Timer1
Create a new project folder named Timer1. Copy files cvectors.asm,
2407_cmd.cmd, DSP24_Sys.c, DSP24_DefaultISR.h and DSP24_DefaultISR.c to the new
folder and create a new project named Timer1. Now, create a new file named T1main.c
and type-in the following code:
extern void initSystem(void);
extern void initTimer1(void);
void main() {
initSystem();
initTimer1();
asm(" CLRC INTM"); // Enable Global Interrupts
while (1) {
}
}
This is an even smaller main() function than the one in program hello! Notice
externally implemented function initTimer1() called right after system initialization. This
function will start the timer and enable the desired interrupts.
Notice the inline assembly instruction asm( CLRC INTM). If you are using interrupts
in your program, you must use this instruction to enable them. By default, following a reset,
interrupts are disabled. The DSP has a global interrupt switch (INTM) that disables/enables
interrupts. You will realize that it comes very handy in many occasions in our programs. You
may disable interrupts using inline assembly instruction asm( SETC INTM).
48
TMS320LF/LC240xA DSP Controllers Reference Guide System and Peripherals (Texas Instruments)
64
The general purpose timers. We have already made our first acquaintance with the
general purpose timers. So far, we have only used them to produce periodic events (period
match, compare and underflow interrupts). In the context of the event manager, timers may
be additionally configured to produce pulse width modulated signals on pins TxCMP/TxPWM
(x=1,2,3,4). Throughout the present chapter, we will be using timer 1 to produce a PWM
signal. Moreover, you should think of timers as the life force of the event managers,
providing clocking to other units, such as the compare units (Figure 5-1).
The compare units. The three compare units (per event manager) can be specifically
used for PWM signal production on pins PWM1, PWM2, PWM3, PWM4, PWM5 and PWM6 in
the case of EVA and PWM7, PWM8, PWM9, PWM10, PWM11, PWM12 for EVB. They are
clocked by timer 1 (EVA) and timer 3 (EVB) and they can be configured to produce pulses in
pairs of pins (e.g., PWM1 and PWM2). The compare units can use a special dead-band unit as
an accessory to produce artificial dead-bands for active high-active low PWM pin pairs.
The capture units. Capture units may come-in very handy when trying to capture
pulses of external origin. Such an example could be the bounce-back pulse from a sonar
transducer, or a series of pulses from a rotary motor encoder. In fact, this is probably what the
designers of the event managers had in mind when they were designing capture units.
Actually, to accommodate our needs in terms of capturing motor encoder pulses, we may
configure the quadrature encoder pulse circuit for quadrature motor encoder pulse capturing
to determine both rotation speed and direction.
Concluding, event managers comprise several interconnected units to accommodate
the numerous specific needs that may arise when controlling a motor and/or when receiving
feedback in the form of pulses. EVA and EVB are highly configurable to the last detail;
therefore, they involve a large set of configuration and control registers. Along with the CAN
controller, they are the most complicated peripherals on the 2407A. The large number of
registers to deal with may give you a headache, but it is something that can be dealt with,
mainly by properly organizing your header files and functions.
The event managers offer the luxury of configuring certain actions upon timer-related
events. Actually, we may use a GP Timer to produce PWM on the T1PWM/T1CMP pin, or even
start the analog to digital converter (ADC). Configuration of these actions (and several others)
can be done through the appropriate general purpose timer control register (i.e., GPTCONA).
Obviously, there are two general purpose timer control registers, GPTCONA (EVA) and
GPTCONB (EVB).
Now, open DSP24_Ev.h and add the declaration for GPTCONA as follows:
#include "DSP24_Ev.h"
volatile unsigned int *T1CNT=(void*)0x7401;
/* GP timer 1 counter reg */
volatile unsigned int *T1CMPR=(void*)0x7402;
/* GP timer 1 compare reg */
volatile unsigned int *T1PR=(void*)0x7403;
/* GP timer 1 period reg */
// GPTCONA
volatile union GPTCONA_REG *GPTCONAbits=(void*)0x7400;
GPTCONA declaration
//T1CON
volatile union T1CON_REG *T1CONbits=(void*)0x7404;
// EVAIMRA
volatile union EVAIMRA_REG *EVAIMRAbits=(void*)0x742C;
// EVAIFRA
volatile union EVAIFRA_REG *EVAIFRAbits=(void*)0x742F;
66
Added code
T1CONbits->bit.rsvd1=0;
// reserved
T1CONbits->bit.TCMPREN=1; // Enable Timer Compare
T1CONbits->bit.TCLD=00;
// reload compare reg on underflow
T1CONbits->bit.TMODE=01; // Continuous Up/Down mode
T1CONbits->bit.TPS=000; // Input Clock PreScale /x1
T1CONbits->bit.rsvd2=0;
T1CONbits->bit.rsvd3=0;
T1CONbits->bit.TCLKS=00; // Internal Clock source select
T1CONbits->bit.SOFT=0;
T1CONbits->bit.FREE=0; // immediate stop on emulation suspend
EVAIFRAbits->bit.T1PINT=1; //
EVAIFRAbits->bit.T1CINT=1; //
EVAIFRAbits->bit.T1UFINT=1;//
EVAIFRAbits->bit.T1OFINT=1;//
clear
clear
clear
clear
EVAIMRAbits->bit.T1PINT=1; //
EVAIMRAbits->bit.T1CINT=1; //
EVAIMRAbits->bit.T1UFINT=1;//
EVAIMRAbits->bit.T1OFINT=1;//
enable
enable
enable
enable
Timer1
Timer1
Timer1
Timer1
Timer1
Timer1
Timer1
Timer1
The new code involves the configuration of GPTCONA. If you take a look in
TMS320LF/LC240xA DSP Controllers Reference Guide System and Peripherals, you will find
that there are two registers configuring GP Timers (GPTCONA and GPTCONB) having identical
67
bit definitions for all four timers in EVA and EVB. Although in project Timer1, we did not
configure the general purpose timer register, it should be a solid policy to configure it, even if
you do not intend to use pulse width modulation on the T1PWM/T1CMP pin.
5.1.3 General Purpose Timer Control Register A
The general purpose timer control register A (GPTCONA) bitwise outline is shown in
Figure 5-2.
The T1PIN0-1 bits. Bits 0 and 1 in GPTCONA configure the polarity of the timer 1
compare pin. We choose active high (10). Check the manual for more options.
The T2PIN0-1 bits. Bits 2 and 3 in GPTCONA configure the polarity of the timer 2
compare pin. It is configured as forced low (00), since timer 2 does not concern this
example.
The TCMPOE bit. Bit 6 in GPTCONA enables timer 1 and timer 2 compare outputs.
Obviously, you should set this bit to 1 if you want to get a pulse out of the compare pins.
The T1TOADC0-1 bits. Bits 7-8 in GPTCONA define the actions of timer 1 events upon
the analog to digital converter. As mentioned earlier, the ADC may be forced to start its
conversion operation by a GP Timer. Since we are not using the ADC, these bits are set 00
(no event triggers ADC). Check your manual for more options.
The T2TOADC0-1 bits. Bits 9-10 in GPTCONA define the actions of timer 1 events upon
the analog to digital converter. The ADC conversion sequence may be triggered by events
related to timer 2. Again, since we are not using the ADC, these bits are set 00 (no event
triggers ADC).
2
TMS320LF/LC240xA DSP Controllers Reference Guide System and Peripherals (Texas Instruments)
68
The T1STAT bit. Bit 13 in GPTCONA is a read -only bit providing information on the
timer counter status (0 counting downward, 1 counting upward).
The T2STAT bit. Same as bit 14 for timer 2.
5.1.4 I/O Pin Configuration
Never forget that most I/O pins on the DSP are multiplexed. Specifically, the
T1PWM/T1CMP pin can either be T1CMP, or just another general I/O pin (i.e., B4). It is
important to configure your I/O before using it. Normally, I/O should be configured after the
system initialization sequence. The best way is to create a function initIO(). Let us append file
DSP24_Sys.c. Open the file, and add the following function:
void initIO(void) {
MCRAbits->bit.T1PWMT1CMP_GPIOB4=1; // T1CMP pin set to PWM
}
Save the file. Now it is time to make a few changes in T1main.c and we will be ready to go!
5.1.5 The main() function
The modifications required for main() are the addition of a call to initIO(), as well as the
external declaration of the function. Modify the code as follows:
extern void initSystem(void);
extern void initTimer1(void);
extern void initIO(void);
void main() {
External declaration
of initIO()
initSystem();
initIO();
initTimer1();
asm(" CLRC INTM");
while (1) {
69
Save all changes to your files and to the project. The project browser window should now look
like the one in Figure 5-3.
Do a Rebuild all and download the program to the DSP. Our next task is to verify the PWM
signal from the T1PWM/T1CMP pin. So, get your oscilloscope ready.
5.1.6 Observing the Pulse Width Modulated signal on the T1PWM/T1CMP pin
Before we run the program, we will have to physically locate the T1PWM/T1CMP pin
on the DSP board. Figure 5-4 shows what you can also discover in the eZdsp LF2407A
Technical Reference manual by Spectrum Digital Incorporated.
70
You may now connect your oscilloscope probe to pin 15. Reference ground is located on pin
40 (you may alternatively use pin 39) in the header.
If your program is already loaded in the DSP, do a CPU Reset and a Go Main
afterwards. Remove breakpoints (if any) from the code, and do a Run. Hopefully, if all went
well, you should be able to see the pulse of Figure 5-5 on your oscilloscope display.
Figure 5-5. Oscilloscope display for the T1PWM/T1CMP pin (500us/div and 5V/div).
Theres nothing like seeing the results you expected to see! Let us examine our
beautiful signal for a while.
Notice that the pin stays high for a period of time equal to the one during which, it
stays low. This is happening because the compare register (T1CMPR) is loaded with 15000,
which is half of 30000, i.e., the value of the period register (T1PR). Recall that we chose a
continuous up/down counting mode. This means that the counter will run from 0 to 30000 and
then countdown to 0 again, thereby repeating this cycle for as long as the timer stays enabled.
The pin changes state whenever the counter meets 15000. Actually, it stays high from the
moment the counter starts until it hits 15000 for the first time. Afterwards, it switches to
low for a time interval equal to 2x15000=30000 (counter reaches 30000 and then descends
towards 0. Upon hitting 15000 during the descend count, the polarity changes again to
high) and the cycle repeats all over again (high-low-high-etc.). Consequently, the pin
stays high, as much as it stays low, for an interval of 30000 count-up/down steps. The
overall period of the signal is 60000 steps. As shown on the scope display, in terms of time
units, this corresponds to a signal period of approximately 1.5 ms. We may deduce that 1
increment/decrement step of the counter corresponds to 1.5 ms / 30000 = 0.025 sec
(approximately 40 MHz count increment/decrement frequency). Hey, remember the
71
clocking signal? We specified internal clocking (CPU) for the timer with /x1 prescaling, so it
would make sense that the counter should be following this frequency. In fact, the CPU
clock of the 2407A runs at about 40 MHz (recall PLL prescale factor, x4). Once again, always
verify your calculations with a scope. Although it only takes basic arithmetic, you better be
safe than sorry. Having a lot of parameters to play with is great on one hand, but is also the
usual reason for miscalculations.
Figure 5-6. Diagram of the timer 1 counter value and the T1PWM pulse through time.
It is highly recommended to play with the timers settings. Notice that you are free
to change the value of T1CMPR at any time in order to achieve different duty cycles with
your signal while the timer is running. Just keep in mind that any change in the T1CMPR value
will become effective (i.e., copied from the shadow register to T1CMPR) after the next period
match or underflow.
72
73
Obviously, in dual Sequencer mode, the two sequencers are sharing the very same
ADC; still, their utilization in our program would be as if we are managing two distinct ADCs
performing a number of auto-conversions per conversion step. Accordingly, we may define
different triggering sources for start of conversion (SOC) in each case (e.g., SEQ1 SOC triggered
by EVA, while SEQ2 SOC triggered by software). In the same way, the respective conclusions of
1
TMS320LF/LC240xA DSP Controllers Reference Guide System and Peripherals (Texas Instruments)
116
conversion runs are bound to be asynchronous to each other; this means that we will have to
acknowledge and handle them separately in the ADC interrupt service routine.
Figure 6-2. ADC Block Diagram with cascaded sequencers (as a single 16-state sequencer)2.
Things are more straightforward in cascaded mode: The ADC can perform a
maximum number of 16 auto-conversions in a single conversion run; SOC can be triggered by
only one source and the ADC ISR should be handling all the samples at once, following a
conversion run.
TMS320LF/LC240xA DSP Controllers Reference Guide System and Peripherals (Texas Instruments)
117
the project. As a next step, we need to create a header and a C file with the necessary register
structure definitions and declarations for the ADC registers.
6.2.1 Creating header and C files for the ADC Registers
The ADC does not involve a large number of registers, therefore the related header
and C files are not very extensive. Create a new file named DSP24_Adc.h and type the
following:
ADC Control Register 1
structure definition
#ifndef DSP24_ADC_H
#define DSP24_ADC_H
//ADCTRL1
struct ADCTRL1_BITS
unsigned int
unsigned int
unsigned int
unsigned int
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
int
int
int
int
int
int
int
int
int
{
STESTENA:1; // 0 Self TEST mode enabled
HILO:1;
// 1 Test Voltage for Test Mode
BRGENA:1; // 2 Allows a refernce voltage in calibration
CALENA:1;
// 3 Calibration enable - disabled the
// input channel multiplexer to calibrate
SEQCASC:1;
// 4 SEQuencer CASCaded operation
INTPRI:1;
// 5 ADC interrupt request priority
CONTRUN:1;
// 6 Continuous run
CPS:1;
// 7 Conversion Clock Prescale
ACQPS:4;
// 8-11 acquisition windows prescale
FREE:1;
// 12-13 configure
SOFT:1;
// operation on emulation suspend
RESET:1;
// 14 ADC software reset
rsvd1:1;
// 15 reserved
};
union ADCTRL1_REG {
unsigned int all;
struct ADCTRL1_BITS bit;
};
extern volatile union ADCTRL1_REG* ADCTRL1bits;
//ADCTRL2
struct ADCTRL2_BITS
unsigned int
unsigned int
unsigned int
unsigned int
unsigned int
unsigned int
unsigned int
unsigned int
unsigned int
unsigned int
unsigned int
unsigned int
unsigned int
unsigned int
};
{
EVBSOCSEQ2:1;
// 0 Allows SOC trigger by EVB
INTFLAGSEQ2:1; // 1 INTerrupt flag for SEQ2
INTENASEQ2:2;
// 3-2 INTerrupt mode ENAble for SEQ2
SEQ2BSY:1;
// 4 SEQ2 BuSY flag
SOCSEQ2:1;
// 5 SOC trigger for SEQ2
RSTSEQ2:1;
// 6 ReSeT SEQ2
EXTSOCSEQ1:1;
// 7 Allows SOC by the ADSOC pin
EVASOCSEQ1:1;
// 8 Allows SOC by EVA
INTFLAGSEQ1:1;
// 9 INTerrupt Flag for SEQ1
INTENASEQ1:2;
// 10-11 Interrupt mode for SEQ1
SEQ1BSY:1;
// 12 Sequencer1 busy
SOCSEQ1:1;
// 13 SOC triogger for SEQ1
RSTSEQ1STRTCAL:1; // 14 resets sequencer to CONV00 state
EVBSOCSEQ:1;
// 15 SOC by EVB (cascaded mode)
118
union ADCTRL2_REG {
unsigned int all;
struct ADCTRL2_BITS
};
bit;
bit;
119
Save the file and create the corresponding C file, DSP24_Adc.c. Type the following:
#include "DSP24_Adc.h"
volatile union ADCTRL1_REG *ADCTRL1bits = (void*)0x70A0;
volatile union ADCTRL2_REG *ADCTRL2bits = (void*)0x70A1;
volatile union AUTO_SEQ_SR_REG *AUTO_SEQ_SRbits = (void*)0x70A7;
volatile union CHSELSEQ1_REG *CHSELSEQ1bits = (void*)0x70A3;
volatile union CHSELSEQ2_REG *CHSELSEQ2bits = (void*)0x70A4;
120
Save file DSP24_Adc.c and add it to the project. Scan the project for dependencies and the
header file (DSP24_Adc.h) should appear under the Include branch on your project view
window. We may now take a look at the registers and their corresponding fields that we have
just included in our project.
6.2.2 The ADC Control Register 1 (ADCTRL1)
The ADC is configured with two control registers, ADC control register 1 and (ADCTRL1)
and ADC control register 2 (ADCTRL2). ADCTRL1 contains mainly configuration settings
regarding calibration and normal operation (Figure 6-3).
The STEST ENA bit. Bit 0 in ADCTRL1 (STESTENA) enables the self-test function (1enabled, 0-disabled).
The HI/LO bit. Bit 1 is used to define the type of voltage currently being calibrated or
tested. Specifically, in self-test mode, the bit informs the ADC about whether we are
testing the low voltage reference (0) or the high voltage reference (1). In calibration
mode, with respect to the value of the BRG ENA bit, the bit informs the ADC about
whether we are calibrating
, or
according to
Table 6-1.
3
TMS320LF/LC240xA DSP Controllers Reference Guide System and Peripherals (Texas Instruments)
121
BRG ENA
HI/LO
CALIBRATION VOLTAGE
VREFLO
VREFHI
Table 6-1. Reference voltage in calibration mode for the various values of BRGENA and HILO bits.
The BRG ENA bit. Bit 2 is the bridge enable bit. When set, it allows mid-point voltages
to be calibrated according to Table 6-1.
The CAL ENA bit. Bit 3 is enables calibration mode (1). If calibration is disabled (0),
the BRG ENA bit is ineffective.
The SEQ CASC bit. Bit 4 enables/disables cascaded sequencer mode. If 0, the ADC
operates in dual sequencer mode; if 1, ADC operates in cascaded sequencer mode.
The INT PRI bit. Bit 5 configures the ADC interrupt priority. A value of 0 corresponds
to high priority and 1 to low priority interrupts requests.
The CONT RUN bit. Bit 6 configures the sequencers action upon the end of an autoconversion sequence. As mentioned earlier, sequencers are finite state machines with states
corresponding to sampling steps. Either operating in cascaded or dual sequencer mode, the
sequencer(s) may stop and remain in the last state (CONT RUN = 0) or reset and start the
sequence all over again (CONT RUN = 1). In most cases we will be using continuous run (CONT
RUN = 1); however, according to the applications needs, we may require a sequencer to
remain idle after just one single auto-conversion sequence (ADC conversion step) and reserve
the right to reset (and possibly, restart) at a later time.
The CPS bit. Bit 7 configures the conversion clock prescaling. If 0, FCLK = CLK, whereas
if 1, FCLK = CLK/2. The ADC uses a clocking signal which may be equal to or half the period of
the CPU clock. The time during which a single sample is taken (also referred to as acquisition
time window) is configured by the ACQ PS1, ACQ PS2, ACQ PS3 and AC PS4 bits in terms of this
particular clocking signal (F CLK).
The ACQ PS1, ACQ PS2, ACQ PS3, ACQ PS4 bits. Bits 8-11 configure the acquisition
time window. The acquisition time window, also referred to as Sample and Hold (S/H)
window, is a period immediately prior to a sampling action. The length of the acquisition
window is directly related to the impedance of the ADCIN0-15 pins (see Tables 7-3 and 7-4 in
122
where TCLK is the period of the ADC clock signal. It is important to think of the ACQPS bits as a
way of configuring the impedance of the ADC, rather than a time delay during an autoconversion. We will be putting the above calculations to a test using an oscilloscope later on in
our example.
The SOFT and FREE bits. Bits 12 (FREE) and 13 (SOFT) configure the operation of the
ADC upon emulation suspension. Much like in the cases of most peripherals seen so far,
possible settings are: a) SOFT-FREE=00 for immediate stop on emulation suspend, b) SOFTFREE = 10 for completing current task before stopping and c) SOFT-FREE=X1 for free run.
The RESET bit. Bit 13 resets the ADC sequencers with a 1-write action. Writing 0
causes no action.
123
TMS320LF/LC240xA DSP Controllers Reference Guide System and Peripherals (Texas Instruments)
146
External connections involve the serial communication data transmit pin (SCITXD) and
the serial communication data receive pin (SCIRXD). When transmitting, data is originally
stored in the transmitter data buffer register (SCITXBUF) and thereafter, forwarded bit-by-bit
to the SCITXD line by the transmit shifting register (TXSHF). In a similar way, upon reception,
data is shifted from the SCIRXD pin through the receive shifting register (RXSHF) to the receiver
data buffer register (SCIRXBUF).
The SCI can be configured by three control registers, whereas data reception can be
monitored with the use of a status register. Transmit flags (TXRDY-TXEMPTY) are stored in SCI
control register 2 (SCICTL2). You may enable/disable transmit and receive interrupts in either
high or low priority. Moreover, you may enable/disable a receive error interrupt.
The SCI of the 2407A is typically organized as most microcontroller UART modules; if
you have already programmed microcontrollers for serial communications, the example that
follows should be very familiar. If you are worried about the multiprocessor communication
mode, it is practically a different way of wrapping your data before transmitting, but the
principles in configuration and operation remain the same. Roughly, using the SCI means
programming three control registers, setting-up a baud register value, enabling the receiver
interrupt and writing/reading data to/from the transmit/receive buffer register.
147
int
int
int
int
LOOPBKENA:1;
PARITYENA:1;
PARITY:1;
STOPBITS:1;
//
//
//
//
4
5
6
7
};
union SCICCR_REG {
unsigned int all;
struct SCICCR_BITS bit;
};
extern volatile union SCICCR_REG *SCICCRbits;
// Control register 1 bit definitions(SCICTL1)
struct SCITCL1_BITS {
unsigned int RXENA:1;
// 0 SCI receiver enable
unsigned int TXENA:1;
// 1 SCI transmitter enable
unsigned int SLEEP:1;
// 2 SCI sleep
unsigned int TXWAKE:1;
// 3 Transmitter wakeup method
unsigned int rsvd1:1;
// 4 reserved
unsigned int SWRESET:1; // 5 Software reset
unsigned int RXERRINTENA:1; // 6 Receive Error interrupt enable
unsigned int rsvd2:1;
// 7 Reserved
};
union SCICTL1_REG {
unsigned int all;
struct SCICTL1_BITS bit;
};
extern volatile union SCICTL1_REG *SCICTL1bits;
// SCI control register 2 (SCICTL2)
struct SCICTL2_BITS {
unsigned int TXINTENA:1;
// 0 Transmit interrupt enable
unsigned int RXBKINTENA:1; // 1 Receiver-buffer break interrupt enable
unsigned int rsvd:4;
// 5:2 reserved
unsigned int TXEMPTY:1; // 6 Transmitter empty flag
unsigned int TXRDY:1;
// 7 Transmitter ready flag
};
union SCICTL2_REG {
unsigned int all;
struct SCICTL2_BITS bit;
};
extern volatile union SCICTL2_REG *SCICTL2bits;
// Receiver status register (SCIRXST)
struct SCIRXST_BITS {
unsigned int rsvd:1;
// 0 reserved
unsigned int RXWAKE:1; // 1 Receiver wakeup detect flag
unsigned int PE:1;
// 2 Parity error flag
unsigned int OE:1;
// 3 Overrun error flag
unsigned int FE:1;
// 4 Framing error flag
unsigned int BRKDT:1;
// 5 Break-detect flag
unsigned int RXRDY:1;
// 6 Receiver ready flag
unsigned int RXERR:1;
// 7 Receiver error flag
};
148
union SCIRXST_REG {
unsigned int all;
struct SCIRXST_BITS bit;
};
extern volatile union SCIRXST_REG *SCIRXSTbits;
// Priority control register (SCIPRI)
struct SCIPRI_BITS {
unsigned int rsvd:3; // 0-2 reserved
unsigned int FREE:1; // 3 Free emulation suspend mode
unsigned int SOFT:1; // 4 Soft emulation suspend mode
unsigned int SCIRXPRI:1;// 5 (0-high priority, 1-low priority)
unsigned int SCITXPRI:1;// 6 (0-high priority, 1-low priority)
unsigned int rsvd1:1; // 6 (0-high priority, 1-low priority)
};
union SCIPRI_REG {
unsigned int all;
struct SCIPRI_BITS bit;
};
extern volatile union SCIPRI_REG *SCIPRIbits;
extern
extern
extern
extern
extern
volatile
volatile
volatile
volatile
volatile
unsigned
unsigned
unsigned
unsigned
unsigned
int*
int*
int*
int*
int*
SCIHBAUD;//
SCILBAUD;//
SCIRXEMU;//
SCIRXBUF;//
SCITXBUF;//
SCI
SCI
SCI
SCI
SCI
#endif
Save the file. We will soon be going through each of those registers.
Now, we need to declare the registers in a .c file. Create a new file named
DSP24_Sci.c for the declarations and type the following:
#include "DSP24_Sci.h"
// Communication Control Register
volatile union SCICCR_REG *SCICCRbits=(void*)0x7050;
// SCI Control Register 1
volatile union SCICTL1_REG *SCICTL1bits=(void*)0x7051;
//SCI Control Register 2
volatile union SCICTL2_REG *SCICTL2bits=(void*)0x7054;
//SCI Receiver Status Register
volatile union SCIRXST_REG *SCIRXSTbits=(void*)0x7055;
//SCI Priority Register
volatile union SCIPRI_REG *SCIPRIbits=(void*)0x705F;
// SCI baud-select register, high byte
volatile unsigned int* SCIHBAUD=(void*)0x7052;
// SCI baud-select register, low byte
volatile unsigned int* SCILBAUD=(void*)0x7053;
// SCI emulation data buffer register
149
Save the file. This pretty much wraps-up the SCI registers! Theres nothing more to add! It is
now time to go through the details of each one of those registers.
150
TMS320LF/LC240xA DSP Controllers Reference Guide System and Peripherals (Texas Instruments)
168
Other than that, the SPI uses two pins, SPISIMO (SPI Slave In-Master Out) and SPISOMI (SPI
Slave Out-Master In) for serial data transmission and reception according to configuration. In
practice, many off-the-shelf commercial SPI devices (such as analog to digital converters, LCDs,
etc.) do not transmit any data; therefore, in many cases, only one line (either SPISIMO or
SPISOMI) is used. Regardless of whether one or both SPI lines are used, master and slave
always transmit simultaneously, which explains the fact that there are no separate interrupts
for transmission and reception.
The operation of data exchange is very much similar to the one in SCI, as there are two
input and output buffer registers (SPIRXBUF, SPITXBUF) and two corresponding 4-level deep
FIFO stacks out of which, data is eventually shifted in/out the SPISIMO/SPISOMI lines. Figure
8-1 shows the block diagram of the peripheral.
To resume the principle of operation of the SPI, assume that the DSP is the master in a
connection with another device. In that case, the DSP uses its SPICLK line to initiate
transmission at will, while the slave transmits data simultaneously. In other words, the master
initiates transmission both ways, using his clock signal. In particular, upon one clock edge,
data is shifted into the line, while on the next edge, the shift register holds back and the
data remains latched. The process repeats until the entire character has been transmitted
from both sides. There are certain variations of this clocking scheme, but the principle
remains the same. An SPI device, except for the serial in/out line would typically have an
active-low strobe line used to enable it by the master; the strobe should be driven low prior to
transmission by the master (namely, the
pin) and high, immediately following
conclusion of the transmission. In short, the master sets the
line to low, in order to
initiate transmission; the line is kept low until the entire character has been transmitted.
8.2 A Program to Transmit characters with the SPI using the DSP as Master
Its about time to move on to an example. The overall functionality is very similar to
the one employed in the SCI example: We need to initialize the SPI at a certain bit rate,
configure it as a master and enable the interrupt. Create a new folder and project under
name, SPI and copy the following files: DSP24_Core.h,DSP24_Core.c, DSP24_Gpio.h,
DSP24_Gpio.c, DSP24_DeafultISR.h, DSP24_DefaultISR.c, DSP24_Sys.c, cvectors.asm
and 2407_cmd.cmd. Add these files to your new project and, of course, dont forget to add
the rts2xx.lib file.
8.2.1 Creating a new header file for the SPI registers
The SPI is not a very extensive peripheral in terms of the number of registers. All
registers are 8-bit long; therefore, this is a good chance to complete yet another peripheral
169
header file to the full extent. Create a new file named DSP24_Spi.h, and type-in the
following code:
#ifndef DSP24_SPI_H
#define DSP24_SPI_H
//SPI Configuration Control Register (SPICCR)
struct SPICCR_BITS {
unsigned int CHARLEN:4; // 0-3 Containing Character length in bits
unsigned int rsvd:2;
// 4-5 reserved
unsigned int CLKPOL:1; // 6 clock polarity
unsigned int SPIRST:1; // 7 Reset
};
union SPICCR_REG {
unsigned int all;
struct SPICCR_BITS bit;
};
extern volatile union SPICCR_REG *SPICCRbits;
// SPI Operation Control Register (SPICTL)
struct SPICTL_BITS {
unsigned int INTENA:1; // 0 Enables Transmit/Receive interrupt
unsigned int TALK:1;
// 1 Transmission enable.
unsigned int MST_SLV:1; // 2 if 0 SPI is slave, 1 for master
unsigned int CLKPHSEL:1; // 3 0 - normal clocking,1 - 1.5 cycle delay
unsigned int OVRNINTENA:1; // 4 Overrun Int enable
unsigned int rsvd:3;
// 5-7 reserved
};
union SPICTL_REG {
unsigned int all;
struct SPICTL_BITS bit;
};
extern volatile union SPICTL_REG *SPICTLbits;
// SPI Status Register (SPISTS)
struct SPISTS_BITS {
unsigned int rsvd:5; // 0-4 reserved
unsigned int TxBUFFULL:1; // 5 Transmit buffer full flag
unsigned int SPIINT:1; //6 SPI INT flag
unsigned int RxOVRN:1; // 7 Receive ioverrun flag
};
union SPISTS_REG {
unsigned int all;
struct SPISTS_BITS bit;
};
extern volatile union SPISTS_REG *SPISTSbits;
// SPI Baud Register (SPIBRR)
struct SPIBRR_BITS {
unsigned int BITRATE:7; // 0-6 SPI bit rate
unsigned int rsvd:1; // 7 reserved
};
union SPIBRR_REG {
unsigned int all;
170
// end definitions
Save the file. As you should be accustomed by now, the next step is to create the
corresponding C file DSP24_Spi.c containing the declarations of each one of the register
structures defined in the header file. Create DSP24_Spi.c and add the following:
#include "DSP24_Spi.h"
volatile union SPICCR_REG *SPICCRbits = (void*)0x7040;
volatile union SPICTL_REG *SPICTLbits = (void*)0x7041;
volatile union SPISTS_REG *SPISTSbits = (void*)0x7042;
volatile union SPIBRR_REG *SPIBRRbits = (void*)0x7044;
volatile union SPIPRI_REG *SPIPRIbits = (void*)0x704F;
// Non union-type declarations
volatile unsigned int *SPIBRR = (void*)0x7044;
volatile unsigned int *SPITXBUF = (void*)0x7048;
volatile unsigned int *SPIRXBUF = (void*)0x7047;
Save the file and add it to the project. If you scan for dependencies, DSP24_Spi.h should
appear under the include branch on your project browser window. Let us now examine a little
bit more closer each one of the registers defined and declared in the files.
171
The SPICHAR bits. Bits 0-3 in SPICCR configure the length of a character. Valid lengths
range from 1 - 16 and they correspond to values 0 15. One of the most common settings is a
value of 7 (8 bit characters); however, it is entirely up to the type of SPI device interfaced to
the DSP.
The CLOCK POLARITY bit. Bit 6 configures how the polarity of the clocking signal
(SPICLK) will affect the data transmission. Specifically, if 0, data is transmitted on a rising
edge and held with a falling edge. A value of 1 causes the opposite: output is
transmitted upon a falling edge and latched with a rising edge (with input transmission).
This is the typical scheme of things if the CLOCK PHASE bit in the operation control register is
set to 0. If the CLOCK PHASE bit is set to 1, the first data transmission precedes the first
rising edge if polarity is 0 or the first falling edge if polarity is 1, by 1.5 clock cycles and
thereafter, it occurs at a falling edge (if polarity is set to 0) or a rising edge (if the polarity
is set to 1). It is a bit confusing, but in practice most setups will involve both CLOCK
POLARITY and PHASE set to 0; therefore, in this case, things will be clear: Output
transmission upon rising edge (and latch with a falling edge) and input transmission upon
falling edge (and latch with a rising edge). The examples in Figures 8-4, 8-5, 8-6 and 8-7 should
give the general idea about how the various configurations work.
The SPI SW RESET bit. Bit 7 is used to clear the flags (RECEIVER OVERRUN, SPI
INTERRUPT and TX BUFFULL). It has no effect on the configuration of the SPI. If set to 0, flags
are cleared, but also the SPICLK line goes low if the DSP is operating as a master; if SWRESET is
TMS320LF/LC240xA DSP Controllers Reference Guide System and Peripherals (Texas Instruments)
172
1, SPI is ready to receive or transmit. Use this bit to clear the flags during configuration, but
you should remember to write a 1 shortly afterwards.
173
CAN transceiver takes care of the relative voltage conversions and signal
routing/multiplexing required to interface the Tx and Rx lines to the CANH and CANL lines.
Specifically, the DSP provides CANTX and CANRX pins multiplexed with IOPC6 and IOPC7
respectively, but it is up to you to interface those lines to the CAN bus by selecting and using
the appropriate transceiver (Figure 9-3).
9.1.3 The CAN lines (CANH and CANL)
The CAN bus is essentially a twisted pair of wires (CANH and CANL), each with a
resistance of no more than 60 m/m and terminator resistors usually chosen at 120 . The
CAN lines represent information based on a method known as differential signaling,
according to which, the voltage difference between the CANH and CANL lines represents
either a 0 or a 1. Specifically, the CAN bus contents, henceforth called the state of the bus,
are recognized according to the following rule:
From the above, it can be easily inferred that logic 1 is a common bus state even when
nodes are not transmitting. Moreover, if two nodes decide to simultaneously transmit a 1
and a 0 respectively, then the bus will eventually have a 0 state, since the first node will
be applying significant voltage to the bus, while the second one will be practically idle (or
forcing a minor voltage difference). For this reason, logic 1 bus states are called recessive,
whereas logic 0 bus states are called dominant.
A great advantage of differential signaling is that the noise present in one line is moreless present in the second; therefore, by retrieving the voltage difference between the CANH
and CANL lines, we cancel-out the common noise to a great extent. To demonstrate this
with simple algebra, let NCOMMON be the common noise and VCANH and VCANL the noise-free
voltages in CANH and CANL respectively; the voltage difference between the two lines can
then be calculated as:
Although the actual equations tend to be rather more complicated, however, the overall
principle is sane. The technique of canceling out common noise by retrieving voltage
differences is called common noise rejection and it really serves the CAN bus nicely! In fact, the
CAN bus is fairly reliable for distances up to 40 m with data transfer rates that may reach 1
Mbps. Figure 9-2 illustrates the general principle of common noise rejection in the CAN bus.
190
Figure 9-2. The general principle of common noise rejection in the CANH and CANL lines.
The CAN bus lines do not convey CMOS/TTL voltage level signals and moreover, the
DSP uses two separate pins to transmit (CANTX) and receive (CANRX) data, whereas the CAN
bus can be thought of as one single bi-directional data line for both transmission and
reception. In fact, the CANH and CANL lines can reach up to 18 V with a voltage level of CANH
CANL = 18 V 9V for dominant bits and CANH CANL = 9 V 18 V for recessive bits. For
these reasons, a buffering circuit is required to interface the Rx and Tx lines with the bus. The
LF2407A, as well as other commercial microcontrollers equipped with a CAN module, do not
usually come with an on-board CAN transceiver; therefore, it is up to you to build the buffer.
CAN transceivers are not difficult to interface and they are not exactly hard to find as there are
several manufacturers of such integrated circuits. Figure 9-3 shows package and function
diagram of the ISO1050 CAN transceiver by Texas Instruments.
Figure 9-3. Package outline and function diagram of TIs ISO1050 CAN transceiver1.
9.1.3 Exchanging messages through the CAN bus using Data and Remote Request Frames
The CAN bus protocol is designed to accommodate the broadcasting of data frames
throughout the common bus. Each data frame contains an identifier (ID) field, based on which,
1
191
the rest of the nodes decide on whether to keep it or ignore it. If a frame arrives to a node and
the ID is not included in the list of acceptable IDs for that particular node, then the frame is
ignored, otherwise the node either stores the frame data or automatically tries to respond to
it by placing a new frame on the bus. To clarify the last statement, the CAN bus protocol
involves essentially two different types of frames in terms of message exchanging: a) Data
frames, containing data and b) Remote frames, requesting a reply from the nodes that
accept their ID. The structure of a CAN data frame is shown in Figure 9-4.
The SOF field. Transmission of a frame always commences with a start of frame (SOF)
bit which should be dominant (i.e., 0).
The Arbitration field. Based on the original CAN specification (2.0A, standard), the
arbitration field is essentially the identifier of the frame, along with the remote request (RTR)
bit; if the RTR bit is set, the frame does not contain data, but rather is a request for a data
frame. Based on a newer CAN specification (2.0B, extended), the arbitration field is 32 bits
long, containing two identifiers of length 11 (base ID) and 18 (extended ID), a flag that defines
whether the extended or standard ID is used (IDE), the substitute remote request (SRR) bit
which overrides the RTR bit, if using extended ID; finally, the RTR bit concludes the list.
Practically, you shouldnt be extremely worried about all these details, since the DSP CAN
controller deals with the frame wrapping automatically. Your task is to configure the
peripheral by defining the valid IDs and to provide or handle the frame data. However,
knowing the mechanisms governing the exchange of data throughout the CAN bus will give
you a better insight and intuition as to what may go wrong in case your program does not
produce the results you expected. Note here that the DSP CAN controller uses the extended
arbitration field structure with the option of using the standard by setting the IDE bit to 0.
Figures 9-5a and 9-5b illustrate the structure of a standard and extended CAN frame
arbitration field.
192
The Control field. The control field is 6-bit long with the last four bits containing the
data length code (DLC), which is the number of bytes contained in the data field. The first two
bits in the control field are reserved and usually receive dominant values; generally, they are
ignored. Figure 9-6 shows the structure of a CAN frame control field.
The Data field. The CAN frame data field contains data which cannot exceed 8 bytes in
length.
The CRC field. The CRC field contains a 15-bit cyclic redundancy checksum sequence
calculated based on BCH code, and a last bit, the CRC delimiter, which is always recessive.
Figure 9-7 shows the structure of the CAN CRC field.
The ACK field. The ACK field contains two bits, the ACK slot and the ACK delimiter.
Initially, both bits are recessive in the frame upon transmission. Since the CAN bus is a closed
channel, each node can hear itself while placing bits on the bus. Once a different node
receives the frame data correctly, it then asserts a dominant bit during the time period that
the transmitting node places the ACK slot bit on the bus. This way, the echo of the ACK slot
bit comes back as dominant to the transmitting node, hence, interpreted as a sign that at least
193
one remote node has received the frame correctly. As far as the DSP is concerned, the ACK
slot corresponds to a flag (ACK) and you may either choose to use it or ignore it. Figure 9-8
illustrates the CAN frame ACK field bits.
The EOF field. The end of frame (EOF) field contains seven recessive bits.
It should be noted that remote request frames are, in fact, data frames without the
control and data fields.
Consecutive frames placed on the bus are separated from each other by interframe
space, which is composed of a series of 3 recessive bits called the intermission and a series of
8 recessive bits called the transmission suspend field. Essentially, the hardcore break
between frames is the intermission, during which, none of the nodes can initiate
transmission. The transmission suspend field is a period during which, error passive nodes
(explained shortly) may not initiate transmission; however, others may do. Following
transmission suspend, if no transmission has been initiated (with a dominant bit), the bus is
said to be in idle state. Figure 9-9 shows the structure of the interframe space.
194
Arbitration for control of the bus is done on the basis of which node ID will eventually
get through to the bus. The idea is that, whoever puts a dominant bit (0) wins over the
ones who put a recessive bit (1) and given that IDs should be unique, eventually only one
ID will go through. As soon as a node wins arbitration, all other nodes resign and wait until
the winner transmits its entire frame. Following transmission of the frame, the losers will
attempt transmission and the process repeats itself, thus ensuring that, all in good time,
everybody will transmit their frame.
As an example, take three CAN nodes attempting to transmit frames with ID values of
7 (0111b), 5 (0101b) and 8 (1000b) and assume for the sake of simplicity, that the IDs are 4-bit
long. Upon transmission of the first ID bit, nodes 1 and 2 win the bus, while the third resigns.
Upon the second bit, both nodes win, since they are placing a 1 on the bus. However, on the
third bit node 2 wins, since it places a dominant bit (0), whereas node 1 places a recessive
(1) and therefore it resigns from the arbitration. Following the forfeit of nodes 1 and 3 from
the arbitration, node 2 will transmit the remaining frame bits, while the others will sit and wait
until the frame transmission is complete. Once transmission is complete, nodes 1 and 3 will
compete again for the bus. Figure 9-10 shows the sequence of events during the arbitration.
Figure 9-10. Bus arbitration between three CAN nodes with 4-bit long IDs.
Except the arbitration rules mentioned above, there are several other details ensuring
that there will be no collisions on the bus which can be found in the CAN Specification 2.0
manual by Robert Bosch and it is highly recommended that you read through the relative
sections (if not all). The CAN controller of the DSP takes care of transmission and reception
without you having to deal with any of the low level operations mentioned here; however,
configuring the controller is your task and in order to that, you should be aware to some
extent, of the events taking place on the CAN bus.
195
196
10
244
Eulers identity is the most popular representation used, since it provides the means
for a more convenient notation, while computations can be facilitated by the properties of the
exponential:
Generally,
Figure 10-1. A cosine wave and the corresponding complex number on the complex plane.
domain signal. The time domain form contains the values of the signal through time,
whereas the frequency domain form contains the values of phase and magnitude of the
sinusoidal waves to which the signal is decomposed. Each form is equivalent to the other and
describes the signal completely (or approximates it to a certain extent). To clarify this with an
example, consider a periodic signal in the time domain defined by the following:
Notice that f is already conveniently written as a sum of cosines. Also notice that the angular
frequency of the second term is double the angular frequency of the first (1=1, 2=2). In fact,
the fundamental concept of Fourier analysis involves approximating (or converging towards)
the function with a finite sum or series of cosines with angular frequencies being integer
multiples of a minimum frequency (called the fundamental frequency), denoted as 0. From
this point of view, if we choose 0 = 1, we have f(t) exactly in the form that we want it.
The frequency domain signal is a new function derived from the time domain signal,
mapping the various frequencies involved in the sum (i.e., 0=1, 1=2) to the respective
magnitudes and phases, in other words, the complex numbers that correspond to each of the
cosines in the sum. If we set aside complicated math for a moment and act purely on
intuition, we may observe the following relations between the cosines involved in the
equation of f and the complex numbers that represent their magnitude and phase:
Based on these observations, we may now define the frequency domain function as follows:
Although we violated several fundamental concepts of Fourier analysis and you probably feel
that you need to make amends to the gods of mathematics, you will be relieved to know that
function F, is indeed, a frequency domain function of f. Unfortunately, whether
approximating the signal with a finite or infinite sum of cosines, the process of finding the
frequency domain signal is not that simple at all. However, you may keep conclusions: The
frequency domain is a function that maps the frequency components (cosines) of the sum to
their respective magnitudes and phases.
246
The infinite sum that approximates f(t) is called the Fourier series, while coefficient ak is
actually the value of the frequency domain function for frequency k0. Notice that the
Fourier series runs from
to
. Also, in case you are wondering how is it possible having
a sum of complex exponentials producing a real number as a result, notice that also ak is a
complex number; therefore, throughout computations, the imaginary components are
eliminated.
Depending on the selection of the fundamental frequency 0, the sum may
approximate f(t) well enough, even within a few terms. In other cases, it may not converge at
all even with infinite terms. Generally, if f is bounded in a bounded time interval (considered
zero for every other time instance out of this interval), the series will converge. The multiples
of the fundamental frequency 20, 30, ..., 0, ..., are called harmonics.
If we now go back to the function of section 10.1.2, and choose 0 = 1, then the
coefficients of the Fourier series for the first two harmonics can be calculated as follows
(intermediate calculations are omitted):
247
Interestingly, the results are looking much like the ones we deduced by observation in the
previous section. Note that computations require that we calculate the frequency domain
value for both k0 and - k0. The Negative frequency k0 corresponds to the same
harmonic component (cosine) with k0. In fact, all frequency components for
are
described by two conjugate Fourier coefficients.
Although the math concurs with our intuition, calculations are not over yet! We still
have to calculate the frequency domain value for k = 0 (a0). Coefficient a0 corresponds to the
constant component of the signal, sometimes referred to as DC offset. In our example, a0 is
found to be 0:
This is obvious, since there is no constant term involved in the equation of f(t). However, if f(t),
involved a constant term, say, equal to 3, such as:
In short, the frequency domain comprises an odd number of coefficients, a-k, a-(k-1),
, a-1, a0, a1, , ak-1, ak corresponding to the harmonic components (cosines) of the signal,
with frequencies 0, 0, ..., (k-1)0 , k0; each harmonic component produces a pair of
conjugate values (a-k, ak) in the frequency domain, except for the 0-frequency (DC offset)
component which produces only one value (a0). The sum may also be infinite, although in
some cases, such as in our example, the coefficients will become 0 after a certain value of k.
Greater values of k will generally produce higher degree of convergence of the sum.
Depending on the chosen function, the series may not converge at all, but this is an issue that
shouldnt keep us worried throughout this text.
The frequency domain function F(k0) = maps frequencies to complex numbers,
therefore, we need two distinct graphs to draw it: One for magnitude and one for phase. To
go back to our example, the frequency domain function F(k) for f(t) =cost + 2cos(2t+/3)
should be the following:
248
Although we decided to use only two harmonic components in the sum, if you put yourself in
the trouble to make a few calculations, you will realize that all coefficients for
are 0:
This means that the series converged with only five terms and our frequency domain is 100%
equivalent to the original time domain signal with only two harmonic components!
Figure 10-2. Magnitude and phase of the signal in the frequency domain.
The process of decomposing the time domain signal into the frequency domain values
is called analysis, as opposed to the reverse process, called synthesis. The frequency domain,
also called frequency spectrum, can reveal certain attributes that may be of critical importance
in the further processing of the signal. In fact, obtaining the frequency spectrum of a signal, in
a great number of occasions, is much more useful to engineers than the actual time domain
form.
10.1.4 The Time-Continuous Fourier Transform
Although the Fourier series applies to periodic functions, the concept can be expanded
to apply to any function under certain conditions. Specifically, if we assume that the
fundamental frequency 0 is converging to 0, then the period T = 2 / 0 is also converging to
infinity. In this case, the frequency domain coefficients become a continuous function of
frequency and can be calculated by,
249
Function F is known as the continuous-time Fourier transform and can provide the continuous
frequency domain of any signal, given that the integral converges. The inverse transform can
be found in a similar manner:
The coefficient can now be found with the use of a sum instead of an integral and therefore, it
can be easily calculated inside a program loop. The fundamental frequency is always chosen to
be 0 = 2/ and the number of samples (N) is called fundamental period. What lies under
the mat here, is the fact that we silently assume that the N samples are a period of an
infinitely long periodic signal. Of course, this is not true in most cases; however, for that
particular window of N values, the DFT will produce the frequency domain nicely!
The standard notation for the Fourier coefficients (frequency domain signal) is X[k]
(instead of the ak, used so far), while the time domain signal is denoted with x[k]. Also, ReX[k]
and ImX[k] are the real and imaginary parts of X[k].
To synthesize the time domain signal, the process is almost identical:
250
For synthesis, also known as the inverse DFT, the process is quite similar. However, be
mindful that the sums are not divided by N.
Figure 10-3 illustrates the three collections of data, x, ReX and ImX involved in the process of
forward and inverse DFT.
Figure 10-3. The three collections of data involved in the forward and inverse DFT.
251
The DFT algorithm discussed in this section is simple to implement and produces
reliable results. However, it is not used in most DSP applications, since it is significantly slow
compared to its fast counterpart, the fast Fourier transform (FFT). The FFT produces the
same results with great performances, compared to the very slow, simple DFT. Unlike the
simple DFT, the FFT is complicated enough to confuse even the most experienced
programmers, but this a price that developers are willing to pay in exchange for a highly
optimized application.
We will be initially implementing the simple DFT algorithm as two nested summation
loops in order to monitor results in the oscilloscope in the example that follows. The program
will be enhanced with an FFT routine in later sections.
252
DIGITAL FILTERS
11
Digital Filters
Since all things in life and DSP are finite, the practical interest of the operation lies with
sequences of finite length; so, let us take an example of two vectors x = [2 5 0] and h = [1 2].
Note that invalid indexes (e.g., i=-3) are assumed to correspond to zero values: Specifically,
x[i] = 0, if i < 0 or i > 2 and h[i] = 0, if i < 0 or i>1. Since both sequences are finite, the
convolution will produce a new sequence, y[n], which will also be finite:
289
DIGITAL FILTERS
Convolution is a commutative operation and therefore, the results obtained with the process
illustrated in Figure 11-1, will be the same if we use vector h sliding over x.
290
DIGITAL FILTERS
In DSP, one of the two convolved vectors is always of finite length and called the
convolution kernel, usually denoted with an h. The kernel is the actual filter. The other
operand is a portion of an infinite sequence, corresponding to the sampled values of a signal,
usually denoted with an x. Regardless of whether x is finite or not, the calculation mechanism
will remain exactly the same.
11.1.2 Impulse, Frequency and Step Response of LTI Systems
One may conceptualize a digital filter as a box with fixed properties (time invariant)
that receives a sampled signal as input and produces a new signal in the output. The filters
examined in the chapter are also linear, in the sense that any linear relationship between
inputs will be valid for their respective outputs through the system. The box contains a
mathematical mechanism that acts upon the input in order to produce the output called the
filter kernel or, more general, the transfer function of the filter. In fact, the output can be
calculated as the convolution of the input with the kernel of the filter. However, to study the
behavior of a system, the Z-transforms of the input, output and transfer function are more
likely to be used instead of the actual sequences. Minimum acquaintance with the properties
of the Z-transform would be very helpful but not absolutely required for the next sections.
With respect to the input, LTI systems will produce a specific behavior in their output.
There are generally three types of inputs, the step, the sinusoidal and the impulse input, that
are of particular interest for system engineers. The output corresponding to each one these
inputs, describes the system from a unique perspective.
The impulse response is the output of the system, when an impulse input is applied.
A discrete impulse, denoted with [n], is a sequence such as:
or, generally:
291
DIGITAL FILTERS
Consequently, the output sequence will also be equal to the inverse transform of the transfer
function, h[n]:
From the above, the impulse response is equal to the kernel of the filter and can be calculated
as the inverse Z-transform of the transfer function. Moreover, we can calculate the output of
the system for a given input, by convolving the kernel with this input.
The step response is the output of the system, when a step input is applied. A step
input, denoted with u[n], is a sequence, such as:
or, generally:
Practically, the step response is a measure of how well the system output settles at a
constant following a step input. Since the input is constant, we would expect the output to be
likewise, given that the system is stable. Following a step input, the output will attempt to
follow the input and stabilize around a constant value as well. What is of interest to system
engineers here, is how the output moves towards that constant value, also known as steady
state output. It is generally desirable that this transition is as smooth and fast as possible.
The frequency response is the phase and amplitude of the systems output when
sinusoidal waves of varying frequencies are applied as inputs. To calculate the frequency
response, we may simply set z = ej in the transfer function, H(z) :
292
DIGITAL FILTERS
If equation (11.7) brings back a few memories, then you made the right connection. The
frequency response is also the Fourier transform of the impulse response of the system; this
coincidence can be of great help in the design of filtering algorithms. In essence, the
frequency response is a description of the systems output in the frequency domain. The
frequency response does not really represent an output, but rather the general treatment
that any input will receive in terms of its harmonic components by being passed through the
system. This is why H(ej) is also commonly referred to as the systems gain.
In order to obtain a global view regarding the performance of the system, the step and
frequency response is all we really need. The step response gives us the performance in terms
of the time domain, while the frequency response gives us the performance in terms of phase
and amplitude of the outputs harmonic components. Generally, digital filters will perform
well in only one aspect of the two. A filter that works nice in terms of separating frequency
components will normally have a poor step response with plenty of ripples and fluctuations,
while a filter that has a smooth step response, is likely to have a poor performance in
separating the harmonic components of the input.
11.1.3 Implementation of Digital Filters
The design of a digital filter essentially concerns the definition of a relationship
between the output and the input sequences. The generic form of such a relationship is
described by the following:
Digital filters are generally categorized into finite impulse response (FIR) and infinite
Impulse response (IIR) filters.
Specifically, if the relationship between the output and the input does not include
previous values of the output (i.e., ak = 0), the filter is an FIR filter and the relative equation
becomes,
Filters that require previous values of the output in the calculation of the new output are
called recursive or infinite impulse response (IIR) filters.
293
DIGITAL FILTERS
Figure 11-3. Convolution calculations using an input rolling buffer and a filter kernel of size M+1.
The FIR filter calculations are also typically presented with a direct-form flow-graph
(Figure 11-4). The z-1 symbol is used to denote the previous term of the input sequence. It is
based on a property of the Z-transform, according to which,
and
-1
therefore, Z{x[k-1]} = z X(z).
294
DIGITAL FILTERS
Calculations involve shifting and storage of the inputs and outputs in separate arrays of
length M+1 and N respectively. The new output is calculated as the sum of the products of the
input and output buffers with the two corresponding arrays of coefficients. Both buffers
should be initialized with zeros. Figure 11-5 illustrates output calculations using two rolling
buffers and two arrays of coefficients.
Figure 11-5. Recursive (IIFR) filter output calculations using two rolling buffers.
The respective representation of the calculations can be given in the form of a directform I flow-graph.
295
DIGITAL FILTERS
The method described in Figures 11-5 and 11-6 is fairly easy to implement, as it involves four
arrays, two of which, are rolling buffers for input and output, and two simple sums. If you are
thinking that things are unfolding strangely easy so far, unfortunately, you are correct.
Although the computation method described above is fairly easy, however, it is NOT the
DSP way! Always keep in mind that DSP routines have to be optimized in terms of execution
time and memory space usage to a feasible extent. It is possible to implement a routine
performing the same computations by using only three arrays instead of four and that is the
strategy that the god of DSP wants us to follow.
At this point, if you are not very much fond of math and control theory, you may wish
to skip the entire process that follows and get straight to the results. However, it is always
better to have a deeper insight into the logic behind the optimization of the routine.
Recall from control theory, that we may obtain the state space equations of a system
from its transfer function. Moreover, we can write these equations in canonical form. An IIR
filter, above all, is a system and its transfer function can be obtained by transforming equation
(11.10):
296
DIGITAL FILTERS
We may now write the state space equations of the system in canonical form, so that,
where D[n] is the state matrix, A is the state transition matrix, B is the control matrix, X[n] is
the systems input, C is the output matrix and Y[n] is the systems output. We may now obtain
matrices A (size, NxN), B (size, Nx1) and C (size, 1xN) as follows:
Let d1[n], d1[n], , dN[n] be the systems states. We may now calculate each state at step n in
terms of the previous states by substituting in equation (11.13):
If we now set dN[n] = d[n], then, from the relations in (11.15), we get that dN-1[n] = d[n-1], dN2[n ]= d[n-2], , d1[n] = d[n-(N-1)]. Now, d[n+1] can be expressed with previous terms:
297
DIGITAL FILTERS
The output of the system can now be calculated in terms of the state vector:
Equations (11.19) and (11.20) are valid only when N>M. For cases in which
, the
process is similar, but the results are slightly different and the buffer should have a size of
M. Specifically, for
, equations become:
Note here, that (M+1-N) phase in the output is usually disregarded and the
calculations are based on the terms of d[n] as they appear in the right-hand part of
equations (11.19)-(11.20) or (11.21)-(11.22) without any adjustments in their phase.
Let us take an example with N = 2 and M = 2. Equations (11.21) and (11.22) yield the
following:
298
DIGITAL FILTERS
Notice the -1 phase shift in the output. The shift will not affect our calculations and they will
still be based on d[n], d[n-1] and d[n-2]. Also, note that the buffer containing d[] can have a
size of only two positions, since d[n] can be calculated in terms d[n-1] and d[n-2].
Figure 11-7 illustrates the relative arrays and corresponding calculations for the
previous example (N = M = 2). The filter can also be described with the direct-form II flowgraph illustrated in Figure 11-8.
Figure 11-7. Recursive filter output calculations using one rolling buffer.
299
DIGITAL FILTERS
Figure 11-8. Direct-form II flow-graph for an IIR filter with M = N =2 (2nd order).
300
12
A product-scaling shifter.
Data-address generation logic, which includes eight auxiliary registers and an auxiliary
register arithmetic unit (ARAU).
Program-address generation logic.
You may find plenty of details regarding the above, in the TMS320LF/LC240xA DSP
Controllers Reference Guide CPU and Instruction Set.
The CPU registers of great interest to us are, the 32-bit accumulator (ACC), which is
practically the main ingredient in almost every calculation, the 32-bit product register
(PREG) to accommodate multiplication results in conjunction with the accumulator and the
eight auxiliary registers (AR0-AR7) used for addressing. Additionally, the temporary register
(TREG) and the 32-bit status register as two 16-bit registers (ST0 and ST1) will also play an
important role in our callable assembly routines. Except the product register and the
accumulator being 32-bit long, the rest of the core registers are 16-bit long. Figure 12-1 shows
the values of the CPU core registers during debugging with the Code Composer Studio
(menu View Registers).
The rest of the core registers include the very well known to us, IMR and IFR, the
program counter (PC), the repeat counter (RPTC) used to count iteration steps, the top of the
stack (TOS), pointing to the program stack top and the global data memory register (GREG),
used to determine the size of global data memory.
The status registers ST0 and ST1 contain flags and control bits. Some of the fields
described below play an active role in computations (e.g., the PM bits determine the number
of positions to shift the result of a multiplication prior to addition to the accumulator). Figures
12-2a and 12-2b show the bitwise outline of status registers ST0 and ST1.
346
The ARB bits. Bits 13-15 of ST1 are the auxiliary register buffer. The buffer contains the
index of the previously selected auxiliary register (0-7 for AR0-AR7).
The ARP bits. Bits 13-15 of ST0 are the auxiliary register pointer. This is a pointer to the
selected auxiliary register (0-7 for AR0-AR7). The auxiliary register selected by ARP is used for
addressing purposes (explained in the next section) and it plays an important role in
calculations.
The CNF bit. Bit 12 in ST1 determines whether reconfigurable dual-access RAM blocks
(i.e., B0) are mapped to data space or to program space. If CNF is 0, reconfigurable dual
access RAM blocks are mapped to data space; if CNF is 1 reconfigurable dual access RAM
blocks are mapped to program space.
The OV bit. Bit 12 in ST0 is the overflow flag.
The TC bit. Bit 11 in ST1 is the test/control flag. It reflects the state of a condition
related to an instruction (e.g., conditional branches).
The OVM bit. Bit 11 in ST0 determines actions on overflows. If 0, no action is taken;
if 1, the accumulator is set to either its most positive or most negative value.
The SXM bit. Bit 10 in ST1 is the sign-extension mode bit. Recall that this bit suppresses
sign extension during shifts. Cleared with CLRC SXM and set by SETC SXM.
1
TMS320LF/LC240xA DSP Controllers Reference Guide System and Peripherals (Texas Instruments)
347
The INTM bit. Bit 9 in ST0 is the global interrupt switch. It must be cleared (as we did in
almost all examples throughout this text) to enable interrupts.
The XF bit. Bit 4 in ST1 determines the state of the XF pin, which is a general-purpose
output pin.
The DP bits. Bits 0-8 in ST0 are the data page pointer. Data memory is divided into
pages of size 128 words. DP may point to any of these data pages and is used for addressing
purposes.
The PM bits. Bits 0-1 in ST1 determine the amount that the PREG value is shifted on its
way to the CALU or to data memory. You should bear in mind that the PM bits will affect the
result of certain instructions, such as MPY, ADD, etc., essential to your program and therefore,
you should always set these bits prior to everything else. If PM is 00 no shifts occur at all. If
PM is 01, PREG is left-shifted by one position. If PM is 10, PREG is left-shifted by 4 bits.
Finally, a setting of 11, produces a right shift of six bits, sign extended. To set the value of
the PM bits, use instructions SPM or LST.
348
Bibliography
Lovrich, A., et al., 1987. Digital Signal Processing Applications with the TMS320 Family,
Volume 1. Englewood Cliffs, New Jersey: Prentice-Hall Inc.
Toliyat, H., Campbell, S., 2004. DSP-Based Electromechanical Motion Control. Boca
Raton, Florida: CRC Press, LLC.
Smith, S. W., 1997. The Scientist and Engineers Guide to Digital Signal Processing. San
Diego, California: California Technical Publishing.
Oppenheim, A. V., Willsky, A. S. and Nawab, S. H., 1997. Signals & Systems. Upper
Saddle River, New Jersey: Prentice-Hall Inc.
Ogata, K., 1995. Discrete Time Control Systems. Upper Saddle River, New Jersey:
Prentice-Hall Inc.
Reese, R., Bruce, J. and Jones, B., 2009. Microcontrollers. From Assembly Language to C
Using the PIC24 Family. Boston, Massachusetts: Course Technology.
Douglas, F. E., 1987. Handbook of Digital Signal Processing Engineering Applications.
Anaheim, California: Academic Press, Inc.
374
Sources
375
Texas Instruments, 2010. ISO1050 Isolated CAN Transceiver. [online] Dallas, Texas:
Texas Instruments Incorporated. Available at:
<http://focus.ti.com/lit/ds/symlink/iso1050.pdf> [Accessed 5 December 2010].
CAN in Automation, 2010.CAN Protocol Specification. [online] Nuremberg: CAN in
Automation. Available at: <http://www.can-cia.org/index.php?id=520> [Accessed 27
November 2010].
Softing AG, 2010.CAN bus (Controller Area Network), an overview. [online] Softing AG.
Available at: <http://www.softing.com/home/en/company/index.php#> [Accessed 27
November 2010].
Bosch, R., 1991.CAN Specification. [online] Stuttgart: Bosch. Available at:
<http://esd.cs.ucr.edu/webres/can20.pdf> [Accessed 29 November 2010].
Wikipedia, 2010. Cooley-Tukey FFT Algorithm. [online] Wikipedia. Available at:
<http://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm> [Accessed 27
November 2010].
Jones, D., 2004. FIR Filter Structures. [online] Connexions. Available at:
<http://cnx.org/content/m11918/latest/> [Accessed 2 December 2010].
Jones, D., 2004. IIR Filter Structures. [online] Connexions. Available at:
<http://cnx.org/content/m11919/latest/> [Accessed 17 December 2010].
Vandevenne, L., 2007.Lodes Computer Graphics Tutorial Fourier Transform. [online]
Lode Vandevenne. Available at:
<http://www.student.kuleuven.be/~m0216922/CG/fourier.html#introduction> [Accessed 2
December 2010].
Bores, C., 2010. Introduction to DSP IIR Filters. [online] Woking, Surrey: Bores Signal
Processing. Available at: <http://www.bores.com/courses/intro/iir/index.htm> [Accessed 2
December 2010].
Wikipedia. Butterworth Filter. [online] Wikipedia. Available at:
<http://en.wikipedia.org/wiki/Butterworth_filter> [Accessed 21 December 2010].
376