Вы находитесь на странице: 1из 106

Introduction to C Programming

with the TMS320LF2407A


DSP Controller

George Terzakis

ii

To my dad; we miss you.


G.T.

iii

iv

About the author


George Terzakis received the B.S. degree in Informatics from the University of Piraeus,
Greece, in 1999. He received the M.S in Electronics & Computer Technology from Indiana
State University, Terre Haute, IN, in 2002 and the M.S. in Robotics from the University of the
West of England, Bristol, in 2010. He joined the Greek army in 2003 for a 12-month period of
national service and during the period of 2005-2010, his main occupation involved teaching
the fundamentals concepts in programming and informatics as a junior/senior high-school
teacher. Among several other jobs, he has worked part-time for Indiana State University and
the University of Patras, Greece, in topics concerning robotics and automation. His research
interests are focused on robotics and relative disciplines.

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

Programming the LF2407A in C ................................................................................................................4

1.3

What you need in order to read this book ...............................................................................................5

2. WRITING AND EXECUTING PROGRAM HELLO ......................................................... 7


2.1 Creating a first project with Code Composer Studio .....................................................................................7
2.1.1 Creating the C file(s) ..................................................................................................................................8
2.1.2 The missing details ....................................................................................................................................8
2.1.3 Putting it all together ..............................................................................................................................10
2.1.4 The moment of truth ...............................................................................................................................11
2.1.5 What do we expect to see? .....................................................................................................................13
2.2 How did we do it? ..........................................................................................................................................13
2.2.1 Initialization of the System Control and Status Registers 1, 2 (SCSR1 and SCSR2).....................................14
2.2.2 The Watchdog .........................................................................................................................................16
2.2.3 I/O Pin configuration ...............................................................................................................................18
2.3 Using C structures to access register bits .......................................................................................................20
2.4 The Linker Command File ...............................................................................................................................21
2.4.1 Sections generated by the C compiler .....................................................................................................21
2.4.2 The MEMORY clause in the Linker Command file.....................................................................................24
2.4.3 The SECTIONS clause in the Linker Command file ....................................................................................25

3. REFINING PROGRAM HELLO ........................................................................................28


vii

3.1 Beginning of execution ...................................................................................................................................28


3.1.1 The Reset interrupt Vector ......................................................................................................................29
3.2 Completing the cvectors.asm file ................................................................................................................31
3.2.1 The LF2407A Core Interrupts ...................................................................................................................31
3.2.2. Adding Declarations for Core Interrupt Service Routines 1-6 in C ...........................................................32
3.3 Building Register Structure Header files .........................................................................................................34
3.3.1 Creating an I/O Register Header File ........................................................................................................34
3.4. Completing the System Initialization Sequence ............................................................................................36
3.4.1 Configuring the System Control and Status Register 1 .............................................................................38
3.4.2 Configuring the Wait-State Generator Control Register (WSGR) ..............................................................39
3.5 Modifying the main() function .......................................................................................................................40
3.6 Adding files to the project ..............................................................................................................................41
3.7 Building and Debugging project hello .........................................................................................................42
3.7.1 Debugging the Program ...........................................................................................................................42
3.7.2 Setting up Breakpoints ............................................................................................................................43
3.7.3 Using the Watch Window ........................................................................................................................43
3.8. Summary .......................................................................................................................................................44

4. USING INTERRUPTS AND THE GENERAL PURPOSE TIMERS .................................46


4.1 A brief introduction to Interrupts of the 2407A .............................................................................................46
4.1.1 The Peripheral Interrupt Expansion Controller (PIE) ................................................................................46
4.2 Using a General Purpose Timer ......................................................................................................................47
4.2.1 Project Timer1 ......................................................................................................................................48
4.2.2 Timer 1 initialization ................................................................................................................................48
4.2.3 Timer 1 Interrupt Service Routines ..........................................................................................................55
4.3 Executing the Program ...................................................................................................................................60
4.4 Summary ........................................................................................................................................................61

5. THE EVENT MANAGERS ....................................................................................................64


5.1 Overview on the Event Managers ..................................................................................................................64
5.1 Using Timer 1 for Pulse Width Modulation ....................................................................................................65
5.1.1 Expanding DSP24_Ev.h .........................................................................................................................66
5.1.2 Modifying the Timer 1 Initialization function ...........................................................................................67
5.1.3 General Purpose Timer Control Register A...............................................................................................68

viii

5.1.4 I/O Pin Configuration ...............................................................................................................................69


5.1.5 The main() function .................................................................................................................................69
5.1.6 Observing the Pulse Width Modulated signal on the T1PWM/T1CMP pin ...............................................70
5.2 Using the Compare Units for Pulse Width Modulation in a new project........................................................72
5.2.1 Configuring Compare Unit 1 in EVA .........................................................................................................73
5.2.2 The Compare Control Register A (COMCONA) .........................................................................................75
5.2.3 The Compare Registers (CMPR1-6) ..........................................................................................................77
5.2.4 The Compare Action Control Registers (ACTRA and ACTRB) .....................................................................77
5.2.5 The Dead-band Timer Control Register A (DBTCONA) ..............................................................................78
5.2.6 PWM Initialization Routine ......................................................................................................................80
5.2.7 I/O Initialization .......................................................................................................................................83
5.2.8 Interrupt Service Routines .......................................................................................................................84
5.2.9 Compiling and executing .........................................................................................................................85
5.3 Using the EVA Capture Units ..........................................................................................................................88
5.3.1 Using the Capture Units for Rising/Falling edge detection in a new project .............................................90
5.3.2 Defining Structures for the Capture Unit Registers ..................................................................................91
5.3.3 EVA Interrupt Mask and Flag Registers B and C .......................................................................................98
5.3.4 Capture Control Register A and Capture FIFO Status Register A ............................................................. 100
5.3.5 Capture FIFO Registers .......................................................................................................................... 102
5.3.6 Initializing Capture Units 1 and 2 ........................................................................................................... 103
5.3.7 Core INT4 and Capture 1 and 2 Interrupt Service Routines .................................................................... 105
5.3.8 Configuring Capture I/O Pins 1 and 2 ..................................................................................................... 110
5.3.9 Executing the Program .......................................................................................................................... 111
5.4 Conclusions/Suggestions ..............................................................................................................................113

6. THE ANALOG TO DIGITAL CONVERTER .................................................................... 115


6.1 Overview of the Analog to Digital Converter ...............................................................................................115
6.1.1 The Sequencers ..................................................................................................................................... 115
6.2 Using the ADC in Cascaded Sequencer Mode ...............................................................................................117
6.2.1 Creating header and C files for the ADC Registers .................................................................................. 118
6.2.2 The ADC Control Register 1 (ADCTRL1) .................................................................................................. 121
6.2.3 The ADC Control Register 2 (ADCTRL2) .................................................................................................. 123
6.2.4 Autosequence Status Register (AUTO_SEQ_SR) ..................................................................................... 125
6.2.5 The Maximum Conversion Channels Register (MAXCONV) .................................................................... 126
6.2.6 The ADC Input Channel Select Sequencing Control Registers (CHSELSEQ n) ............................................ 127
6.2.7 ADC Conversion Result Buffer Registers (RESULTn) ................................................................................ 128
6.2.8 Initializing the ADC in Cascaded Sequencer Mode ................................................................................. 128
6.2.9 The ADC High Priority Interrupt Service Routine .................................................................................... 131
6.2.10 I/O initialization ................................................................................................................................... 133
6.2.11 The main() function ............................................................................................................................. 133
6.2.12 Executing the program ........................................................................................................................ 134

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

7. THE SERIAL COMMUNICATIONS INTERFACE .......................................................... 146


