Introduction to C Programming with the ...

3 downloads 0 Views 3MB Size Report
9.1.5 The Bit Stuffing Rule . .... 9.3.12 The Bit Configuration Register 2 (BCR2) . ...... During that period, I came across the F2812's 16-bit fixed- point counterpart ...
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.

v

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

x

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 TI’s 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 F2812’s 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 one’s “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 [email protected] 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

1

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 TI’s 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).

1

INTRODUCTION

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

1

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

2

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.

5

INTRODUCTION

6

WRITING AND EXECUTING PROGRAM “HELLO”

2

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

7

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 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 project’s 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”

3

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 program’s 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. Don’t 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 TI’s 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

4

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

1

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

5

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.

1

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 don’t 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.

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

There’s 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 timer’s 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

6

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, don’t 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 (“1”enabled, “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

0

0

VREFLO

0

1

VREFHI

1

0

1

1

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 sequencer’s 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 application’s 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

7

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.

1

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, you’ll 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! There’s nothing more to add! It is now time to go through the details of each one of those registers.

150

THE SERIAL PERIPHERAL INTERFACE

8

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.

1

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 It’s 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, don’t 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

2

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

9

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 don’t) 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 TI’s 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 shouldn’t 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 frame’s 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 “0”s, 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 “0”s, 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(2πt+π/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

Euler’s 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 Fourier’s 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=2ω0, ..., ωκ=κω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 kω0. 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 2ω0, 3ω0, ..., κω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 kω0 and - kω0. The “Negative” frequency –kω0 corresponds to the same harmonic component (cosine) with kω0. 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 0ω0 = 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 , kω0; 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 shouldn’t keep us worried throughout this text. The frequency domain function F(kω0) = ακ 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 system’s 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 system’s 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 system’s 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 output’s 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 system’s input, C is the output matrix and Y[n] is the system’s 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 system’s 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, TI’s 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 Engineer’s 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: [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: [Accessed 10 November 2009]. Texas Instruments, 2003.TMS320LF2407, TMS320LF2406, TMS320LF2402 DSP Controllers. [online] Dallas, Texas: Texas Instruments Incorporated. Available at: [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: [Accessed 18 October 2009]. Brenman, L., 1995.Setting Up TMS320 Interrupts in C. [online] Dallas, Texas: Texas Instruments Incorporated. Available at: [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: [Accessed 6 October 2009]. Spectrum Digital, 2003.eZdsp™ LF2407A – Technical Reference. [online] Stafford, Texas: Spectrum Digital Incorporated. Available at: [Accessed 10 October 2009]. Texas Instruments, 2000.TLC5615, TLC5615I 10-Bit Digital to Analog Converters. [online] Dallas, Texas: Texas Instruments Incorporated. Available at: [Accessed 10 December 2010].

375

Texas Instruments, 2010. ISO1050 Isolated CAN Transceiver. [online] Dallas, Texas: Texas Instruments Incorporated. Available at: [Accessed 5 December 2010]. CAN in Automation, 2010.CAN Protocol Specification. [online] Nuremberg: CAN in Automation. Available at: [Accessed 27 November 2010]. Softing AG, 2010.CAN bus (Controller Area Network), an overview. [online] Softing AG. Available at: [Accessed 27 November 2010]. Bosch, R., 1991.CAN Specification. [online] Stuttgart: Bosch. Available at: [Accessed 29 November 2010]. Wikipedia, 2010. Cooley-Tukey FFT Algorithm. [online] Wikipedia. Available at: [Accessed 27 November 2010]. Jones, D., 2004. FIR Filter Structures. [online] Connexions. Available at: [Accessed 2 December 2010]. Jones, D., 2004. IIR Filter Structures. [online] Connexions. Available at: [Accessed 17 December 2010]. Vandevenne, L., 2007.Lode’s Computer Graphics Tutorial – Fourier Transform. [online] Lode Vandevenne. Available at: [Accessed 2 December 2010]. Bores, C., 2010. Introduction to DSP – IIR Filters. [online] Woking, Surrey: Bores Signal Processing. Available at: [Accessed 2 December 2010]. Wikipedia. Butterworth Filter. [online] Wikipedia. Available at: [Accessed 21 December 2010].

376