7.1 Overview of the Serial Communications Interface .......................................................................................146
7.2 A Program to Transmit and Receive Characters with the SCI .......................................................................147
7.2.1 Creating a new header file for SCI register structures ............................................................................ 147
7.2.2 The SCI Communication Control Register (SCICCR) ................................................................................ 150
7.2.3 The SCI Control Register 1 ..................................................................................................................... 151
7.2.4 The SCI Control Register 2 ..................................................................................................................... 153
7.2.5 The SCI Receiver Status Register ............................................................................................................ 153
7.2.6 The SCI Priority Register ........................................................................................................................ 154
7.2.7 Baud-Select Registers (SCIHBAUD SCILBAUD) ..................................................................................... 155
7.2.8 Receiver Buffer Register and Transmitter Buffer Register ...................................................................... 157
7.2.9 The main() function of project sci ....................................................................................................... 157
7.2.10 Initialization of Serial Communications (file DSP24_Uart.c) .............................................................. 158
7.2.11 I/O Configuration.................................................................................................................................162
7.2.12 Interrupt Service Routines ................................................................................................................... 162
7.2.13 Program Execution .............................................................................................................................. 164
7.3 Summary ......................................................................................................................................................166

8. THE SERIAL PERIPHERAL INTERFACE ...................................................................... 168


8.1 Overview of the Serial Peripheral Interface .................................................................................................168
8.2 A Program to Transmit characters with the SPI using the DSP as Master ....................................................169
8.2.1 Creating a new header file for the SPI registers ..................................................................................... 169
8.2.2 The SPI Configuration Control Register (SPICCR) .................................................................................... 172
8.2.3 The SPI Operation Control Register (SPICTL) .......................................................................................... 173
8.2.4 The SPI Status Register (SPISTS) ............................................................................................................. 176
8.2.5 The SPI Baud Rate Register (SPIBRR) ...................................................................................................... 177
8.2.6 The SPICLK signal in terms of the CLKOUT signal and the value in SPIBRR .............................................. 177
8.2.7 The SPI Priority Register (SPIPRI) ........................................................................................................... 179
8.2.8 The SPI Receive and Transmit Buffer Registers (SPIRXBUF and SPITXBUF) ............................................. 179
8.2.9 The SPI Emulation Buffer Register (SPIRXEMU) ...................................................................................... 179

8.2.10 Initialization of the SPI ......................................................................................................................... 180


8.2.11 Sending a character ............................................................................................................................. 182
8.2.12 I/O Configuration.................................................................................................................................182
8.2.13 The main() function ............................................................................................................................. 183
8.2.14 SPI Interrupt Service Routines ............................................................................................................. 184
8.2.15 Building and Executing ........................................................................................................................ 185
8.3 Summary/Conclusions .................................................................................................................................187

9. THE CONTROLLER AREA NETWORK (CAN) MODULE .......................................... 189


9.1 Overview of the CAN Bus Protocol ...............................................................................................................189
9.1.2 The CAN Physical Layer .......................................................................................................................... 189
9.1.3 The CAN lines (CANH and CANL) ............................................................................................................ 190
9.1.3 Exchanging messages through the CAN bus using Data and Remote Request Frames ........................... 191
9.1.4 Placing frames on the CAN bus .............................................................................................................. 194
9.1.5 The Bit Stuffing Rule .............................................................................................................................. 196
9.1.6 Error and Overload Frames.................................................................................................................... 196
9.1.7 States of a CAN node ............................................................................................................................. 196
9.1.8 Bit Timing and Synchronization ............................................................................................................. 199
9.2 Overview of the CAN Controller ...................................................................................................................200
9.2.1 CAN Mailboxes ...................................................................................................................................... 201
9.3 Using the CAN module to Transmit and Receive Data frames .....................................................................202
9.3.1 Creating a new header file for the CAN registers ................................................................................... 203
9.3.2 Message Identifier for High-Word Mailboxes 0-5 (MSGIDnH) ................................................................ 213
9.3.3 Message Identifier for Low-Word Mailboxes 0-5 (MSGIDnL) .................................................................214
9.3.4 Message Control Field (MSGCTRLn) ....................................................................................................... 214
9.3.5 The Local Acceptance Mask Register 0 and 1 High Word (LAM0_H and LAM1_H).................................. 214
9.3.6 The Local Acceptance Mask Register 0 and 1 Low Word (LAM0_L and LAM1_L) .................................... 215
9.3.7 Mailbox Buffers ..................................................................................................................................... 215
9.3.8 The Mailbox Direction/Enable Register (MDER) ..................................................................................... 216
9.3.9 The Transmit Control Register (TCR) ...................................................................................................... 217
9.3.10 The Receive Control Register ............................................................................................................... 218
9.3.11 The Master Control Register (MCR) ..................................................................................................... 219
9.3.12 The Bit Configuration Register 2 (BCR2) ............................................................................................... 221
9.3.13 The Bit Configuration Register 1 (BCR1) ............................................................................................... 221
9.3.14 The Error Status Register (ESR) ............................................................................................................ 223
9.3.15 The Global Status Register (GSR) ......................................................................................................... 225
9.3.16 The CAN Error Counter Register (CEC) .................................................................................................226
9.3.17 The CAN Interrupt Flag Register (CAN_IFR) .......................................................................................... 226
9.3.18 The CAN Interrupt Mask Register (CAN_IMR) ...................................................................................... 227
9.3.19 Initialization of the CAN module .......................................................................................................... 228
9.3.20 A Routine for Transmission .................................................................................................................. 234
9.3.21 I/O Configuration.................................................................................................................................235

xi

9.3.22 CAN Interrupt Service Routines ........................................................................................................... 235


9.3.23 The main() function ............................................................................................................................. 237
9.3.24 Building and Executing ........................................................................................................................ 238
9.3.25 Tracking the data frame on the transmission line ................................................................................ 239
9.4 Summary/Conclusions .................................................................................................................................242

10. THE DISCRETE FOURIER TRANSFORM ..................................................................... 244


10.1 Overview on Fourier Analysis .....................................................................................................................244
10.1.1 Complex Numbers as a Representation of Phase and Magnitude ........................................................ 244
10.1.2 Fourier Analysis ................................................................................................................................... 245
10.1.3 The Fourier Series ................................................................................................................................ 247
10.1.4 The Time-Continuous Fourier Transform ............................................................................................. 249
10.1.5 The Fourier series for Discrete-Time Signals (Discrete Fourier Transform) ........................................... 250
10.1.5 The DFT algorithm ............................................................................................................................... 251
10.2 A Program to perform signal Analysis using the simple DFT ......................................................................252
10.2.1 Modifying the Linker Command File .................................................................................................... 252
10.2.2 Initialization of the ADC ....................................................................................................................... 254
10.2.3 Initialization of Timer 1 for Pulse Width Modulation ........................................................................... 255
10.2.4 Initialization of the SPI ......................................................................................................................... 259
10.2.5 Global Data and DFT Routines ............................................................................................................. 261
10.2.6 The ADC Interrupt Service Routine ...................................................................................................... 263
10.2.7 I/O initialization ................................................................................................................................... 265
10.2.8 The main() function ............................................................................................................................. 265
10.2.9 Program Execution .............................................................................................................................. 266
10.3 The Fast Fourier Transform (FFT) ...............................................................................................................267
10.3.1 How the FFT works .............................................................................................................................. 268
10.3.2 Forward/Inverse FFT............................................................................................................................ 272
10.3.3 Adding FFT routines in the application.................................................................................................274
10.3.4 Signal Transposition Routine ............................................................................................................... 275
10.3.5 Routines for Forward/Inverse FFT Computations ................................................................................. 278
10.3.6 Modifying the main() function ............................................................................................................. 285
10.3.7 Program Execution .............................................................................................................................. 286
10.4 Conclusions/Suggestions ............................................................................................................................286

11. DIGITAL FILTERS ............................................................................................................. 289


11.1 Overview on Digital Filtering ......................................................................................................................289
11.1.1 Convolution ......................................................................................................................................... 289
11.1.2 Impulse, Frequency and Step Response of LTI Systems ........................................................................ 291
11.1.3 Implementation of Digital Filters ......................................................................................................... 293
11.1.4 Calculating the Output of a FIR filter .................................................................................................... 294

xii

11.1.5 Calculating the Output of an IIR filter .................................................................................................. 295


11.2 Implementing FIR filters .............................................................................................................................300
11.2.1 Moving Average Filters ........................................................................................................................ 301
11.2.2 Windowed-Sinc Low-Pass Filters.......................................................................................................... 302
11.2.3 Windowed-Sinc High-Pass Filters ......................................................................................................... 306
11.2.4 Windowed-Sinc Band-Pass Filters ........................................................................................................ 307
11.2.5 Peripheral Initialization........................................................................................................................ 309
11.2.6 Input shifting and Convolution ............................................................................................................ 312
11.2.7 Putting it all together .......................................................................................................................... 313
11.2.8 Interrupt Service Routines ................................................................................................................... 316
11.2.9 The main() function ............................................................................................................................. 317
11.2.10 Program execution ............................................................................................................................ 319
11.3 Implementing IIR filters ..............................................................................................................................326
11.3.1 Transforming Continuous Filters into Discrete Filters .......................................................................... 327
11.3.2 Designing a 2nd order Low-Pass Butterworth Filter .............................................................................. 330
11.3.3 Designing a 2nd order Butterworth High-Pass Filter .............................................................................. 332
11.3.4 Calculating the Output of the filter ...................................................................................................... 333
11.3.5 Putting it altogether ............................................................................................................................ 335
11.3.6 The main() function ............................................................................................................................. 338
11.3.7 Program Execution .............................................................................................................................. 339
11.4 Conclusions/Suggestions ............................................................................................................................343

12. TOPICS OF SPECIAL INTEREST .................................................................................... 345


12.1 Creating C-callable Assembly functions ......................................................................................................345
12.1.1 The Components of the C2xx CPU ....................................................................................................... 345
12.1.2 Assembly Language of the LF2407A ..................................................................................................... 348
12.1.3 Creating C-callable Assembly function Templates with TIs Code Composer Studio .......................... 351
12.1.4 A few Tips for your C-callable Assembly Template ............................................................................... 367
12.2 More about the Watchdog Timer ...............................................................................................................367
12.2.1 Overview of the Watchdog Timer ........................................................................................................ 368
12.2.2 Using the Watchdog in a Program ....................................................................................................... 369

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

Appendix B: Header and C files for the LF2407A ISRs ........................................................................392


Declarations of Interrupt Service Routines (DSP24_DefaultISR.h) ............................................................... 392
Implementations of Interrupt Service Routines (DSP24_DefaultISR.c)......................................................... 394

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

I would like to thank Julie Van Haren, Director of Communications Embedded


Processing, Texas Instruments, for her useful advises regarding the proper use of Texas
Instruments trademarks in literature.
I would also like to thank Manus and Jo McParland for devoting some of their time in
making sure that the text is devoid of unnecessary pretentious language and that it is
articulate and intelligible to the reader.

xix

xx

INTRODUCTION

Introduction

1.1 The TMS320LF/LC240xA series of DSP Controllers by Texas Instruments


The Texas Instruments TMS320LF/LC240xA digital signal processor controller is a nicely
wrapped package that includes a high-speed CPU core suitable for digital signal processing
applications, combined with the typical set of microcontroller peripherals in a single-chip
package (Figure 1-1). Performances of up to 40 million instructions per second (40 MIPS), is
one of the greatest assets of the TMS320LF/LC240xA when compared to traditional 16-bit
microcontrollers. The 240xA core uses 16-bit fixed point arithmetic with a wide variety of
instructions specifically suited to accommodate the necessary calculations required in digital
processing applications.
1.1.1 The TMS320LF2407A DSP Controller
TIs TMS320LF2407A, henceforth referred to as LF2407A or 2407A throughout this
book, is the classic representative of the 240xA series. The LF2407A is part of the C24x
generation and member of the C2000 platform of fixed point DSPs; the architectural
similarities of these processors make software highly portable between them, while controller
peripherals are practically identical in several aspects. Understanding the LF2407A is, in fact,
the key to unlocking the secrets of all other members of the C2000 platform and possibly,
many other DSP products by Texas Instruments. The broader TMS320 family includes the
C1x, C2x, C20x, C24x, C5x, C54x, and C6x generations of fixed-point DSPs; additionally, the C3x
and C4x floating-point DSPs; finally, the C8x multiprocessor DSPs. Devices within a generation
are identical in terms of CPU architecture, while they present slight variations in the
corresponding configurations of memory and peripherals.
The naming conventions applied in the C code examples throughout this book are
suited to follow the standards of C libraries of other DSP models in the C2000 platform (i.e.,
the TMS320F2812). You may be surprised to see how easily the code introduced in the next
chapters will apply to other DSP controllers (such as the TMS320F2812) with minor
differences, regardless of CPU architectural incompatibilities (e.g., 16-bit as opposed to 32bit).

INTRODUCTION

Figure 1-1. 240xA CPU Core and Peripherals single-chip package1.

TMS320LF/LC240xA DSP Controllers Reference Guide-System and Peripherals (Texas Instruments)

INTRODUCTION

1.1.2 Peripherals of the LF2407A Controller


The LF2407A combines the high-performance CPU core with a set of peripherals acting
as the heavy artillery to meet interfacing requirements for the most demanding of problems
in terms of digital signal processing, communications and general purpose I/O operations. The
set of peripherals on the LF2407A includes:
The Event Managers, incorporating Timers and PWM generators.
The Controller Area Network (CAN) Module.
The Analog to Digital Converter.
The Serial Peripheral Interface (SPI) for synchronous serial communications.
The Serial Communications Interface (SCI) - asynchronous serial port (universal
asynchronous receiver and transmitter UART).
The Watchdog timer.
General bi-directional digital I/O (GPIO) pins.
In the next chapters, each of the above peripherals will be introduced with simple examples
and several configurations will be discussed. In terms of pure DSP applications, the peripherals
commonly employed are the event managers and the ADC.
The event managers. These peripherals include a set of modules to facilitate creation
of pulse width modulated signals and capture rising/falling edges in pulses. In the heart of
the event managers, lie the general purpose timers, providing clocking to the modules of the
device; they may also be used to synchronize the occurrence of events in our programs. The
event managers are highly configurable to the last detail, with an extensive list of
configuration/control registers.
The CAN module. The controller area network module implements the multi-master
CAN bus communications protocol interface with a set of six mailboxes.
The Analog to Digital Converter. The ADC is used to sample analog signals and
produce the corresponding digital value stored in a 10-bit integer result. Arguably, it is one of
the most significant peripherals on the LF2407A. It utilizes two sequencers as finite state
machines that synchronize the sampling process.
The Serial Peripheral Interface. The SPI is used for synchronous master-slave high
speed serial communications. Typically, the SPI is used for communications with external
devices such as LCDs and Digital to Analog Converters.
The Serial Communications Interface. The SCI implements typical asynchronous serial
communications (UART). Typical applications of the SCI include communications with other
3

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.

1.2 Programming the LF2407A in C


Traditionally, the 2407A does not come with C header files regarding its set of
peripherals. Most of the existing code examples are developed in assembly. There are a great
number of reasons why a DSP should be programmed in assembly and all of them have to do
with performance in terms of execution time. However, using a high level language to initialize
the required controller devices in a program should not interfere with performance, but
rather only with the program size, which should not be a major issue these days.
The following chapters take the reader throughout all peripherals on the 2407A with a
few simple examples developed in C regarding each case. Since there are no libraries to work
with, the text will guide the reader through the process of creating a set of header files
involving the registers of the corresponding peripherals. It may be extra work, but it is
advantageous; the process of creating these files can be a nice exercise for memorizing and/or
highlighting the names of registers related to the initialization of every device on the DSP.
Moreover, the naming conventions for typical header files, registers and functions (interrupt
service routines and system initialization functions) are chosen so that they match the ones
used in the tidcs library provided by Texas Instruments for the TMS320F2812. Given that the
DSP controllers of the C2000 platform (and, possibly, ones that belong to other generations
and platforms) share most of their peripherals, you will find that your code can be easily
portable to other controllers with very few modifications. As mentioned earlier, the LF2407A
is the gateway to understanding a broader set of DSP products by Texas Instruments. The
overall gain is that in the end of the day, the reader should have a very good notion of what
kind of problems one may be faced with, regarding initialization and use of peripherals, not
4

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.

1.3 What you need in order to read this book


Reading through the first nine chapters does not require extended programming and/or
digital signal processing skills. However, a minimum acquaintance with C language and
computer architecture will be the prerequisites for the early chapters at least. Every new
concept comes with an example, following a short discussion on the issues presented in that
example. Readers who may have a certain experience in embedded programming will
probably have a head-start; the concepts introduced here, are somehow deviant from the
typical programming scheme in which, for example, a computer science student may be
accustomed to and it may take a while until he/she becomes fully adjusted. Finally, a certain
background on mathematics and control theory will be required for Chapters 10 and 11. It is
advisable to consult and cross-check every new concept with the technical manuals provided
by Texas Instruments and with the literature presented in the bibliography and sources
sections of this book.

INTRODUCTION

WRITING AND EXECUTING PROGRAM HELLO

Writing and Executing Program hello

2.1 Creating a first project with Code Composer Studio


We better quickly jump-start your interest with the 2407A with the old-fashioned
hello program. In fact, the programming approach involves the all times classic code
structure; we have a main() function, a few variables and a main loop. Sounds familiar? Start
Code Composer Studio IDE by Texas Instruments and create a new project.

Figure 2-1. Creating a new project.

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.

Figure 2-2. One step away from project hello.

WRITING AND EXECUTING PROGRAM HELLO

2.1.1 Creating the C file(s)


Like in any other C/C++ IDE, you will have to create your .c or .h files and thereafter,
add them to the project. Let us create a file named hmain.c from File New Source File. If
all went nicely, you should be able to work on a new editor window for the file you just
created. Type the following code:
#define
#define
#define
#define

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

= 0x00E8; // disable the watchdog

*MCRA &= 0xFFFC; // set Port A General Pins 0 and 1


// to General I/O function
*PADATDIR|=0x0303; // Port A0, A1 bits output and 'high'
/* main loop */
while (1) {
for(i=0;i<1000;i++); // delay loop
// store PADATDIR in temp
temp = *PADATDIR;
// store PADATDIR & 3 in temp1
temp1 = temp & 3;
if (temp1 ==0) temp |= 0x0003; // set bits A0, A1 = 1
else temp &= 0xFFFC; // set bits A0, A1 = 0
// copy temp to PADATDIR
*PADATDIR = temp;
}
}

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

WRITING AND EXECUTING PROGRAM HELLO

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 */

/* Sections declared by the user */


/* vectors:

>

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

WRITING AND EXECUTING PROGRAM HELLO

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.

Figure 2-3. Adding files to the 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

WRITING AND EXECUTING PROGRAM HELLO

11

REFINING PROGRAM HELLO

Refining program hello

3.1 Beginning of execution


Let us load our program again to the DSP. Following download, the instruction pointer
moves right at the beginning of the cinit section in program memory as shown in the
disassembly window in Figure 3-1.

Figure 3-1. Disassembly window after downloading hello.out.

Now, let us try something new. Go Debug Reset CPU and check the disassembly
window again (Figure 3-2).

Figure 3-2. The Disassembly Window after a CPU Reset.

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

REFINING PROGRAM HELLO

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

REFINING PROGRAM HELLO

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.

Figure 3-3. Project browser window following addition of cvectors1.asm.

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.

Figure 3-4. Execution suspension (break) following a reset.

30

REFINING PROGRAM HELLO

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!

3.2 Completing the cvectors.asm file


So far, we have ensured that the program will restart smoothly following a reset. But
this is not the only reason why we need to have a cvectors.asm file. In fact, cvectors.asm
should include the entire interrupt vector table with unconditional branches to all interrupt
service routines.
3.2.1 The LF2407A Core Interrupts
The 2407A is capable of six (6) maskable interrupts and several software (TRAPS) and
non-maskable interrupts (NMI). Practically, your code will be dealing with the six maskable
core interrupts (INT1-6), with the extreme exception of the occasional use of software
interrupts. The first 6 interrupts (except INT0 which is the reset interrupt vector) correspond
to the peripherals of the 2407A through a peripheral interrupt expansion controller (will be
discussed later), and it is important that the branching instructions in cvectors.asm are
pointing to the appropriate interrupt service routines (ISR) implemented in the C code.
Depending on the program specifications, you may need to implement less than six ISRs, but it
is a good policy to keep a set of 6 routine definitions in your code, so that you will not have to
modify the cvectors.asm every once in a while. Let us first conclude the cvectors1.asm file.
Open the editor and type the following:
.ref
.ref
.ref
.ref
.ref
.ref
.ref
rset:
int1:
int2:
int3:
int4:
int5:
int6:
int7:
int8:
int9:
int10:
int11:
int12:

.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

REFINING PROGRAM HELLO


int13:
int14:
int15:
int16:
int17:
int18:
int19:
int20:
int21:
int22:
int23:
int24:
int25:
int26:
int27:
int28:
int29:
int30:
int31:

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

REFINING PROGRAM HELLO

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

USING INTERRUPTS AND THE GENERAL PURPOSE TIMERS

Using Interrupts and the General Purpose Timers

4.1 A brief introduction to Interrupts of the 2407A


For those of you acquainted with event driven programming in Unix or other operating
systems, you surely realize the importance of handling asynchronous events in a program.
Think of interrupts as special events, normally triggered by external sources involving
peripherals. Depending on the case, you may choose to ignore these signals; however, in
other cases, you may choose to interrupt the sequential flow of execution and branch code
execution to a special function that handles the event that triggered the interrupt. The special
routines that handle interrupt signals are usually called interrupt handlers, but you will find
the term interrupt service routines (ISR) rather more commonly used. The 2407A is able to
sense numerous interrupt sources, mainly related to its peripherals.
4.1.1 The Peripheral Interrupt Expansion Controller (PIE)
The 2407A acknowledges interrupts in two levels. The core itself provides six maskable
interrupts (INT1-6). Technically, each of those interrupts may correspond to one specific
source. When programming interrupts for a PC, we know that there is a one-to-one mapping
from a peripheral interrupt source to a core interrupt in the CPU (i.e., the Intel x86 has 256
core interrupt vector table entries). Unfortunately, we do not have the luxury of using a
powerful Pentium on our DSP board. On the other hand, the DSP should be able to serve up
to 49 interrupt sources, most of which correspond to its peripherals. To overcome the
problem of having a great number of hardware interrupts (as opposed to the six available
maskable core interrupts) to be served by the CPU, these interrupts are organized in groups
or levels, each one corresponding to one of the six core maskable interrupts (INT1-6). This is
actually where the peripheral interrupt expansion controller (PIE) kicks-in. The PIE
intercepts interrupt signals from the various peripherals and consequently triggers the
appropriate core interrupt. It is as simple as that: Every maskable core interrupt in the 2407A,
is responsible for several interrupt sources. How is this happening? Better see this through
an example and fill in the details as we go.

46

USING INTERRUPTS AND THE GENERAL PURPOSE TIMERS

Figure 4-1. The Peripheral Interrupt Expansion scheme of the 2407A1.

4.2 Using a General Purpose Timer


The LF2407A is equipped with four general purpose timers (timer 1-4), all identical in
every aspect. For those already acquainted with embedded programming, it is common
knowledge that if you want your program to do business, you must always have at least one

TMS320LF/LC2407A DSP Controllers Reference Guide System and Peripherals (Texas Instruments)

47

USING INTERRUPTS AND THE GENERAL PURPOSE TIMERS

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

THE EVENT MANAGERS

The Event Managers

5.1 Overview on the Event Managers


As mentioned earlier, the 2407A is equipped with event managers A and B (EVA and
EVB). EVA and EVB are identical in every aspect; for simplicity reasons, we will be going
through the characteristics of EVA. EVA includes two general purpose timers (timer 1 and
timer 2), three compare units, three capture units and one quadrature encoder pulse (QEP)
circuit.

Figure 5-1. Block diagram of Event Manager A1.

TMS320LF/LC240xA DSP Controllers Reference Guide System and Peripherals (Texas Instruments)

64

THE EVENT MANAGERS

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.

5.1 Using Timer 1 for Pulse Width Modulation


Let us create a new project folder named t1pwm. Copy all source files from Timer1
folder into the new one, including the linker command file 2407_cmd.cmd and assembly file
cvectors.asm. Now, go to folder hello and copy files DSP24_Gpio.h and DSP24_Gpio.c
to your new folder (since we will be using an I/O pin, we should make sure that this particular
pin is configured for PWM operation with the appropriate I/O mux register defined in
DSP24_Gpio.h). Now, create a new project t1pwm. Add all files to your new project, and
dont forget to add rts2xx.lib after you finished.
65

THE EVENT MANAGERS

5.1.1 Expanding DSP24_Ev.h


Open DSP24_Ev.h. In order to use timer 1 to produce a PWM signal, we will have to
configure additional registers. Add the following structure definitions:
// General Purpose Timer CONtrol register A (GPTCONA)
struct GPTCONA_BITS {
unsigned int T1PIN:2;
// 0-1
Polarity of GP timer 1 compare
unsigned int T2PIN:2;
// 2-3
Polarity of GP timer 2 compare
unsigned int rsvd1:2;
// 4-5 Reserved
unsigned int TCOMPOE:1;
// 6 CoMPare Output Enable
unsigned int T1TOADC:2;
// 7-8 Start ADC with Timer 3
unsigned int T2TOADC:2;
// 9-10 Start ADC with Timer 4
unsigned int rsvd2:2;
// 11-12 Reserved
unsigned int T1STAT:1;
// 13 Timer 3 STATus
unsigned int T2STAT:1;
// 14 Timer 3 STATus
unsigned int rsvd3:1;
// 15 reserved
};
union GPTCONA_REG {
unsigned int
all;
struct GPTCONA_BITS bit;
};
extern volatile union GPTCONA_REG *GPTCONAbits;

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

THE EVENT MANAGERS

5.1.2 Modifying the Timer 1 Initialization function


We now need to modify initTimer1() function to configure the timer to produce a pulse
width modulated signal on pin T1PWM/T1CMP. Open DSP24_Timer1.c and modify the code
in initTimer1() as follows:
#include "DSP24_Ev.h"
#include "DSP24_Core.h"
void initTimer1(void) {
GPTCONAbits->bit.T1PIN=0x2; // T1CMP Compare output active high
GPTCONAbits->bit.T2PIN=00; // T2CMP Comp output forced low (not used)
GPTCONAbits->bit.TCOMPOE=1;
// Enable all GP Timer Compare outputs
GPTCONAbits->bit.T1TOADC=00; // Do not start ADC with Timer1
GPTCONAbits->bit.T2TOADC=00; // Do not start ADC with Timer2
*T1CNT=0;
*T1PR=30000;
*T1CMPR=15000;

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

Per. Match interrupt flag


Compare interrupt flag
UnderFlow interrupt flag
OverFlow interrupt flag
Period Match interrupt
Compare interrupt
UnderFlow interrupt
OverFlow interrupt

*IMR|=0x0002; //enable core level interrupt 2


T1CONbits->bit.TENABLE=1; // Enable the timer
}

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

THE EVENT MANAGERS

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.

Figure 5-2. Register GPTCONA bits2.

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 EVENT MANAGERS

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
}

A 1 is written to the appropriate bit-field of structure MCRAbits in order to configure pin


T1PWM/T1CMP/GPIOB4 as a timer 1 output (primary function). This is the first time we are
accessing MCRAbits from DSP24_Sys.c, therefore you should add an include statement right
at the beginning of the file:
#include "DSP24_Gpio.h"

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) {

Call to initIO() right after


System Initialization
// enable Interrupts

69

THE EVENT MANAGERS


}
}

Save all changes to your files and to the project. The project browser window should now look
like the one in Figure 5-3.

Figure 5-3. Project browser window for t1pwm.

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.

Figure 5-4. P2/P8 Header connections (T1PWM is 15 and GND is 40)3.

eZdsp LF2407A Technical Reference (Spectrum Digital)

70

THE EVENT MANAGERS

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

THE EVENT MANAGERS

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

THE EVENT MANAGERS

73

THE ANALOG TO DIGITAL CONVERTER

The Analog to Digital Converter

6.1 Overview of the Analog to Digital Converter


The analog to digital converter (ADC) along with EVA and EVB are, arguably, the most
important peripherals on all C2000 platform DSPs by Texas Instruments. The ADC of the 2407A
is a highly configurable 10-bit ADC with built-in sample-and-hold, two sequencers and 16
buffer registers to store the sampled results. The ADC can be triggered by the event managers,
software, or externally, with the ADC start-of-conversion (ADCSOC) pin. Configuration of the
ADC is rather extensive and we will get the opportunity to better acquaint ourselves with all
features of the peripheral throughout examples, rather than just enumerating them in this
section. However, it is important to gain a general insight into the principles of ADC operation
in the LF2407A.
6.1.1 The Sequencers
The ADC can sample 16 different channels, physically corresponding to pins ADC0ADC15 (non-multiplexed) located on a separate pin header on the DSP board. A conversion
run (session) involves a number of up to 16 samples, referred to as auto-conversions, from
some, or all of the ADC0-ADC15 pins, according to configuration. An auto-conversion
sequence is synchronized by two sequencers (SEQ1 and SEQ2) which can be thought of, as
finite state machines that arbitrate a maximum number of eight auto-conversions as a chain
of consecutive state changes. Although you do not need to be aware of the hardware specifics
of each sequencer, nevertheless, you need to be acquainted with the concepts of their
operation, since certain events related to their operation are tied to the ADC interrupt. The
sequencers can either operate in dual or cascaded mode. In dual mode, each sequencer
performs a number of sampling steps (auto-conversions) independently of the other; you
may think of it as having two distinct ADCs working as totally independent entities. In
cascaded mode, sequencers are joined to form a single 16-state sequencer and therefore,
performing a number of auto-conversions as a single ADC. Apparently, depending on
whether we operate the ADC in dual sequencer mode (therefore, we have two pseudo-ADCs
sampling a maximum of 8 channels each) or cascaded mode (unique ADC sampling a
maximum of 16 channels) the way we handle the ADC interrupts should be distinctively
different. Figures 6-1 and 6-2 show the block diagrams of the ADC in dual and cascaded
sequencer mode respectively.
115

THE ANALOG TO DIGITAL CONVERTER

Figure 6-1. ADC Block Diagram with Dual Sequencers1.

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

THE ANALOG TO DIGITAL CONVERTER

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.

6.2 Using the ADC in Cascaded Sequencer Mode


An example can take us through all the necessary steps to configure and operate the
ADC in cascaded sequencer mode. Create a folder ADC-CS and copy files DSP24_Core.h,
DSP24_Core.c, DSP24_Gpio.h, DSP24_Gpio.c, DSP24_Sys.c, 2407_cmd.cmd,
DSP24_DefaultISR.h, DSP24_DefaultISR.c and cvectors.asm into it. Now, create a new
project named ADC-CS and add the files to it. Lastly, dont forget to add file rts2xx.lib to
2

TMS320LF/LC240xA DSP Controllers Reference Guide System and Peripherals (Texas Instruments)

117

THE ANALOG TO DIGITAL CONVERTER

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
};

ADC Control Register 2


structure definition

{
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

THE ANALOG TO DIGITAL CONVERTER

union ADCTRL2_REG {
unsigned int all;
struct ADCTRL2_BITS
};

bit;

Autosequence Status Register


structure definition

extern volatile union ADCTRL2_REG *ADCTRL2bits;


// AUTO_SEQ_SR
struct AUTO_SEQ_SR_BITS {
unsigned int SEQ1STATE:3; // 0-3 SEQ1 state (only in dual mode)
unsigned int SEQ2STATE:2; //4-6 SEQ2 state (only in dual mode)
unsigned int rsvd2:1;
unsigned int SEQCNTR:4; // 8-11 Sequencing counter status bits
unsigned int rsvd1:4;
//12-15 reserved
};
union AUTO_SEQ_SR_REG {
unsigned int all;
struct AUTO_SEQ_SR_BITS bit;
};
extern volatile union AUTO_SEQ_SR_REG *AUTO_SEQ_SRbits;
// CHSELSEQ1
struct CHSELSEQ1_BITS {
unsigned int CONV00:4;
unsigned int CONV01:4;
unsigned int CONV02:4;
unsigned int CONV03:4;
};
union CHSELSEQ1_REG{
unsigned int all;
struct CHSELSEQ1_BITS bit;
};
extern volatile union CHSELSEQ1_REG *CHSELSEQ1bits;
//CHSELSEQ2
struct CHSELSEQ2_BITS {
unsigned int CONV04:4;
unsigned int CONV05:4;
unsigned int CONV06:4;
unsigned int CONV07:4;
};
union CHSELSEQ2_REG{
unsigned int all;
struct CHSELSEQ2_BITS
};

bit;

extern volatile union CHSELSEQ2_REG *CHSELSEQ2bits;

119

THE ANALOG TO DIGITAL CONVERTER


//CHSELSEQ3
struct CHSELSEQ3_BITS {
unsigned int CONV08:4;
unsigned int CONV09:4;
unsigned int CONV10:4;
unsigned int CONV11:4;
};
union CHSELSEQ3_REG{
unsigned int all;
struct CHSELSEQ3_BITS bit;
};
extern volatile union CHSELSEQ3_REG *CHSELSEQ3bits;
//CHSELSEQ4
struct CHSELSEQ4_BITS {
unsigned int CONV12:4;
unsigned int CONV13:4;
unsigned int CONV14:4;
unsigned int CONV15:4;
};
union CHSELSEQ4_REG {
unsigned int all;
struct CHSELSEQ4_BITS bit;
};
extern volatile union CHSELSEQ4_REG *CHSELSEQ4bits;
// MAXCONV
extern volatile unsigned int *MAXCONV;
// RESULT REGISTERS (access i-th register as: *(RESULT+i), i=0,...,15)
extern volatile unsigned int *RESULT;
// CALIBRATION REGISTER
extern volatile unsigned int *ADCCAL;
#endif

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

THE ANALOG TO DIGITAL CONVERTER

volatile union CHSELSEQ3_REG *CHSELSEQ3bits = (void*)0x70A5;


volatile union CHSELSEQ4_REG *CHSELSEQ4bits = (void*)0x70A6;
// Single word pointers
volatile unsigned int *MAXCONV = (void*)0x70A2;
volatile unsigned int *RESULT = (void*)0x70A8;
volatile unsigned int *ADCCAL = (void*)0x70B8;

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).

Figure 6-3. The ADC Control Register 13.

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

THE ANALOG TO DIGITAL CONVERTER

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

THE ANALOG TO DIGITAL CONVERTER

the TMS320LF/LC240xA Controllers Reference Guide System and Peripherals); therefore,


by adjusting the ACQPS bits, we may adjust the impedance of the ADC. The length of an
acquisition window can be calculated by
. The overall length of an
auto-conversion should be equal to the S/H window length, added to the sampling time
(TSAMPLE = 11TCLK ):

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

THE SERIAL COMMUNICATIONS INTERFACE

The Serial Communications Interface

7.1 Overview of the Serial Communications Interface


The 2407A implements serial communications with the SCI module. The SCI supports
asynchronous serial communications with other peripherals or controllers. It is typically
configured for a specific baud rate, number of data bits, 1 or 2 stop bits, even/odd/no parity,
and handshaking/no handshaking, using separate transmit and receive buffer registers.
Additionally, the SCI offers two multiprocessor communication modes for multiple addressable
devices throughout a single transmit line using addressing bytes. Figure 7-1 illustrates the
block diagram of the SCI.

Figure 7-1. Block Diagram of the Serial Communications Interface1.

TMS320LF/LC240xA DSP Controllers Reference Guide System and Peripherals (Texas Instruments)

146

THE SERIAL COMMUNICATIONS INTERFACE

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.

7.2 A Program to Transmit and Receive Characters with the SCI


An example is always the best way to start digging deeper into the details of
configuring and using a peripheral. Create a new folder named sci and new project with
same name in the new folder. Copy files 2407_cmd.cmd, cvectors.asm, DSP24_Gpio.h,
DSP24_Gpio.c, DSP24_Core.h, DSP24_Core.c , DSP24_DefaultISR.h,
DSP24_DefaultISR.c and DSP24_Sys.c from your previous project to the new folder.
7.2.1 Creating a new header file for SCI register structures
Unfortunately, we must now create all the data structures for the SCI registers in order
to use them. You should not be too much frustrated though. Fortunately, the SCI does not
involve a large number of registers if you compare it to the event managers. Also, youll be
delighted to know that all SCI registers are 8-bit long. Create a new file named DSP24_Sci.h
and type the following:
#ifndef DSP24_SCI_H
#define DSP24_SCI_H
// Communication control register (SCICCR)
struct SCICCR_BITS {
unsigned int SCICHAR:3;
// 0-2 Character length (11 for 8 bits)
unsigned int ADDRIDLE_MODE:1;// 3 ADDR/IDLE Mode

147

THE SERIAL COMMUNICATIONS INTERFACE


unsigned
unsigned
unsigned
unsigned

int
int
int
int

LOOPBKENA:1;
PARITYENA:1;
PARITY:1;
STOPBITS:1;

//
//
//
//

4
5
6
7

Loop Back enable


Parity enable
Even-1 or Odd-0 Parity (if enabled)
Number of Stop Bits

};
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

THE SERIAL COMMUNICATIONS INTERFACE

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

baud-select reg, high byte


baud-select reg, low byte
emulation data buffer register
receiver data buffer register
transmit data buffer register

#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

THE SERIAL COMMUNICATIONS INTERFACE


volatile unsigned int* SCIRXEMU=(void*)0x7056;
// SCI receiver data buffer register
volatile unsigned int* SCIRXBUF=(void*)0x7057;
// SCI transmit data buffer register
volatile unsigned int* SCITXBUF=(void*)0x7059;

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

THE SERIAL PERIPHERAL INTERFACE

The Serial Peripheral Interface

8.1 Overview of the Serial Peripheral Interface


The SPI is yet another serial interface on the LF2407A providing synchronous
communications as opposed to the asynchronous operation of the SCI. Communications with
the SPI require some sort of arbitration between communicating parties, a role which either
device can play. Specifically, the device that synchronizes the operation is called the master
and it provides a clocking signal synchronizing data transmission; consequently, the other
device is called slave.

Figure 8-1. Serial Peripheral Interface block diagram1.

TMS320LF/LC240xA DSP Controllers Reference Guide System and Peripherals (Texas Instruments)

168

THE SERIAL PERIPHERAL INTERFACE

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

THE SERIAL PERIPHERAL INTERFACE

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

THE SERIAL PERIPHERAL INTERFACE


struct SPIBRR_BITS bit;
};
extern volatile union SPIBRR_REG *SPIBRRbits;
// SPI Baud register as a word
extern volatile unsigned int *SPIBRR;
// SPI Priority Control Register (SPIPRI)
struct SPIPRI_BITS {
unsigned int rsvd1:4;
//0-3 reserved
unsigned int SPIFREE:1; // 4 SPI suspension free bit
unsigned int SPISOFT:1; // 5 SPI suspension soft bit
unsigned int SPIPRI:1; // 6 SPI interrupt priority (0 high, 1 low)
unsigned int rsvd2:1;
// 7 reserved
};
union SPIPRI_REG {
unsigned int all;
struct SPIPRI_BITS bit;
};
extern volatile union SPIPRI_REG *SPIPRIbits;
// SPI Transmit and Receive Buffer Registers (SPITXBUF and SPIRXBUF)
extern volatile unsigned int* SPITXBUF;
extern volatile unsigned int* SPIRXBUF;
#endif

// 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 SERIAL PERIPHERAL INTERFACE

8.2.2 The SPI Configuration Control Register (SPICCR)


The SPI configuration control register configures the operation of the SPI in terms of
clock polarity-phase and character length. It also includes a reset bit that clears flags and
enables/disables transmission.

Figure 8-2. The SPI Configuration Control Register2.

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

THE SERIAL PERIPHERAL INTERFACE

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

THE CONTROLLER AREA NETWORK MODULE

The Controller Area Network (CAN) Module

9.1 Overview of the CAN Bus Protocol


The controller area network, usually referred to as CAN or CAN bus protocol, is a simple
broadcast protocol over a common channel (bus) shared by all connected nodes in the
network (Figure 9-1). The CAN was originally designed for applications in the automotive
industry as the means to accommodate information exchange between the microcontrollers
installed in various locations on a car. Imagine that all these indications that you see (along
with some that you dont) on the dash board of your car are, in fact, remote sensors (engine,
wheels, chassis, etc.) connected to microcontrollers which communicate with another
microcontroller installed locally, responsible for displaying these indications on the board. The
CAN is designed to accommodate the fast and reliable (in terms of electromagnetic
interference) transmission of relatively short pieces of information (a few bytes), also known
as CAN data frames, between embedded platforms located several meters apart from each
other.

Figure 9-1. Generic layout of a CAN bus with n-nodes.

9.1.2 The CAN Physical Layer


In terms of physical connections, the CAN bus is nothing but two wires, namely, CAN
High (CANH) and CAN Low (CANL), connected to each node through a buffering circuit known
as a CAN transceiver (Figure 9-3). Each node uses two separate lines for serial transmission
(Tx) and reception (Rx) which cannot be directly connected to the CAN bus lines; instead, the
189

THE CONTROLLER AREA NETWORK MODULE

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

THE CONTROLLER AREA NETWORK MODULE

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

ISO1050 ISOLATED CAN TRANSCEIVER (Texas Instruments)

191

THE CONTROLLER AREA NETWORK MODULE

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.

Figure 9-4. Structure of a CAN frame.

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.

Figure 9-5a. Standard CAN frame arbitration field structure.

192

THE CONTROLLER AREA NETWORK MODULE

Figure 9-5b. Extended CAN frame arbitration field structure.

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.

Figure 9-6. CAN frame control field structure.

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.

Figure 9-7. CAN frame CRC field structure.

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

THE CONTROLLER AREA NETWORK MODULE

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.

Figure 9-8. CAN frame ACK field structure.

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.

Figure 9-9. Interframe Space structure.

9.1.4 Placing frames on the CAN bus


A CAN node wishing to place a frame on the bus has to wait for a sufficient amount of
recessive bits (at least 3) after which, the bus is said to be in idle state. This way, the node
ensures that transmission will not commence while some other node is still transmitting a
frame. As soon as the bus is idle, the node begins transmission of the SOF bit followed by the
frames ID. It is likely that several other nodes will decide on placing their data on the bus as
well, by transmitting their SOF and ID. This is a situation in which there can be only one left.

194

THE CONTROLLER AREA NETWORK MODULE

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

THE CONTROLLER AREA NETWORK MODULE

9.1.5 The Bit Stuffing Rule


The CAN protocol allows only up to five consecutive bits of the same value on the bus.
This means that, if, for example, a data field contains five consecutive 0s, the transmitter
will have to stuff an additional bit complementary to the previous five (i.e., a 1). This is
happening because during the transmission of 0s, nodes may lose synchronization and
therefore, take advantage of the change in the state of the bus (i.e., 0 to 1) as a milestone
based on which they may re-synchronize. Figure 9-11 illustrates examples of bit stuffing for
five consecutive bits of the same polarity.

Figure 9-11. Bit stuffing after five consecutive dominant bits.

9.1.6 Error and Overload Frames


The CAN protocol involves two other types of frames, not used for data exchange, but
rather as error signals on the bus. Specifically, the protocol also includes error frames and
overload frames.
Error frames are created following an error in a node and can be either active or
passive. In the case of an error, any node can force unnatural situations to occur on the bus
(such as 6 consecutive dominant bits, or 6 consecutive recessive bits breaking the bit stuffing
rule), perceived as errors by all nodes. Error frames are visible only in the transfer layer (and
therefore handled solely by the CAN controller), but they will affect flags and may even cause
an interrupt which you may have to deal with, given the specifics of the application at hand.
Overload frames are used to provide delays between succeeding or preceding data
frames or remote requests. Much like in error frames, they cause situations incompatible to
the bit stuffing rule, thus forcing the nodes to respond accordingly. Simply put, overload
frames can be used by any node to delay the others from placing data frames or remote
requests on the bus.

196

THE DISCRETE FOURIER TRANSFORM

10

The Discrete Fourier Transform

10.1 Overview on Fourier Analysis


The destiny of a DSP predominantly involves the manipulation of signals. Essentially, a
signal can be any real function of time. However, engineers always wish to expand this
perspective by looking at signals from different angles as well. The overall theory behind this
approach is extensive, with plenty of equations involving both real and complex numbers. On
the other hand, the actual applications implement several tedious or less-tedious, in terms of
development, algorithms based on these equations. One may think of the math as the
mountain-top view on signals and the corresponding algorithms as a rather narrow, yet very
clear and specific picture. In order to implement algorithms, you should first consult the math,
while the algorithms can give you a great insight into what the math tells you.
10.1.1 Complex Numbers as a Representation of Phase and Magnitude
Complex numbers are prevalent in signal theory. Although you do not have to be well
acquainted with their properties, understanding the essence of their symbolic representation
is quite significant. From the point of view of mathematicians, the set of complex numbers is
an expansion of the set of real numbers to include a special number, sometimes called the
imaginary radical, such as that, when raised to the power of 2, the result is -1 (i.e., j2 = -1). A
complex number can also be seen as a vector of certain length (absolute value) and angle
(argument) from the real axis as shown in Figure 10-1.
However, from the point of view of engineers, a complex number is a representation
of a cosine wave in terms of its phase and magnitude. Specifically, the absolute value of the
complex number corresponds to the magnitude and the argument, to the phase. Take for
example, function f(t) = 5cos(2t+/4) with =2 and magnitude 5. The corresponding
complex number Zf should then be:

Sometimes, the phasor notation is used instead of the polar form:

244

THE DISCRETE FOURIER TRANSFORM

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.

Regardless of notation, complex numbers hold properties essential to the computations


required in dealing with signals in terms of their phase and magnitude. A certain level of
familiarity with their attributes would help gaining a better insight into the contents of the
following sections.
10.1.2 Fourier Analysis
Fourier analysis is a set of techniques aiming at decomposing a signal into cosine
waves. Jean Baptist Joseph Fourier (1768-1830) presented a paper in 1807, based on which,
every periodic function can be written as the summation of cosines of specifically chosen
magnitudes and frequencies. In fact, to extend Fouriers claim, every signal can be
approximated by a series of cosines, if the decomposition is performed on bounded time
intervals. There are very specific exceptions to this rule, but they exist only in the minds of
mathematicians and therefore, do not concern engineers.
The fundamental aspects of Fourier analysis involve basically two distinct notions
regarding the form that a signal may assume: The time domain signal and the frequency
245

THE DISCRETE FOURIER TRANSFORM

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 DISCRETE FOURIER TRANSFORM

10.1.3 The Fourier Series


Assume that you wish to approximate a periodic function f(t) with an infinite or finite
series of cosines. Also, assume that you wish to use 0 as fundamental frequency and
therefore, the cosine components will have frequencies 1=0, 2=20, ..., =0, .. . Then, if
is the approximation of f, it can be calculated by the following series:

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

THE DISCRETE FOURIER TRANSFORM

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:

then, the corresponding frequency domain value for 00 = 0 would be 3:

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

THE DISCRETE FOURIER TRANSFORM

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

THE DISCRETE FOURIER TRANSFORM

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:

In practice, the continuous-time Fourier transform does not correspond to an


algorithm that can be implemented inside a computer program. However, you may think of it
as a mathematical tool which can give us a peek at the fully continuous frequency domain of a
function and enable us to cross-check our results when calculating the Fourier coefficients.
10.1.5 The Fourier series for Discrete-Time Signals (Discrete Fourier Transform)
Signals are continuous functions of time and potentially infinitely long, but we can only
store a finite number of discrete-time sampled values in the memory of the DSP at a time.
Under these conditions, the techniques for the computation of the Fourier coefficients do not
apply exactly as stated in the previous section; however, the overall principle remains the
same.
If we wish to obtain the frequency domain of a discrete-time signal of finite length,
then the discrete Fourier transform (DFT) is the mathematical technique that should be
employed. The DFT computes the time domain of a signal using a finite number of sampled
values for the analysis. Specifically, let N be an even number of samples x*0+, , x*N-1], then
the time domain signal X=[a0 a1 aN-1] can be calculated as follows:

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

THE DISCRETE FOURIER TRANSFORM

10.1.5 The DFT algorithm


The DFT algorithm uses N time domain values, where N is usually chosen to be a power
of 2 (but can also be any even number), to compute the corresponding N frequency domain
values. The DFT algorithm is relatively easy to implement and involves the following sums for
the analysis (forward DFT):

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 DISCRETE FOURIER TRANSFORM

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

11.1 Overview on Digital Filtering


Filtering is the most common problem encountered in signal processing. In a sense,
DSP is all about distinguishing the interesting features of a signal in any given form. Towards
that specific end, there are several fundamental concepts and mathematical operations which
will always be present and/or required in the design of the appropriate filter. As shown in
Chapter 10, mathematics can provide the key to optimizing the implementation of a DSP
algorithm; therefore, a certain degree of insight into the properties of filters as linear time
invariant (LTI) systems would be most helpful.
11.1.1 Convolution
Convolution is a mathematical operation defined for continuous and discrete
functions. In DSP, it goes without saying that we are exclusively interested in the discrete form
of the operation.
Think of two sequences, let x[] and h[]. The convolution of x and h can then be defined
as a new sequence, y = x*h, according to the following sum:

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

The rest of the values of y are zero for


or
. The values of interest are the sums
containing valid indexes for at least one of h[i] and x[i]. The result is always of length N+M-1
(i.e., 3+2+1 = 6). This is a little bit of a mind twister! Fortunately, there is a better way of
looking at these computations.
Think of x and h as two vectors contrarily indexed, that slide over each other. In
particular, consider h as being stationary, and x sliding to the right over it, as shown in
Figure 11-1. Each time x shifts by one position to the right, we may calculate the convolved
result as the weighted sum of the components of x multiplied by the corresponding
components of h.

Figure 11-1. Convolution calculations as x shifts over h.

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.

Figure 11-2. Input-output relation in an LTI discrete system.

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

An impulse is a nice way of expressing a disturbance, or abrupt, momentary change in


mathematical terms. Hence, the impulse response describes the reaction of the system to
a sudden change in the input. The transform of an impulse is 1 (i.e.,
) and
therefore, we may obtain the following regarding the impulse response:

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

11.1.4 Calculating the Output of a FIR filter


Equation (11.9) is practically a convolution between a kernel of length M+1, specified
by coefficients bk and the sampled input sequence x[n-k]. Therefore, FIR calculations are
always being carried out with a convolution. In this operation, the kernel is finite, but the
input is potentially infinite, since there is no limitation about the number of samples. To
implement convolution of an FIR, we usually keep a rolling buffer of sampled values with size
equal to the size of the kernel and the output is calculated as the weighted sum of the
coefficients with the input values in the buffer. Every new sample is stored in the leftmost
position in the input buffer, while the rest of the values shift by one position to the right upon
the arrival of a new input. The input buffer should initially contain zeros. Figure 11-3 illustrates
calculations.

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

Figure 11-4. Length M+1 direct-form flow-graph of an FIR filter.

11.1.5 Calculating the Output of an IIR filter


Calculating the output of IIR filters is a more-less similar process to the one used in FIR
filters. The essential difference lies with the fact that we need to keep an extra storage space
for previous outputs. If we set a0 = 0 (current output is not included in the sum of previous
outputs) in equation (11.8), the output of a recursive filter becomes:

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

Figure 11-6. IIR filter direct-form I flow-graph.

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

For N > M, equation (11.11) becomes:

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):

Following multiplications, we get:

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:

We may now express the output in terms of d[n]:

We are finished! What we have just achieved, is to express everything in terms of


d[n]! This means that, instead of keeping two rolling buffers in memory, we can actually
keep only one of size N, containing the values of d[n]! The output can always be calculated
using equation (11.17), based on the values contained in the buffer of d[n] and the current
input only. This is the DSP way.
I am sure that most people, including me, would like to forget the calculations that led
to equations (11.16) and (11.18). So, here is all you need to keep in your pocket when
implementing the calculations for an IIR filer with N>M:

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

TOPICS OF SPECIAL INTEREST

12

Topics of Special Interest

12.1 Creating C-callable Assembly functions


Although it may sound extremely unordinary, TIs TMS320LC/LF240xA DSP series are
known to be programmed mostly in assembly, rather than in C. In fact, the majority of the
relative code snippets widely available on the internet and existing literature are implemented
in assembly. To generalize this statement, If you ever speak to the gurus and professionals
of digital signal processing, you will realize that, majority concurs, that the tool of preference
in terms of development, regardless of DSP embedded platform, is assembly; and they could
justify this obsession with a few, but very good reasons.
The prominent argument for the use of assembly in DSP is obviously execution time.
Imagine how great it would be, if we could only reduce the execution time of a convolution or
a fast Fourier transform to its half or even less! It would certainly allow us to use higher
sampling rates and therefore, process the signal at significantly higher levels of detail.
Moreover, assembly code is more compact than compiler-generated code and could reduce
the overall program size, which could also be an advantage in terms of saving program
memory, but this is not generally an issue these days.
The truth is, that programming the DSP in C will sometimes get you to where you are
intending to go, and this is perfectly acceptable. However, once you get your hands really dirty
on the LF2407A (including any other DSP by TI) you will realize that there are built-in abilities
which could lead to much faster solutions tailored for very demanding problems and it is a real
shame to let them pass unexploited. This does not necessarily mean that you should quit C
and switch to assembly! There are nice ways to combine the fast assembly routines with your
C code, so that you may be able to develop your program quickly and, in the same time,
incorporate all those special abilities provided by the CPU of the LF2407A.
12.1.1 The Components of the C2xx CPU
The C2xx CPU contains the following:
A 32-bit central arithmetic logic unit (CALU).
A 32-bit accumulator.
Input and output data-scaling shifters for the CALU.
A 16-bit x 16-bit multiplier.
345

TOPICS OF SPECIAL INTEREST

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).

Figure 12-1. The LF2407A core registers during debugging.

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

TOPICS OF SPECIAL INTEREST

Figure 12-2a. Status Register ST01.

Figure 12-2b. Status Register ST11.

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

TOPICS OF SPECIAL INTEREST

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

Texas Instruments, 2006. TMS320LF/LC240xA DSP Controllers Reference Guide - System


and Peripherals. [online] Dallas, Texas: Texas Instruments Incorporated. Available at:
<http://focus.ti.com.cn/cn/lit/ug/spru357c/spru357c.pdf> [Accessed 26 October 2009].
Texas Instruments, 1999. TMS320LF/LC240xA DSP Controllers Reference Guide CPU
and Instruction Set. [online] Dallas, Texas: Texas Instruments Incorporated. Available at:
<http://focus.ti.com/lit/ug/spru160c/spru160c.pdf> [Accessed 10 November 2009].
Texas Instruments, 2003.TMS320LF2407, TMS320LF2406, TMS320LF2402 DSP
Controllers. [online] Dallas, Texas: Texas Instruments Incorporated. Available at:
<http://focus.ti.com/lit/ds/sprs094i/sprs094i.pdf> [Accessed 21 January 2010].
Anderson, T., 2001.An Easy Way of Creating a C-callable Assembly Function for the
TMS320F28x DSP. [online] Dallas, Texas: Texas Instruments Incorporated. Available at:
<http://focus.ti.com/lit/an/spra806/spra806.pdf> [Accessed 18 October 2009].
Brenman, L., 1995.Setting Up TMS320 Interrupts in C. [online] Dallas, Texas: Texas
Instruments Incorporated. Available at: <http://focus.ti.com/lit/an/spra036/spra036.pdf>
[Accessed 6 December 2009].
Alter, D. A., 2002. Getting Started in C and Assembly Code with the TMS320LF24x DSP.
[online] Dallas, Texas: Texas Instruments Incorporated. Available at:
<http://focus.ti.com.cn/cn/lit/an/spra755a/spra755a.pdf> [Accessed 6 October 2009].
Spectrum Digital, 2003.eZdsp LF2407A Technical Reference. [online] Stafford, Texas:
Spectrum Digital Incorporated. Available at:
<http://c2000.spectrumdigital.com/ezlf2407a/docs/ezlf2407a_techref.pdf> [Accessed 10
October 2009].
Texas Instruments, 2000.TLC5615, TLC5615I 10-Bit Digital to Analog Converters.
[online] Dallas, Texas: Texas Instruments Incorporated. Available at:
<http://www.datasheetcatalog.org/datasheet/texasinstruments/tlc5615.pdf> [Accessed 10
December 2010].

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

Вам также может понравиться