TMS320C28x™ DSP Workshop: Student Guide
TMS320C28x™ DSP Workshop: Student Guide
C28xmdw
Revision 6.22
February 2007
Technical Training
Organization
Important Notice
Important Notice
Texas Instruments and its subsidiaries (TI) reserve the right to make changes to their products or to
discontinue any product or service without notice, and advise customers to obtain the latest version of
relevant information to verify, before placing orders, that information being relied on is current and
complete. All products are sold subject to the terms and conditions of sale supplied at the time of order
acknowledgment, including those pertaining to warranty, patent infringement, and limitation of liability.
TI warrants performance of its semiconductor products to the specifications applicable at the time of sale in
accordance with TI’s standard warranty. Testing and other quality control techniques are utilized to the
extent TI deems necessary to support this warranty. Specific testing of all parameters of each device is not
necessarily performed, except those mandated by government requirements.
In order to minimize risks associated with the customer’s applications, adequate design and operating
safeguards must be provided by the customer to minimize inherent or procedural hazards.
TI assumes no liability for applications assistance or customer product design. TI does not warrant or
represent that any license, either express or implied, is granted under any patent right, copyright, mask
work right, or other intellectual property right of TI covering or relating to any combination, machine, or
process in which such semiconductor products or services might be or are used. TI’s publication of
information regarding any third party’s products or services does not constitute TI’s approval, warranty or
endorsement thereof.
Revision History
October 2001 – Revision 1.0 February 2004 – Revision 5.0
January 2002 – Revision 2.0 May 2004 – Revision 5.1
May 2002 – Revision 3.0 January 2005 – Revision 5.2
June 2002 – Revision 3.1 June 2005 – Revision 6.0
October 2002 – Revision 4.0 September 2005 – Revision 6.1
December 2002 – Revision 4.1 October 2005 – Revision 6.2
July 2003 – Revision 4.2 May 2006 – Revision 6.21
August 2003 – Revision 4.21 February 2007 – Revision 6.22
Mailing Address
Texas Instruments
Training Technical Organization
7839 Churchill Way
M/S 3984
Dallas, Texas 75251-1903
Texas Instruments
Technical Training
T TO
Technical Training
Organization eZdsp is a trademark of Spectrum Digital, Inc. Copyright © 2007 Texas Instruments. All rights reserved.
Introductions
Introductions
Name
Company
Project Responsibilities
DSP / Microcontroller Experience
TMS320 DSP Experience
Hardware / Software - Assembly / C
Interests
LED On-Chip:
(DS1) 18K RAM
+5V 64K Flash
1K OTP
Power
Connector
(P6) +5V ANALOG
Interface
(P5/P9)
Introduction
This architecture overview introduces the basic architecture of the TMS320C28x (C28x) series of
Digital Signal Processors from Texas Instruments. The C28x series adds a new level of general
purpose processing ability unseen in any previous DSP chips. The C28x is ideal for applications
combining DSP, standard microcontroller processing, efficient C code execution, or operating
system tasks.
Unless otherwise noted, the terms C28x and C280x refer to TMS320C280x and TMS320F280x
devices throughout the remainder of these notes. For specific details and differences please refer
to the device data sheet and user’s guide.
Learning Objectives
When this module is complete, you should have a basic understanding of the C28x architecture
and how all of its components work together to create a high-end, uniprocessor control system.
Learning Objectives
Module Topics
Architecture Overview.............................................................................................................................. 1-1
Boot eCAP
Sectored ROM
RAM eQEP
Flash
12-bit ADC
Watchdog
PIE
32-bit R-M-W Interrupt
32x32 bit Manager CAN 2.0B
Auxiliary Atomic
Multiplier
Registers ALU I2C
3
32 bit SCI
Realtime Register Bus Timers SPI
JTAG
CPU
• Memory
• Peripherals
• A program read bus (22 bit address line and 32 bit data line)
• A data read bus (32 bit address line and 32 bit data line)
• A data write bus (32 bit address line and 32 bit data line)
The 32-bit-wide data busses enable single cycle 32-bit operations. This multiple bus architecture,
known as a Harvard Bus Architecture enables the C28x to fetch an instruction, read a data value
and write a data value in a single cycle. All peripherals and memories are attached to the memory
bus and will prioritize memory accesses.
C28x CPU
The C28x is a highly integrated, high performance solution for demanding control applications.
The C28x is a cross between a general microcontroller and a digital signal processor, balancing
the code density of a RISC chip and the execution speed of a DSP with the architecture,
firmware, and development tools of a microcontroller.
The DSP features include a modified Harvard architecture and circular addressing. The RISC
features are single-cycle instruction execution, register-to-register operations, and modified
Harvard architecture. The microcontroller features include ease of use through an intuitive
instruction set, byte packing and unpacking, and bit manipulation.
C28x CPU
MCU/DSP balancing code density
& execution time.
Supports 32-bit instructions
Program Bus for improved execution time;
Supports 16-bit instructions
for improved code efficiency
32-bit fixed-point DSP
PIE
32-bit 32x32 bit R-M-W
32-bit R-M-W Interrupt 32 x 32 bit fixed-point MAC
32x32 bit Manager
Auxiliary Multiplier Atomic
Auxiliary Atomic Dual 16 x 16 single-cycle fixed-
Registers Multiplier ALU
Registers ALU 33 point MAC (DMAC)
32 32-/64-bit saturation
32bit
bit
Register Bus Timers
Realtime
Realtime Timers 64/32 and 32/32 modulus division
CPU
JTAG
JTAG Fast interrupt service time
Data Bus Single cycle read-modify-write
instructions
Unique real-time debugging
capabilities
Upward code compatibility
The C28x design supports an efficient C engine with hardware that allows the C compiler to
generate compact code. Multiple busses and an internal register bus allow an efficient and
flexible way to operate on the data. The architecture is also supported by powerful addressing
modes, which allow the compiler as well as the assembly programmer to generate compact code
that is almost one to one corresponded to the C code.
The C28x is as efficient in DSP math tasks as it is in system control tasks that typically are
handled by microcontroller devices. This efficiency removes the need for a second processor in
many systems.
The C28x is one of several members of the fixed-point generations of digital signal processors
(DSPs) in the TMS320 family. The C28x is source-code and object-code compatible with the
C27x. In addition, the C28x is source code compatible with the 24x/240x DSP and previously
written code can be reassembled to run on a C28x device. This allows for migration of existing
code onto the C28x.
32
ALU (32)
32
ACC (32)
AH (16) AL (16)
AH.MSB AH.LSB AL.MSB AL.LSB
• 32
Shift R/L (0-16)
32
Data Bus
The 32 x 32-bit MAC capabilities of the C28x and its 64-bit processing capabilities, enable the
C28x to efficiently handle higher numerical resolution problems that would otherwise demand a
more expensive floating-point processor solution. Along with this is the capability to perform
two 16 x 16-bit multiply accumulate instructions simultaneously or Dual MACs (DMAC).
6 LSB
XAR0 DP (16) from IR
XAR1
XAR2
32 22
XAR3
XAR4 MUX
XAR5
XAR6
XAR7
MUX
ARAU
Data Memory
XARn → 32-bits
ARn → 16-bits
Special Instructions
C28x Atomic Read/Modify/Write
Atomic Instructions Benefits:
LOAD ¾ Simpler programming
READ
Atomics are small common instructions that are non-interuptable. The atomic ALU capability
supports instructions and code that manages tasks and processes. These instructions usually
execute several cycles faster than traditional coding.
Pipeline Advantage
C28x Pipeline
A F1 F2 D1 D2 R1 R2 X W 8-stage pipeline
B F1 F2 D1 D2 R1 R2 X W
C F1 F2 D1 D2 R1 R2 X W
D F1 F2 D1 D2 R1 R2 X W
E & G Access
E F1 F2 D1 D2 R1 R2 X W same address
F F1 F2 D1 D2 R1 R2 X W
G F1 F2 D1 D2 R11 R2 RX2 W
X W
H F1 F2 D1 D2 R1 R X2 W
R21 R X W
The C28x uses a special 8-stage protected pipeline to maximize the throughput. This protected
pipeline prevents a write to and a read from the same location from occurring out of order.
This pipelining also enables the C28x to execute at high speeds without resorting to expensive
high-speed memories. Special branch-look-ahead hardware minimizes the latency for conditional
discontinuities. Special store conditional operations further improve performance.
Memory
The memory space on the C28x is divided into program and data space. There are several
different types of memory available that can be used as both program or data space. They include
the flash memory, single access RAM (SARAM), expanded SARAM, and Boot ROM which is
factory programmed with boot software routines or standard tables used in math related
algorithms.
Memory Map
The C28x CPU contains no memory, but can access memory both on and off the chip. The C28x
uses 32-bit data addresses and 22-bit program addresses. This allows for a total address reach of
4G words (1 word = 16 bits) in data space and 4M words in program space. Memory blocks on
all C28x designs are uniformly mapped to both program and data space.
This memory map shows the different blocks of memory available to the program and data space.
Peripherals
The C28x comes with many built in peripherals optimized to support control applications. These
peripherals vary depending on which C28x device you choose.
• ePWM • SPI
• eCAP • SCI
• eQEP • I2C
vectors INT1 to
INT12 28x
¾ Auto flags update 96
IFR IER INTM CPU
12 interrupts
¾ Concurrent auto PIE
Register
context save
Map
C28x Mode
The C28x is one of several members of the fixed-point generations of digital signal processors
(DSPs) in the TMS320 family. The C28x is source-code and object-code compatible with the
C27x. In addition, the C28x is source code compatable with the 24x/240x DSP and previously
written code can be reassembled to run on a C28x device. This allows for migration of existing
code onto the C28x.
Reserved 0 1
Reset
Reset – Bootloader
Reset
OBJMODE=0 AMODE=0
ENPIE=0 VMAP=1
Bootloader sets
OBJMODE = 1
AMODE = 0
Reset vector fetched
from boot ROM Boot determined by
state of GPIO pins
0x3F FFC0
Execution
Entry Point
Note: M0 SARAM
Details of the various boot options will be
discussed in the Reset and Interrupts module
Summary
Summary
High performance 32-bit DSP
32 x 32 bit or dual 16 x 16 bit MAC
Atomic read-modify-write instructions
8-stage fully protected pipeline
Fast interrupt response manager
64Kw on-chip flash memory
Code security module (CSM)
Control peripherals
12-bit ADC module
35 shared GPIO pins
Watchdog timer
Communications peripherals
Introduction
This module will explain how to use Code Composer Studio (CCS) integrated development
environment (IDE) tools to develop a program. Creating projects and setting building options
will be covered. Use and the purpose of the linker command file will be described. Additionally,
the DSP/BIOS Configuration Tool will be used to handle system memory and system setup.
Learning Objectives
Learning Objectives
Module Topics
Programming Development Environment .............................................................................................. 2-1
Each file of code, called a module, may be written independently, including the specification of
all resources necessary for the proper operation of the module. Modules can be written using
Code Composer Studio (CCS) or any text editor capable of providing a simple ASCII file output.
The expected extension of a source file is .ASM for assembly and .C for C programs.
Build SIM
Compile lnk.cmd Probe In
eZdsp™
Asm Link Debug
EVM
DSP/BIOS
DSP/BIOS Probe Out
Edit Config Third
Libraries Graphs
Tool Party
Profiling
XDS
Code Composer Studio includes:
Integrated Edit/Debug GUI DSP
Code Generation Tools Board
DSP/BIOS
Code Composer Studio includes a built-in editor, compiler, assembler, linker, and an automatic
build process. Additionally, tools to connect file input and output, as well as built-in graph
displays for output are available. Other features can be added using the plug-ins capability
Numerous modules are joined to form a complete program by using the linker. The linker
efficiently allocates the resources available on the device to each module in the system. The
linker uses a command (.CMD) file to identify the memory resources and placement of where the
various sections within each module are to go. Outputs of the linking process includes the linked
object file (.OUT), which runs on the DSP, and can include a .MAP file which identifies where
each linked section is located.
The high level of modularity and portability resulting from this system simplifies the processes of
verification, debug and maintenance. The process of COFF development is presented in greater
detail in the following paragraphs.
Writing code in modular form permits code to be developed by several people working in parallel
so the development cycle is shortened. Debugging and upgrading code is faster, since
components of the system, rather than the entire system, is being operated upon. Also, new
systems may be developed more rapidly if previously developed modules can be used in them.
Projects
Code Composer works with a project paradigm. Essentially, within CCS you create a project for
each executable program you wish to create. Projects store all the information required to build
the executable. For example, it lists things like: the source files, the header files, the target
system’s memory-map, and program build options.
The project information is stored in a .PJT file, which is created and maintained by CCS. To
create a new project, you need to select the Project:New… menu item.
Along with the main Project menu, you can also manage open projects using the right-click
popup menu. Either of these menus allows you to Add Files… to a project. Of course, you can
also drag-n-drop files onto the project from Windows Explorer.
Build Options
Project options direct the code generation tools (i.e. compiler, assembler, linker) to create code
according to your system’s needs. When you create a new project, CCS creates two sets of build
options – called Configurations: one called Debug, the other Release (you might think of as
Optimize).
To make it easier to choose build options, CCS provides a graphical user interface (GUI) for the
various compiler options. Here’s a sample of the Debug configuration options.
There is a one-to-one relationship between the items in the text box and the GUI check and drop-
down box selections. Once you have mastered the various options, you can probably find
yourself just typing in the options.
There are many linker options but these four handle all of the basic needs.
• -o <filename> specifies the output (executable) filename.
• -m <filename> creates a map file. This file reports the linker’s results.
• -c tells the compiler to autoinitialize your global and static variables.
• -x tells the compiler to exhaustively read the libraries. Without this option libraries are
searched only once, and therefore backwards references may not be resolved.
To help make sense of the many compiler options, TI provides two default sets of options
(configurations) in each new project you create. The Release (optimized) configuration invokes
the optimizer with –o3 and disables source-level, symbolic debugging by omitting –g (which
disables some optimizations to enable debug).
Sections
Global Vars (.ebss) Init vals (.cinit)
Every C program
int x = 2; consists of different
int y = 7; parts called sections
All default sections
names begin with “.”
void main(void) The compiler has
{ default sections
names for initialized
long z; and uninitialized
z = x + y; sections
In the TI code-generation tools (as with any toolset based on the COFF – Common Object File
Format), these various parts of a program are called Sections. Breaking the program code and
data into various sections provides flexibility since it allows you to place code sections in ROM
and variables in RAM. The preceding diagram illustrated five sections:
• Global Variables
• Initial Values for global variables
• Local Variables (i.e. the stack)
• Code (the actual instructions)
Following is a list of the sections that are created by the compiler. Along with their description,
we provide the Section Name defined by the compiler.
Uninitialized Sections
Name Description Link Location
.ebss global & static variables RAM
.stack stack space low 64Kw RAM
.esysmem memory for far malloc functions RAM
Sections of a C program must be located in different memories in your target system. This is the
big advantage of creating the separate sections for code, constants, and variables. In this way,
they can all be linked (located) into their proper memory locations in your target embedded
system. Generally, they’re located as follows:
Memory
Sections
0x00 0000 M0SARAM
(0x400)
.ebss
0x00 0400 M1SARAM
(0x400)
.stack
.text
Linking
zz Memory
Memorydescription
description
zz How
How to
toplace
places/w
s/winto
into h/w
h/w
Link.cmd
.map
Memory-Map Description
The MEMORY section describes the memory configuration of the target system to the linker.
For example, if you placed a 64K FLASH starting at memory location 0x3E8000, it would read:
MEMORY
{
FLASH: origin = 0x3E8000 , length = 0x010000
}
Each memory segment is defined using the above format. If you added M0SARAM and
M1SARAM, it would look like:
MEMORY
{
M0SARAM: origin = 0x000000 , length = 0x0400
M1SARAM: origin = 0x000400 , length = 0x0400
}
Remember that the DSP has two memory maps: Program, and Data. Therefore, the MEMORY
description must describe each of these separately. The loader uses the following syntax to
delineate each of these:
MEMORY
{
PAGE 0: /* Program Space */
FLASH: org = 0x3E8000, len = 0x10000
Section Placement
The SECTIONS section will specify how you want the sections to be distributed through
memory. The following code is used to link the sections into the memory specified in the
previous example:
SECTIONS
{
.text:> FLASH PAGE 0
.ebss:> M0SARAM PAGE 1
.cinit:> FLASH PAGE 0
.stack:> M1SARAM PAGE 1
}
The linker will gather all the code sections from all the files being linked together. Similarly, it
will combine all ‘like’ sections.
Beginning with the first section listed, the linker will place it into the specified memory segment.
Exercise 2a
Looking at the following block diagram, and create a linker command file.
Exercise 2a
F2808
Create a linker command file and link the C program file (LAB2.C) into the system described
below.
System Description:
• TMS320F2808
• All internal RAM blocks allocated
Placement of Sections:
• .text into RAM Block H0SARAM on PAGE 0 (code space)
• .cinit into RAM Block H0SARAM on PAGE 0 (code space)
• .ebss into RAM Block M0SARAM on PAGE 1 (data space)
• .stack into RAM Block M1SARAM on PAGE 1 (data space)
System Description
• TMS320F2808
• All internal RAM blocks allocated
Placement of Sections:
• .text into RAM Block H0SARAM on PAGE 0 (code space)
• .cinit into RAM Block H0SARAM on PAGE 0 (code space)
• .ebss into RAM Block M0SARAM on PAGE 1 (data space)
• .stack into RAM Block M1SARAM on PAGE 1 (data space)
¾ Procedure
The menu bar (at the top) lists File ... Help. Note the horizontal tool bar below the menu
bar and the vertical tool bar on the left-hand side. The window on the left is the project
window and the large right hand window is your workspace.
2. A project is all the files you will need to develop an executable output file (.out) which
can be run on the DSP hardware. Let’s create a new project for this lab. On the menu bar
click:
Project Æ New
type Lab2 in the project name field and make sure the save in location is:
C:\C28x\Labs\Lab2. This will create a .pjt file which will invoke all the necessary
tools (compiler, assembler, linker) to build your project. It will also create a debug
folder that will hold immediate output files.
6. In the project window on the left click the plus sign (+) to the left of Project. Now,
click on the plus sign next to Lab2.pjt. Notice that the Lab2a.cmd file is listed.
Click on Source to see the current source file list (i.e. Lab2.c).
8. Select the Linker tab. Notice that .out and .map files are being created. The .out file is
the executable code that will be loaded into the DSP. The .map file will contain a linker
report showing memory useage and section addresses in memory.
9. Set the Stack Size to 0x200. Select OK and then close the Build Options window.
11. Edit the Memory{} declaration by describing the system memory shown on the “Lab2a:
Linker Command File” slide.
12. In the Sections{} area, notice that a section called .reset has already been allocated.
The .reset section is part of the rts2800_ml.lib, and is not needed. By putting the TYPE =
DSECT modifier after its allocation, the linker will ignore this section and not allocate it.
13. Place the sections defined on the slide into the appropriate memories via the
Sections{} area. Save your work.
15. Code Composer Studio can automatically load the output file after a successful build. On
the menu bar click: Option Æ Customize… and select the “Program/Project
Load” tab, check “Load Program After Build”.
Also, Code Composer Studio can automatically connect to the target when started. Select
the “Debug Properties” tab, check “Connect to the target when a
control window is opened”, then click OK.
16. Click the “Build” button and watch the tools run in the build window. Check for
errors (we have deliberately put an error in Lab2.c). When you get an error, scroll the
build window at the bottom of the Code Composer Studio screen until you see the error
message (in red), and simply double-click the error message. The editor will
automatically open the source file containing the error, and position the mouse cursor at
the correct code line.
17. Fix the error by adding a semicolon at the end of the "z = x + y" statement. For
future knowlege, realize that a single code error can sometimes generate multiple error
messages at build time. This was not the case here.
18. Rebuild the project (there should be no errors this time). The output file should
automatically load. The Program Counter should be pointing to _c_int00 in the
Disassembly Window.
19. Under Debug on the menu bar click “Go Main”. This will run through the C-
environment initialization routine in the rts2800_ml.lib and stop at main() in
Lab2.c.
Type “&z” into the address field. Note that you must use the ampersand (meaning
"address of") when using a symbol in a memory window address box. Also note that
Code Composer Studio is case sensitive.
Set the properties format to “Hex – TI style.” This will give you more viewable data in
the window.
Click OK to close the window property selection screen. The memory window will now
open. You can change the contents of any address in the memory window by double-
clicking on its value. This is useful during debug.
21. Open the watch window to view the local variables x and y.
Click the “Watch Locals” tab and notice that the local variables x and y are already
present. The watch window will always contain the local variables for the code function
currently being executed.
(Note that local variables actually live on the stack. You can also view local variables in
a memory window by setting the address to “SP” after the code function has been
entered).
22. We can also add global variables to the watch window if desired. Let's add the global
variable “z”.
Click the “Watch 1" tab at the bottom of the watch window. In the empty box in the
"Name" column, type “z”. Note that you do not use an ampersand here. The watch
window knows you are specifying a symbol.
Check that the watch window and memory window both report the same value for “z”.
Trying changing the value in one window, and notice that the value also changes in the
other window.
End of Exercise
When you add a .cdb file to your project, CCS automatically adds the C and assembly
(.s28) files and the linker command file (.cmd) to the project under the Generated Files
folder.
To place a section
into a memory area:
Right-click on MEM
and select
Properties
Select the
appropriate tab (e.g.
Compiler)
Select the memory
for each section
When you have finished creating memory regions and allocating sections into these memory
areas (i.e. when you save the .cdb file), the CCS configuration tool creates five files. One of the
files is BIOS’s cfg.cmd file — a linker command file.
MEMORY{
MEMORY{
FLASH:
FLASH: org org == 0x3E8000,
0x3E8000, len
len == 0x10000
0x10000 *cfg_c.c
H0SARAM:
H0SARAM: org = 0x00A000, len == 0x2000
org = 0x00A000, len 0x2000
…… }} *cfg.s28
SECTIONS{
SECTIONS{ *cfg.cmd
.text:
.text: >> FLASH
FLASH
.bss:
.bss: >> M0SARAM
M0SARAM *cfg.h
…… }}
*cfg.h28
This file contains two main parts, MEMORY and SECTIONS. (Though, if you open and
examine it, it’s not quite as nicely laid out as shown above.)
The linker’s main purpose is to link together various object files. It combines like-named input
sections from the various object files and places each new output section at specific locations in
memory. In the process, it resolves (provides actual addresses for) all of the symbols described in
your code.
appcfg.cmd Linker
Linker
.obj files
.map
libraries
(.lib) myApp.out
The linker can create two outputs, the executable (.out) file and a report which describes the
results of linking (.map).
Note: If the graphic above wasn’t clear enough, the linker gets run automatically when you
BUILD or REBUILD your project.
Use Code Composer Studio and DSP/BIOS configuration tool to create a configuration database
files (*.cdb). The generated linker command file Labcfg.cmd will be then be used with Lab2.c to
verify its operation. The memory and sections of a “user” linker command file will be deleted,
however, the “user” linker command file will be needed and modified in future labs.
System Description:
• TMS320F2808
• All internal RAM blocks allocated
Placement of Sections:
• .text into RAM Block H0SARAM in code space (PAGE 0)
• .cinit into RAM Block H0SARAM in code space (PAGE 0)
• .ebss into RAM Block M0SARAM in data space (PAGE 1)
• .stack into RAM Block M1SARAM in data space (PAGE 1)
System Description
• TMS320F2808
• All internal RAM blocks allocated
Placement of Sections:
• .text into RAM Block H0SARAM in code space (PAGE 0)
• .cinit into RAM Block H0SARAM in code space (PAGE 0)
• .ebss into RAM Block M0SARAM in data space (PAGE 1)
• .stack into RAM Block M1SARAM in data space (PAGE 1)
¾ Procedure
Project Lab2.pjt
1. If Code Composer Studio is not running from the previous lab exercise, double click on
the CCS icon on the desktop. Maximize CCS to fill your screen. Then select Lab2.pjt
from the Project Æ Recent Project Files list. This will put you at the
proper starting point for this lab exercise.
2. If needed, verify that the project is open in CCS by left clicking the plus sign (+) to the
left of Project. Then, click on the plus sign next to Lab2.pjt ,as well as the other
plus signs to verify all the previous files have been included.
4. Remove Lab2a.cmd using the same procedure. We will be using the DSP/BIOS
configuration tool to create a linker command file.
8. In the project window left click the plus sign (+) to the left of DSP/BIOS Config.
Notice that the Lab.cdb file is listed. Then left click the plus sign (+) to the left of
Generated Files. The generated linker command file, Labcfg.cmd, is listed and
has been automatically added with the configuration file.
10. By default, the Memory Section Manager has combined the memory space for
L0SARAM and L1SARAM into a single memory block called L0SARAM. It has also
combined M0SARAM and M1SARAM into a single memory block called M0SARAM.
We want to split these memory sections as shown in the slide for this lab exercise.
Right click on MEM – Memory Section Manager and select Insert MEM.
Rename the newly added memory section to L1SARAM. Create a second new memory
section, and rename it to M1SARAM.
11. Modify the length and base addresses of each of the memory sections L0SARAM,
L1SARAM, M0SARAM, and M1SARAM to correspond to the memory mapping shown
in the figure at the beginning of this lab. To modify the length and base address of a
memory section, right click on the memory in configuration tool, and select “Properties.”
While modifying the length and base address of each section, make sure the
“create a heap in memory” box is checked ONLY for L0SARAM. Uncheck
this box in the other three memory sections.
12. Check the memory section properties for H0SARAM and make sure that it corresponds
to the memory mapping shown in the figure at the beginning of this lab. Modify, if
needed.
13. Check the memory section properties for FLASH and make sure that it has the following
settings – base: 0x3E8000, len: 0xFFF6, space: code. Modify, if needed.
14. Right click on MEM – Memory Section Manager and select Properties.
Select the Compiler Sections tab and place the .text, .cinit, and .ebss sections
defined on the lab introduction slide into the appropriate memories via the pull-down
boxes. Similarly, place the .stack section into memory using the BIOS Data tab.
Click OK to save your work.
16. Click: Project Æ Build Options… and select the Linker tab. Delete the entry
for setting the Stack Size to 0x200. Select OK to close the Build Options window.
17. Right click on MEM – Memory Section Manager and select Properties.
Select the General tab. Notice that the Stack Size has been set to 0x200 by default, so
there is no need to modify this. Click OK to close the window. Close the configuration
window and select YES to save changes to Lab.cdb.
19. Under Debug on the menu bar click “Go Main”. This will run through the DSP/BIOS
C-environment initialization routine and stop at main() in Lab2.c.
21. Next, single-step the routine through to the end. Check to see if the program is working
as expected. You should get the same value for “z” as in Lab2a.
End of Exercise
Solutions
Exercise 2a - Solution
MEMORY
{
PAGE 0: /* Program Space */
FLASH: org = 0x3E8000, len = 0x10000
PAGE 1: /* Data Space */
M0SARAM: org = 0x000000, len = 0x400
M1SARAM: org = 0x000400, len = 0x400
L0SARAM: org = 0x008000, len = 0x1000
L1SARAM: org = 0x009000, len = 0x1000
H0SARAM: org = 0x00A000, len = 0x2000
}
SECTIONS
{
.text: > FLASH PAGE 0
.ebss: > M0SARAM PAGE 1
.cinit: > FLASH PAGE 0
.stack: > M1SARAM PAGE 1
}
SECTIONS
{
.text: > H0SARAM PAGE 0
.ebss: > M0SARAM PAGE 1
.cinit: > H0SARAM PAGE 0
.stack: > M1SARAM PAGE 1
.reset: > H0SARAM PAGE 0, TYPE = DSECT
}
Introduction
The purpose of the F280x C-code header files is to simplify the programming of the many
peripherals on the C28x device. Typically, to program a peripheral the programmer needs to
write the appropriate values to the different fields within a control register. In it’s simplest form,
the process consists of writing a hex value (or masking a bit field) to the correct address in
memory. But, since this can be a burdensome and repetitive task, the C-code header files were
created to make this a less complicated task.
The F280x C-code header files are part of a library consisting of C functions, macros, peripheral
structures, and variable definitions. Together, this set of files is known as the ‘header files.’
Registers and the bit-fields are represented by structures. C functions and macros are used to
initialize or modify the structures (registers).
In this module, you will learn how to use the header files and C programs to facilitate
programming the peripherals.
Learning Objectives
Learning Objectives
Module Topics
Peripherial Registers Header Files .......................................................................................................... 3-1
(This example could not have been coded any more efficiently with hand assembly)
Naming Conventions
The header files use a familiar set of naming conventions. They are consistent with the Code
Composer Studio configuration tool, and generated file naming conventions
SECTIONS
{
...
AdcRegsFile :> ADC PAGE = 1
...
}
The user can modify their own linker command file, or use the pre-configured linker command
files such as EzDSP_RAM_lnk.cmd or F2808.cmd. These files have the peripheral memory
regions defined and tied to the individual peripheral.
A DSP280x_Peripheral.gel GEL file can provide a pull down menu to load peripheral data
structures into a watch window. Code Composer Studio can load a GEL file automatically. To
include fuctions to the standard F2808.gel that is part of Code Composer Studio, add:
GEL_LoadGel(“base_path/gel/DSP280x_Peripheral.gel”)
.h Definition Files
The DSP280x_Device.h header file is the main include file. By including this file in the .c source
code, all of the peripheral specific .h header files are automatically included. Of course, each
specific .h header file can included individually in an application that do not use all the header
files, or you can comment out the ones you do not need. (Also includes typedef statements).
.h Definition Files
Files found in the
\DSP280x_headers\include directory
Define structures and bit fields in
peripheral and system registers
DSP280x_Device.h – main include file
will include all other .h files
#include “DSP280x_Device.h”
DSP280x_GlobalVariableDefs.C
Defines all variables to use .h files
DATA_SECTION pragma used to
define data section for each
peripheral structure
Linker will link each structure to the
physical address of the peripheral in
memory
Add DSP280x_GlobalVariableDefs.C
to the Code Composer Studio project
DSP280x_SysCtrl.c DSP280x_Gpio.c
DSP280x_PieCtrl.c DSP280x_I2c.c
DSP280x_Adc.c DSP280x_Sci.c
DSP280x_CpuTimers.c DSP280x_Spi.c
DSP280x_ECan.c DSP280x_ECap.c
DSP280x_EPwm.c DSP280x_EQep.c
DSP280x_PieVect.c DSP280x_DefaultIsr.c
.sect "codestart"
Summary
Peripheral Register Header Files
Summary
Introduction
This module describes the interrupt process and explains how the Peripheral Interrupt Expansion
(PIE) works.
Learning Objectives
Learning Objectives
Module Topics
Reset and Interrupts ................................................................................................................................. 4-1
Reset
Reset Sources
C28x Core
Watchdog Timer
RS
RS pin active
To RS pin
Reset - Bootloader
Reset – Bootloader
Reset
OBJMODE=0 AMODE=0
ENPIE=0 VMAP=1
Bootloader sets
OBJMODE = 1
AMODE = 0
Reset vector fetched
from boot ROM Boot determined by
state of GPIO pins
0x3F FFC0
Execution Bootloading
Entry Point Routines
FLASH SCI-A
M0 SARAM SPI-A
OTP I2C
eCAN-A
Parallel load
Bootloader Options
GPIO pins
18 29 34
1 1 1 jump to FLASH address 0x3F 7FF6
0 1 0 jump to M0 SARAM address 0x00 0000
0 0 1 jump to OTP address 0x3D 7800
1 1 0 bootload code to on-chip memory via SCI-A
1 0 1 bootload external EEPROM to on-chip memory via SPI-A
1 0 0 bootload external EEPROM to on-chip memory via I2C
0 1 1 Call CAN_Boot to load from eCAN-A mailbox 1
0 0 0 bootload code to on-chip memory via GPIO port A (parallel)
0x3E 8000
FLASH (64Kw)
0x3F 7FF6
Execution Entry
0x3F F000 Boot ROM (4Kw) Point Determined
Boot Code By GPIO Pins
0x3F FB50
• •
• •
Interrupts
Interrupt Sources
Internal Sources
TINT2
TINT1 C28x CORE
TINT0 RS
Interrupt Processing
Maskable Interrupt Processing
Conceptual Core Overview
INT1 1
INT2 0 C28x
Core
INT14 1
7 6 5 4 3 2 1 0
INT8 INT7 INT6 INT5 INT4 INT3 INT2 INT1
7 6 5 4 3 2 1 0
INT8 INT7 INT6 INT5 INT4 INT3 INT2 INT1
12 Interrupts
INT11.x interrupt group Core
PIE Registers
PIEIFRx register (x = 1 to 12)
15 - 8 7 6 5 4 3 2 1 0
reserved INTx.8 INTx.7 INTx.6 INTx.5 INTx.4 INTx.3 INTx.2 INTx.1
PIECTRL register 15 - 1 0
PIEVECT ENPIE
#include “DSP280x_Device.h”
PieCtrlRegs.PIEIFR1.bit.INTx4 = 1; //manually set IFR for XINT1 in PIE group 1
PieCtrlRegs.PIEIER3.bit.INTx5 = 1; //enable EPWM5_INT in PIE group 3
PieCtrlRegs.PIEACK.all = 0x0004; //acknowledge the PIE group 3
PieCtrlRegs.PIECTRL.bit.ENPIE = 1; //enable the PIE
INT7
INT10
INT11
INT12
Hardware Interrupts
_c_int00:
. . .
CALL main()
Initialization ( )
{
EALLOW
main() Load PIE Vectors PIE Vector Table
{ initialization(); Enable the PIEIER
256 Word RAM
. . . Enable PIECTRL
} Enable Core IER 0x00 0D00 – 0DFF
Enable INTM
EDIS
}
Interrupt Latency
Latency
ext. Internal
interrupt interrupt Assumes ISR in
occurs occurs internal RAM
here here
cycles
2 4 3 3 1 3
Recognition Get vector ISR
Sync ext. F1/F2/D1 of Save D2/R1/R2 of instruction
signal delay (3), SP and place ISR return ISR
alignment (1), in PC executed
instruction address instruction on next
(ext. interrupt (3 reg. (3 reg. pairs
interrupt placed in pairs cycle
saved)
only) pipeline saved)
Introduction
This module discusses the operation of the OSC/PLL-based clock module and watchdog timer.
Also, various low power modes, general-purpose digital I/O ports, and the EALLOW protected
registers will be covered.
Learning Objectives
Learning Objectives
Watchdog Timer
Module Topics
System Initialization.................................................................................................................................. 5-1
X1 / XCLKIN
Watchdog
Module CLKIN C280x
XTAL OSC
Core
OSCCLK
crystal • • (PLL bypass)
0
/1 SYSCLKOUT
MUX
or • •
X2 VCOCLK /2
PLL 1 HISPCP LOSPCP
PLLCR.bit.DIV
default = 0000b
•
PLLSTS.bit.CLKINDIV HSPCLK LSPCLK
default = /2 (ADC) (SCI/SPI)
(All other peripherals
DIV Clock Frequency (CLKIN) clocked by SYSCLKOUT)
0000 OSCCLK / CLKINDIV (PLL bypass)
0001 OSCCLK x 1 / CLKINDIV
0010 OSCCLK x 2 / CLKINDIV Input Clock Fail Detection
0011 OSCCLK x 3 / CLKINDIV PLL will issue a “limp mode”
0100 OSCCLK x 4 / CLKINDIV clock (1-4 MHz) if input clock
0101 OSCCLK x 5 / CLKINDIV is removed after clock has
0110 OSCCLK x 6 / CLKINDIV been present initially
0111 OSCCLK x 7 / CLKINDIV
1000 OSCCLK x 8 / CLKINDIV
1001 OSCCLK x 9 / CLKINDIV
1010 OSCCLK x 10 / CLKINDIV
The OSC/PLL clock module provides all the necessary clocking signals for C28x devices. The
PLL has a 4-bit ratio control to select different CPU clock rates. Two modes of operation are
supported – crystal operation, and external clock source operation. Crystal operation allows the
use of an external crystal/resonator to provide the time base to the device. External clock source
operation allows the internal oscillator to be bypassed, and the device clocks are generated from
an external clock source input on the X1/CLKIN pin. The watchdog receives a clock signal from
OSCCLK. The C28x core provides a SYSCLKOUT clock signal. This signal is prescaled to
provide a clock source for some of the on-chip peripherals through the high-speed and low-speed
peripheral clock prescalers. Other peripherals are clocked by SYSCLKOUT and use their own
clock prescalers for operation.
SysCtrlRegs.PCLKCR0.bit.name
15 14 13 - 12 11 10 9 8
ECANB ECANA reserved SCIB SCIA SPIB SPIA
ENCLK ENCLK ENCLK ENCLK ENCLK ENCLK
7 6 5 4 3 2 1-0
SPID SPIC reserved I2CA ADC TBCLK reserved
ENCLK ENCLK ENCLK ENCLK SYNC
SysCtrlRegs.PCLKCR1.bit.name
15 14 13 - 12 11 10 9 8
EQEP2 EQEP1 reserved ECAP4 ECAP3 ECAP2 ECAP1
ENCLK ENCLK ENCLK ENCLK ENCLK ENCLK
7-6 5 4 3 2 1 0
reserved EPWM6 EPWM5 EPWM4 EPWM3 EPWM2 EPWM1
ENCLK ENCLK ENCLK ENCLK ENCLK ENCLK
The peripheral clock control register allows individual peripheral clock signals to be enabled or
disabled. If a peripheral is not being used, its clock signal could be disabled, thus reducing power
consumption.
ADC
SysCtrlRegs.LOSPCP.all
15 - 3 2-0
reserved LSPCLK
SCI / SPI
H/LSPCLK Peripheral Clock Frequency
000 SYSCLKOUT / 1
001 SYSCLKOUT / 2 (default HISPCP)
NOTE:
010 SYSCLKOUT / 4 (default LOSPCP)
011 SYSCLKOUT / 6 All Other
100 SYSCLKOUT / 8 Peripherals
101 SYSCLKOUT / 10 Clocked By
110 SYSCLKOUT / 12 SYSCLKOUT
111 SYSCLKOUT / 14
Watchdog Timer
Watchdog Timer
The watchdog timer provides a safeguard against CPU crashes by automatically initiating a reset
if it is not serviced by the CPU at regular intervals. In motor control applications, this helps
protect the motor and drive electronics when control is lost due to a CPU lockup. Any CPU reset
will revert the PWM outputs to a high-impedance state, which should turn off the power
converters in a properly designed system.
The watchdog timer is running immediately after system power-up/reset, and must be dealt with
by software soon after. Specifically, you have 6.55 ms (for a 100 MHz device) after any reset
before a watchdog initiated reset will occur. This translates into 131,072 instruction cycles,
which is a seemingly tremendous amount! Indeed, this is plenty of time to get the watchdog
configured as desired and serviced. A failure of your software to properly handle the watchdog
after reset could cause an endless cycle of watchdog initiated resets to occur.
WD Flag Bit
Gets set when the WD causes a reset
• Writing a 1 clears this bit
• Writing a 0 has no effect
15 - 8 7 6 5-3 2-0
15 - 8 7-0
reserved WDKEY
1 AAh No action
2 AAh No action
3 55h WD counter enabled for reset on next AAh write
4 55h WD counter enabled for reset on next AAh write
5 55h WD counter enabled for reset on next AAh write
6 AAh WD counter is reset
7 AAh No action
8 55h WD counter enabled for reset on next AAh write
9 AAh WD counter is reset
10 55h WD counter enabled for reset on next AAh write
11 23h No effect
15 - 3 2 1 0
IDLE off on on on
15 14 - 8 7-2 1-0
WDINTE reserved QUALSTDBY LPM0
31 30 29 28 27 26 25 24
23 22 21 20 19 18 17 16
GPIO23 GPIO22 GPIO21 GPIO20 GPIO19 GPIO18 GPIO17 GPIO16
15 14 13 12 11 10 9 8
7 6 5 4 3 2 1 0
GPIO7 GPIO6 GPIO5 GPIO4 GPIO3 GPIO2 GPIO1 GPIO0
Exit
Interrupt RESET Watchdog Any GPIO
or Interrupt Enabled Port A
Low Power XNMI Interrupt Signal
Mode
GPIO Port A
Register (GPAMUX1)
[GPIO 0 to 15] GPIO Port A
Direction Register
(GPADIR)
GPIO Port A Mux2 [GPIO 0 to 31]
Internal Bus
Register (GPAMUX2)
[GPIO 16 to 31]
GPIO Port B
Register (GPBMUX1)
[GPIO 32 to 34] GPIO Port B
Direction Register
(GPBDIR)
GPIO Port B Mux2 [GPIO 32 to 34]
Register (GPBMUX2)
[reserved]
QUALPRD2
5-4 GPIO18 SPICLKA SCITXB reserved
GPACTRL
7-6 GPIO19 SPISTEA SCIRXB reserved
9-8 GPIO20 EQEP1A SPISIMOC CANTXB
11-10 GPIO21 EQEP1B SPISOMIC CANRXB
13-12 GPIO22 EQEP1S SPICLKC SCITXB
15-14 GPIO23 EQEP1I SPISTEC SCIRXB
17-16 GPIO24 ECAP1 EQEP2A SPISIMOB
19-18 GPIO25 ECAP2 EQEP2B SPISOMIB
QUALPRD3
21-20 GPIO26 ECAP3 EQEP2I SPICLKB
GPACTRL
23-22 GPIO27 ECAP4 EQEP2S SPISTEB
25-24 GPIO28 SCIRXDA reserved TZ5
27-26 GPIO29 SCITXDA reserved TZ6
29-28 GPIO30 CANRXA reserved reserved
31-30 GPIO31 CANTXA reserved reserved
GPxPUD Internal
15 - 8 7-0 Pull-Up
GPACTRL
QUALPRD1
31 - 24
QUALPRD0
23 - 16 • • 0 = enable
(default GPIO 12-31)
1 = disable
QUALPRD3 QUALPRD2 (default GPIO 0-11)
31 - 8 7-0
GPBCTRL reserved QUALPRD0 Pin
00h no qualification (SYNC to SYSCLKOUT)
01h QUALPRD = SYSCLKOUT/2 GPAQSEL1 / GPAQSEL2 / GPBQSEL1 / GPBQSEL2
02h QUALPRD = SYSCLKOUT/4 00 = SYNC to SYSCLKOUT
.. .. .. 01 = qual to 3 samples – time specified in GPxCTRL
. . . 10 = qual to 6 samples – time specified in GPxCTRL
FFh QUALPRD = SYSCLKOUT/510 11 = no sync or qual (for peripheral; GPIO same as 00)
Name Description
GPACTRL GPIO A Control Register [GPIO 0 – 31]
GPAQSEL1 GPIO A Qualifier Select 1 Register [GPIO 0 – 15]
GPAQSEL2 GPIO A Qualifier Select 2 Register [GPIO 16 – 31]
GPAMUX1 GPIO A Mux1 Register [GPIO 0 – 15]
GPAMUX2 GPIO A Mux2 Register [GPIO 16 – 31]
GPADIR GPIO A Direction Register [GPIO 0 – 31]
GPAPUD GPIO A Pull-Up Disable Register [GPIO 0 – 31]
GPBCTRL GPIO B Control Register [GPIO 32 – 34]
GPBQSEL1 GPIO B Qualifier Select 1 Register [GPIO 32 – 34]
GPBQSEL2 GPIO B Qualifier Select 2 Register [reserved]
GPBMUX1 GPIO B Mux1 Register [GPIO 32 – 34]
GPBMUX2 GPIO B Mux2 Register [reserved]
GPBDIR GPIO B Direction Register [GPIO 32 – 34]
GPBPUD GPIO B Pull-Up Disable Register [GPIO 32 – 34]
Name Description
GPADAT GPIO A Data Register [GPIO 0 – 31]
GPASET GPIO A Data Set Register [GPIO 0 – 31]
GPACLEAR GPIO A Data Clear Register [GPIO 0 – 31]
GPATOGGLE GPIO A Data Toggle [GPIO 0 – 31]
GPBDAT GPIO B Data Register [GPIO 32 – 34]
GPBSET GPIO B Data Set Register [GPIO 32 – 34]
GPBCLEAR GPIO B Data Clear Register [GPIO 32 – 34]
GPBTOGGLE GPIO B Data Toggle [GPIO 32 – 34]
External Interrupts
There are 3 external interrupt signals: XINT1, XINT2, XNMI
Any GPIO port A pin (GPIO0 – GPIO31) can be mapped to any
of these three interrupt signals
GpioIntRegs.name
Name Description
GPIOXINT1SEL selects GPIO0 – GPIO31 pin as XINT1 source
GPIOXINT2SEL selects GPIO0 – GPIO31 pin as XINT2 source
GPIOXNMISEL selects GPIO0 – GPIO31 pin as XNMI source
XIntruptRegs.name
Name Description
XINT1CR enable / disable interrupt, polarity
XINT2CR enable / disable interrupt, polarity
XNMICR enable / disable interrupt, polarity
For each external interrupt, there is also a 16-bit counter (XINT1CTR, XINT2CTR, and XNMICTR)
that is reset to 0x0000 whenever an interrupt edge is detected. These counters can be used to
accurately time stamp an occurrence of the interrupt.
The first part of the lab exercise will setup the system initialization and test the watchdog
operation by having the watchdog cause a reset. In the second part of the lab exercise the PIE
vectors will be added and tested by using the watchdog to generate an interrupt. This lab will
make use of the DSP280x C-code header files to simplify the programming of the device, as well
as take care of the register definitions and addresses. Please review these files, and make use of
them in the future, as needed.
¾ Procedure
Note: LAB 5 files have been provided as a starting point for the lab and need to be
completed. DO NOT copy files from a previous lab.
Main_5.c DSP280x_GlobalVariableDefs.c
Lab.cdb DSP280x_Headers_BIOS.cmd
User_5_6_7.cmd CodeStartBranch.asm
SysCtrl.c Gpio.c
Note that include files, such as DSP280x_Device.h and Lab.h, are automatically
added at project build time. (Also, the generated linker command file, Labcfg.cmd, is
automatically added with the configuration file).
Select the Compiler tab. In the Preprocessor Category, find the Include Search
Path (-i) box and enter:
..\DSP280x_headers\include
This is the path for the header files. Then select OK to save the Build Options.
Modify the configuration file lab.cdb to create a new memory block named
BEGIN_M0: base = 0x000000, length = 0x0002, space = code. Uncheck the “create
a heap in memory” box. You will also need to modify the existing memory block
M0SARAM to avoid any overlaps with this new memory block.
5. Open and inspect Gpio.c. Notice that the shared I/O pins have been set to the GPIO
function. (Note: In Main_5.c do not edit the “main loop” section. This section will be
used to test the watchdog operation.) Save your work.
8. Under Debug on the menu bar click “Go Main”. You should now be at the start of
Main().
10. Single-step your code into the “main loop” section and watch the lines of code
execute. If you don’t want to see each line execute, place the cursor in the “main
loop” section (on the asm(“ NOP”); instruction line) and right click the mouse key
and select Run To Cursor. This is the same as setting a breakpoint on the selected
line, running to that breakpoint, and then removing the breakpoint.
11. Run your code for a few seconds by using the <F5> key, or using the Run button on the
vertical toolbar, or using Debug Æ Run on the menu bar. After a few seconds halt
your code by using Shift <F5>, or the Halt button on the vertical toolbar. Where did your
code stop? Are the results as expected? If things went as expected, your code should be
in the “main loop”.
12. Modify the InitSysCtrl() function to enable the watchdog (WDCR). This will
enable the watchdog to function and cause a reset. Save the file and click the “Build”
button. Then reset the DSP by clicking on Debug Æ Reset CPU. Under Debug on
the menu bar click “Go Main”.
14. Run your code. Where did your code stop? Are the results as expected? If things went
as expected, your code should stop at the breakpoint.
PieCtrl_5_6_7_8_9.c
DefaultIsr_5_6_7.c
Check your files list to make sure the files are there.
16. In Main_5.c, add code to call the InitPieCtrl() function. There are no passed
parameters or return values, so the call code is simply:
InitPieCtrl();
17. Using the “PIE Interrupt Assignment Table” shown in the previous module find the
location for the watchdog interrupt, “WAKEINT”.
19. In SysCtrl.c modify the system control and status register (SCSR) to cause the
watchdog to generate a WAKEINT rather than a reset.
20. Open and inspect DefaultIsr_5_6_7.c. This file contains interrupt service
routines. The ISR for WAKEINT has been trapped by an emulation breakpoint contained
in an inline assembly statement using “ESTOP0”. This gives the same results as placing
a breakpoint in the ISR. We will run the lab exercise as before, except this time the
watchdog will generate an interrupt. If the registers have been configured properly, the
code will be trapped in the ISR.
21. Modify the configuration file Lab.cdb to setup the PIE vector for the watchdog
interrupt. Click on the plus sign (+) to the left of Scheduling and again on the plus
sign (+) to the left of HWI – Hardware Interrupt Service Routine
Manager. Click the plus sign (+) to the left of PIE INTERRUPTS. Locate the
interrupt location for the watchdog. Right click, select Properties, and type
_WAKEINT_ISR (with a leading underscore) in the function field. Click OK and save
all updates.
24. Run your code. Where did your code stop? Are the results as expected? If things went
as expected, your code should stop at the “ESTOP0” instruction in the WAKEINT ISR.
End of Exercise
Note: By default, the watchdog timer is enabled out of reset. Code in the file
CodeStartBranch.asm has been configured to disable the watchdog. This can be
important for large C code projects (ask your instructor if this has not already been
explained). During this lab exercise, the watchdog was actually re-enabled (or disabled
again) in the file SysCtrl.c.
Introduction
This module explains the operation of the analog-to-digital converter. The system consists of a
12-bit analog-to-digital converter with 16 analog input channels. The analog input channels have
a range from 0 to 3 volts. Two input analog multiplexers are used, each supporting 8 analog input
channels. Each multiplexer has its own dedicated sample and hold circuit. Therefore, sequential,
as well as simultaneous sampling is supported. Also, the ADC system features programmable
auto sequence conversions with 16 results registers. Start of conversion (SOC) can be performed
by an external trigger, software, or an ePWM event.
Learning Objectives
Learning Objectives
Module Topics
Analog-to-Digital Converter..................................................................................................................... 6-1
Analog-to-Digital Converter
ADC Module Block Diagram (Cascaded Mode)
Analog MUX
ADCINA0
ADCINA1 Result MUX
MUX S/H
RESULT0
...
ADCINA7
A A
RESULT1
S/H 12-bit A/D RESULT2
MUX Converter
...
ADCINB0
ADCINB1 MUX S/H Result
SOC EOC
...
B B Select RESULT15
ADCINB7 Autosequencer
MAX_CONV1
Ch Sel (CONV00)
Ch Sel (CONV01)
Ch Sel (CONV02)
Software Ch Sel (CONV03)
ePWM_SOC_A
...
ePWM_SOC_B
External Pin Ch Sel (CONV15)
(GPIO/XINT2_ADCSOC)
Start Sequence
Trigger
A A RESULT1
12-bit A/D
...
ADCINA7 Result
S/H Converter
MUX Select RESULT7
ADCINB0 Sequencer
ADCINB1 MUX S/H Arbiter
...
B B SOC1/ SOC2/
RESULT8
ADCINB7 EOC1 EOC2 RESULT9
...
Software
ePWM_SOC_A
ePWM_SOC_B
External Pin Ch Sel (CONV07) Ch Sel (CONV15)
(GPIO/XINT2 Start Sequence Start Sequence
_ADCSOC)
Trigger Trigger
ADC Module
12-bit resolution ADC core
Sixteen analog inputs (range of 0 to 3V)
Two analog input multiplexers
Up to 8 analog input channels each
Two sample/hold units (for each input mux)
Sequential and simultaneous sampling modes
Autosequencing capability - up to 16
autoconversions
Two independent 8-state sequencers
“Dual-sequencer mode”
“Cascaded mode”
Sixteen individually addressable result registers
Multiple trigger sources for start-of-conversion
External trigger, S/W, and ePWM triggers
Note: ADCCLK can be a maximum of 12.5 MHz. See device data sheet
for more information.
Upper Register:
15 14 13 - 12 11 - 8 7
reserved RESET SUSMOD ACQ_PS CPS
Lower Register:
Continuous Run Sequencer Mode
0 = stops after reaching 0 = dual mode
end of sequence 1 = cascaded mode
1 = continuous (starts all over
again from “initial state”)
6 5 4 3-0
CONT_RUN SEQ_OVRD SEQ_CASC reserved
Sequencer Override
(continuous run mode)
0 = sequencer pointer resets to “initial state”
at end of MAX_CONVn
1 = sequencer pointer resets to “initial state”
after “end state”
Upper Register:
ePWM SOC A
ePWM SOC B SEQ1 Mask Bit
Start Conversion (SEQ1) 0 = cannot be started
(cascaded mode only) 0 = clear pending SOC trigger
0 = no action by ePWM trigger
1 = software trigger-start SEQ1 1 = can be started
1 = start by ePWM
signal by ePWM trigger
15 14 13 12 11 10 9 8
ePWM_SOCB RST_SEQ1 SOC_SEQ1 reserved INT_ENA INT_MOD reserved ePWM_SOCA
_SEQ _SEQ1 _SEQ1 _SEQ1
Lower Register:
ePWM SOC B
SEQ2 Mask Bit
Start Conversion (SEQ2) 0 = cannot be started
External SOC (SEQ1) (dual-sequencer mode only)
0 = no action by ePWM trigger
0 = clear pending SOC trigger
1 = start by signal from 1 = can be started
1 = software trigger-start SEQ2
ADCSOC pin by ePWM trigger
7 6 5 4 3 2 1 0
EXT_SOC RST_SEQ2 SOC_SEQ2 reserved INT_ENA INT_MOD reserved ePWM_SOCB
_SEQ1 _SEQ2 _SEQ2 _SEQ2
15 - 8 7 6 5 4-1 0
reserved ADCBGRFDN1 ADCBGRFDN0 ADCPWDN ADCCLKPS SMODE_SEL
15-7 6 5 4 3 2 1 0
MAX_ MAX_ MAX_ MAX_ MAX_ MAX_ MAX_
reserved
CONV 2_2 CONV 2_1 CONV 2_0 CONV 1_3 CONV 1_2 CONV 1_1 CONV 1_0
SEQ2 SEQ1
Dual Mode
ePWM
Output
System Requirements:
•Three autoconversions (I1, I2, I3) off trigger 1 (CTR = 0)
•Three autoconversions (V1, V2, V3) off trigger 2 (CTR = PRD)
ePWM and SEQ1 are used for this example with sequential sampling mode
RESULT0 I1 RESULT3 V1
RESULT1 I2 RESULT4 V2
RESULT2 I3 RESULT5 V3
→ User can reset SEQ1 by software to state CONV00 and repeat same trigger 1, 2 session
• SEQ1 keeps “waiting” at current state for another trigger
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
MSB LSB
Numerical Format
How do we Read the Result?
Integer format
x x x x x x x x x x x x 0 0 0 0 RESULTx
0 0 0 0 x x x x x x x x x x x x Data Mem
void main(void)
{
Uint16 value; // unsigned
Note: The ADC result registers are dual mapped. The result registers that are located
in PF2 (have 2 wait states) are left justified, and the result registers located
in PF0 (have 0 wait states) are right justified.
ADCLO
2) Subtract “1.5” from digital result:
GND
#include
#include “DSP280x_Device.h”
“DSP280x_Device.h”
#define
#define offset
offset 0x07FF
0x07FF
void
void main(void)
main(void)
{{
int16
int16 value;
value; //
// signed
signed
value
value == (AdcRegs.ADCRESULT0
(AdcRegs.ADCRESULT0 >>
>> 4)
4) –– offset;
offset;
}}
The objective of this lab is to apply the techniques discussed in module 6 and to become familiar
with the programming and operation of the on-chip analog-to-digital converter. The DSP will be
setup to sample a single ADC input channel at a prescribed sampling rate and store the
conversion result in a buffer in the DSP memory. This buffer will operate in a circular fashion,
such that new conversion data continuously overwrites older results in the buffer.
pointer rewind
ADC ISR
ADCINA0
...
ePWM2 triggering
ADC on period match
using SOC A trigger
every 20 µs (50 kHz) View ADC
buffer PWM
Samples
Code Composer
Studio
ePWM2
Recall that there are three basic ways to initiate an ADC start of conversion (SOC):
1. Using software
a. SOC_SEQ1/SOC_SEQ2 bit in ADCTRL2 causes an SOC upon completion of the current
conversion (if the ADC is currently idle, an SOC occurs immediately)
2. Automatically triggered on user selectable ePWM conditions
a. ePWM underflow (CTR = 0)
b. ePWM period match (CTR = PRD)
c. ePWM compare match (CTRU/D = CMPA/B)
3. Externally triggered using a pin
a. ADCSOC pin
One or more of these methods may be applicable to a particular application. In this lab, we will
be using the ADC for data acquisition. Therefore, one of the ePWMs (ePWM2) will be
configured to automatically trigger an SOC A at the desired sampling rate (SOC method 2b
above). The ADC end-of-conversion interrupt will be used to prompt the CPU to copy the results
of the ADC conversion into a results buffer in memory. This buffer pointer will be managed in a
circular fashion, such that new conversion results will continuously overwrite older conversion
results in the buffer. In order to generate an interesting input signal, the code also alternately
toggles a GPIO pin (GPIO33) high and low in the ADC interrupt service routine. The ADC ISR
will also toggle LED DS2 on the eZdsp™ as a visual indication that the ISR is running. This pin
will be connected to the ADC input pin, and sampled. After taking some data, Code Composer
Studio will be used to plot the results. A flow chart of the code is shown in the following slide.
Notes
• Program performs conversion on ADC channel A0 (ADCINA0 pin)
• ADC conversion is set at a 50kHz sampling rate
• ePWM2 is triggering the ADC on period match using SOC A trigger
• Data is continuously stored in a circular buffer
• GPIO33 pin is also toggled in the ADC ISR
• ADC ISR will also toggle the eZdsp™ LED DS2 as a visual indication that it is running
¾ Procedure
Project File
Note: LAB6 files have been provided as a starting point for the lab and need to be
completed. DO NOT copy files from a previous lab.
1. A project named Lab6.pjt has been created for this lab. Open the project by clicking
on Project Æ Open… and look in C:\C28x\Labs\Lab6. All Build Options
have been configured like the previous lab. The files used in this lab are:
Main_6.c Labcfg.cmd
Lab.cdb DSP280x_Headers_BIOS.cmd
User_5_6_7.cmd CodeStartBranch.asm
SysCtrl.c Gpio.c
DSP280x_GlobalVariableDefs.c PieCtrl_5_6_7_8_9.c
DefaultIsr_5_6_7.c Adc.c
EPwm_6.c DelayUs.asm
4. Using the “PIE Interrupt Assignment Table” find the location for the
ADC interrupt, “ADCINT” and fill in the following information:
7. Modify the configuration file lab.cdb to setup the PIE vector for the ADC interrupt.
Click on the plus sign (+) to the left of Scheduling and again on the plus sign (+) to
the left of HWI – Hardware Interrupt Service Routine Manager. Click
the plus sign (+) to the left of PIE INTERRUPTS. Locate the interrupt location for the
ADC (use the information from step #4). Right click, select Properties, and type
_ADCINT_ISR (with a leading underscore) in the function field. Click OK and save all
updates.
11. Open a memory window to view some of the contents of the ADC results buffer. The
address label for the ADC results buffer is AdcBuf.
Note: Exercise care when connecting any wires, as the power to the eZdsp™ is on, and we
do not want to damage the eZdsp™! Details of pin assignments can be found in
Appendix A.
12. Using a connector wire provided, connect the ADCINA0 (pin # P9-2) to “GND” (pin #
P9-1) on the eZdsp™. Then run the code again, and halt it after a few seconds. Verify
that the ADC results buffer contains the expected value of 0x0000.
13. Adjust the connector wire to connect the ADCINA0 (pin # P9-2) to “+3.3V” (pin # P8-
36) on the eZdsp™. (Note: pin # P8-36 / GPIO32 has been set to “1” in Gpio.c). Then
run the code again, and halt it after a few seconds. Verify that the ADC results buffer
contains the expected value of 0x0FFF.
14. Adjust the connector wire to connect the ADCINA0 (pin # P9-2) to GPIO33 (pin # P8-
38) on the eZdsp™. Then run the code again, and halt it after a few seconds. Examine
the contents of the ADC results buffer (the contents should be alternating 0x0000 and
0x0FFF values). Are the contents what you expected?
15. Open and setup a graph to plot a 50-point window of the ADC results buffer.
Click: View Æ Graph Æ Time/Frequency… and set the following values:
16. Recall that the code toggled the GPIO33 pin alternately high and low. (Also, the ADC
ISR is toggling the LED DS2 on the eZdsp™ as a visual indication that the ISR is
running). If you had an oscilloscope available to display GPIO33, you would expect to
see a square-wave. Why does Code Composer Studio plot resemble a triangle wave?
What is the signal processing term for what is happening here?
17. Recall that the program toggled the GPIO33 pin at a 50 kHz rate. Therefore, a complete
cycle (toggle high, then toggle low) occurs at half this rate, or 25 kHz. We therefore
expect the period of the waveform to be 40 μs. Confirm this by measuring the period of
the triangle wave using the graph (you may want to enlarge the graph window using the
mouse). The measurement is best done with the mouse. The lower left-hand corner of
the graph window will display the X and Y axis values. Subtract the X-axis values taken
over a complete waveform period.
1. Windows within Code Composer Studio can be updated at up to a 10 Hz rate while the
DSP is running. This not only allows graphs and watch windows to update, but also
allows the user to change values in watch or memory windows, and have those
changes affect the DSP behavior. This is very useful when tuning control law
parameters on-the-fly, for example.
2. It allows the user to halt the DSP and step through foreground tasks, while specified
interrupts continue to get serviced in the background. This is useful when debugging
portions of a realtime system (e.g., serial port receive code) while keeping critical
parts of your system operating (e.g., commutation and current loops in motor control).
18. Reset the DSP, and then enable real-time mode by selecting:
19. A message box will appear. Select YES to enable debug events. This will set bit 1
(DGBM bit) of status register 1 (ST1) to a “0”. The DGBM is the debug enable mask bit.
When the DGBM bit is set to “0”, memory and register values can be passed to the host
processor for updating the debugger windows.
20. The memory and graph windows displaying AdcBuf should still be open. The connector
wire between ADCINA0 (pin # P9-2) and GPIO33 (pin # P8-38) should still be
connected. In real-time mode, we would like to have our window continuously refresh.
Click:
Note: “Global Continuous Refresh” causes all open windows to refresh at the
refresh rate. This can be problematic when a large number of windows are open, as
bandwidth over the emulation link is limited. Updating too many windows can cause the
refresh frequency to bog down. In that case, either close some windows, or disable
global refresh and selectively enable “Continuous Refresh” for individual
windows of interest instead.
21. Run the code and watch the windows update in real-time mode. Are the values updating
as expected?
22. Fully halting the DSP when in real-time mode is a two-step process. First, halt the
processor with Debug Æ Halt. Then uncheck the “Real-time mode” to take
the DSP out of real-time mode.
23. So far, we have seen data flowing from the DSP to the debugger in realtime. In this step,
we will flow data from the debugger to the DSP.
• Open and inspect DefaultIsr_5_6_7.c. Notice that the global variable
DEBUG_TOGGLE is used to control the toggling of the GPIO33 pin. This is the pin
being read with the ADC.
• Highlight DEBUG_TOGGLE with the mouse, right click and select “Add to
Watch Window”. The global variable DEBUG_TOGGLE should now be in the
watch window with a value of “1”.
• Run the code in real-time mode and change the value to “0”. Are the results shown
in the memory and graph window as expected? Change the value back to “1”. As
you can see, we are modifying data memory contents while the processor is running
in real-time (i.e., we are not halting the DSP nor interfering with its operation in any
way)! When done, fully halt the DSP.
24. Code Composer Studio includes GEL (General Extension Language) functions which
automate entering and exiting real-time mode. Four functions are available:
• Run_Realtime_with_Reset (reset DSP, enter real-time mode, run DSP)
• Run_Realtime_with_Restart (restart DSP, enter real-time mode, run DSP)
• Full_Halt (exit real-time mode, halt DSP)
• Full_Halt_with_Reset (exit real-time mode, halt DSP, reset DSP)
These GEL functions can be executed by clicking:
GEL Æ Realtime Emulation Control Æ GEL Function
In the remaining lab exercises we will be using the above GEL functions to run and halt
the code in real-time mode. If you would like, try repeating the previous step using the
following GEL functions:
GEL Æ Realtime Emulation Control Æ Run_Realtime_with_Reset
GEL Æ Realtime Emulation Control Æ Full_Halt
End of Exercise
Introduction
This module explains how to generate PWM waveforms using the ePWM unit. Also, the eCAP
unit, and eQEP unit will be discussed.
Learning Objectives
Learning Objectives
Module Topics
PWM Review
What is Pulse Width Modulation?
t t
T
Original Signal PWM representation
Pulse width modulation (PWM) is a method for representing an analog signal with a digital
approximation. The PWM signal consists of a sequence of variable width, constant amplitude
pulses which contain the same total energy as the original analog signal. This property is
valuable in digital motor control as sinusoidal current (energy) can be delivered to the motor
using PWM signals applied to the power converter. Although energy is input to the motor in
discrete packets, the mechanical inertia of the rotor acts as a smoothing filter. Dynamic motor
motion is therefore similar to having applied the sinusoidal currents directly.
DC Supply DC Supply
? PWM
Desired PWM approx.
signal to of desired
system signal
Unknown Gate Signal Gate Signal Known with PWM
ePWM
ePWM Block Diagram
CMPA . 15 - 0 CMPB . 15 - 0
TBCTL . 12 - 7
Shadowed Shadowed
Clock Compare Compare
Prescaler Register Register
AQCTLA . 11 - 0
TBCTR . 15 - 0
AQCTLB . 11 - 0 DBCTL . 4 - 0
16-Bit
Compare Action Dead
Time-Base
Logic Qualifier Band
Counter
EPWMxSYNCI EPWMxSYNCO
Period
Register EPWMxA
PWM Trip
Shadowed EPWMxB
Chopper Zone
SYSCLKOUT TBPRD . 15 - 0
PCCTL . 10 - 0 TZx
TZSEL . 15 - 0
Note: x = 1, 2, 3, 4, 5, or 6
CMPA . 15 - 0 CMPB . 15 - 0
TBCTL . 12 - 7
Shadowed Shadowed
Clock Compare Compare
Prescaler Register Register
AQCTLA . 11 - 0
TBCTR . 15 - 0
AQCTLB . 11 - 0 DBCTL . 4 - 0
16-Bit
Compare Action Dead
Time-Base
Logic Qualifier Band
Counter
EPWMxSYNCI EPWMxSYNCO
Period
Register EPWMxA
PWM Trip
Shadowed EPWMxB
Chopper Zone
SYSCLKOUT TBPRD . 15 - 0
PCCTL . 10 - 0 TZx
TZSEL . 15 - 0
Note: x = 1, 2, 3, 4, 5, or 6
TBPRD
Asymmetrical
Waveform
Count Up Mode
TBCTR
TBPRD
Asymmetrical
Waveform
TBCTR
TBPRD
Symmetrical
Waveform
Phase
φ=0°
En
o o .
SyncIn
EPWM1A
o
CTR=zero o
CTR=CMPB o o EPWM1B
X o
SyncOut
Phase
φ=120°
En
o o .
SyncIn
EPWM2A φ=120°
o
CTR=zero o
CTR=CMPB o o EPWM2B
X o
SyncOut
Phase
φ=240°
En
o o .
SyncIn
EPWM3A
φ=120°
o
CTR=zero o
CTR=CMPB o o EPWM3B
X o
SyncOut φ=240°
Upper Register:
15 - 14 13 12 - 10 9-7
FREE_SOFT PHSDIR CLKDIV HSPCLKDIV
Lower Register:
Counter Mode
Software Force Sync Pulse 00 = count up
01 = count down
0 = no action 10 = count up and down
1 = force one-time sync 11 = stop – freeze (default)
6 5-4 3 2 1-0
SWFSYNC SYNCOSEL PRDLD PHSEN CTRMODE
15 - 3 2 1 0
reserved CTRMAX SYNCI CTRDIR
CMPA . 15 - 0 CMPB . 15 - 0
TBCTL . 12 - 7
Shadowed Shadowed
Clock Compare Compare
Prescaler Register Register
AQCTLA . 11 - 0
TBCTR . 15 - 0
AQCTLB . 11 - 0 DBCTL . 4 - 0
16-Bit
Compare Action Dead
Time-Base
Logic Qualifier Band
Counter
EPWMxSYNCI EPWMxSYNCI
Period
Register EPWMxA
PWM Trip
Shadowed EPWMxB
Chopper Zone
SYSCLKOUT TBPRD . 15 - 0
PCCTL . 10 - 0 TZx
TZSEL . 15 - 0
Note: x = 1, 2, 3, 4, 5, or 6
.. .. ..
TBPRD
CMPA Asymmetrical
CMPB Waveform
Count Up Mode
TBCTR
TBPRD
CMPA
CMPB
.. .. .. Asymmetrical
Waveform
TBCTR
.. .. .. ..
TBPRD
CMPA Symmetrical
CMPB Waveform
Upper Register:
15 - 10 9 8 7
reserved SHDWBFULL SHDWAFULL reserved
6 5 4 3-2 1-0
SHDWBMODE reserved SHDWAMODE LOADBMODE LOADAMODE
CMPA . 15 - 0 CMPB . 15 - 0
TBCTL . 12 - 7
Shadowed Shadowed
Clock Compare Compare
Prescaler Register Register
AQCTLA . 11 - 0
TBCTR . 15 - 0
AQCTLB . 11 - 0 DBCTL . 4 - 0
16-Bit
Compare Action Dead
Time-Base
Logic Qualifier Band
Counter
EPWMxSYNCI EPWMxSYNCO
Period
Register EPWMxA
PWM Trip
Shadowed EPWMxB
Chopper Zone
SYSCLKOUT TBPRD . 15 - 0
PCCTL . 10 - 0 TZx
TZSEL . 15 - 0
Note: x = 1, 2, 3, 4, 5, or 6
SW Z CA CB P Do Nothing
X X X X X
SW Z CA CB P Clear Low
↓ ↓ ↓ ↓ ↓
SW Z CA CB P Set High
↑ ↑ ↑ ↑ ↑
SW Z CA CB P
Toggle
T T T T T
TBCTR
TBPRD
. .
. .
Z P CB CA Z P CB CA Z P
↑ X X ↓ ↑ X X ↓ ↑ X
EPWMA
Z P CB CA Z P CB CA Z P
↑ X ↓ X ↑ X ↓ X ↑ X
EPWMB
TBCTR
TBPRD
. .
. .
CA CB CA CB
↑ ↓ ↑ ↓
EPWMA
Z Z Z
T T T
EPWMB
TBPRD
. . . .
. . . .
CA CA CA CA
↑ ↓ ↑ ↓
EPWMA
CB CB CB CB
↑ ↓ ↑ ↓
EPWMB
TBPRD
. .
. .
CA CB CA CB
↑ ↓ ↑ ↓
EPWMA
Z P Z P
↓ ↑ ↓ ↑
EPWMB
15 - 4 3-2 1-0
reserved CSFB CSFA
CMPA . 15 - 0 CMPB . 15 - 0
TBCTL . 12 - 7
Shadowed Shadowed
Clock Compare Compare
Prescaler Register Register
AQCTLA . 11 - 0
TBCTR . 15 - 0
AQCTLB . 11 - 0 DBCTL . 4 - 0
16-Bit
Compare Action Dead
Time-Base
Logic Qualifier Band
Counter
EPWMxSYNCI EPWMxSYNCO
Period
Register EPWMxA
PWM Trip
Shadowed EPWMxB
Chopper Zone
SYSCLKOUT TBPRD . 15 - 0
PCCTL . 10 - 0 TZx
TZSEL . 15 - 0
Note: x = 1, 2, 3, 4, 5, or 6
supply rail
PWMxA
Rising
.
0
.
Edge
°
0 S1 PWMxA
0 Delay ° S2 RED °
° ° S4
° °1
°1
In Out
(10-bit
° °1
counter)
Falling
.
Edge 0
. ° S3
0 Delay FED 1
° ° S5
° ° S0° PWMxB
°1
In Out
(10-bit
° °1 °0
counter)
IN-MODE POLSEL OUT-MODE
PWMxB
Two basic approaches exist for controlling shoot-through: modify the transistors, or modify the
PWM gate signals controlling the transistors. In the first case, the opening time of the transistor
gate must be increased so that it (slightly) exceeds the closing time. One way to accomplish this
is by adding a cluster of passive components such as resistors and diodes in series with the
transistor gate, as shown in the next figure.
by-pass diode
PWM
signal
R
The resistor acts to limit the current rise rate towards the gate during transistor opening, thus
increasing the opening time. When closing the transistor however, current flows unimpeded from
the gate via the by-pass diode and closing time is therefore not affected. While this passive
approach offers an inexpensive solution that is independent of the control microprocessor, it is
imprecise, the component parameters must be individually tailored to the power converter, and it
cannot adapt to changing system conditions.
precise control of gate timing requirements. In addition, the dead time is typically specified with
a single program variable that is easily changed for different power converters or adapted on-line.
Polarity Select
00 = active high
01 = active low complementary (RED)
10 = active high complementary (FED)
11 = active low
CMPA . 15 - 0 CMPB . 15 - 0
TBCTL . 12 - 7
Shadowed Shadowed
Clock Compare Compare
Prescaler Register Register
AQCTLA . 11 - 0
TBCTR . 15 - 0
AQCTLB . 11 - 0 DBCTL . 4 - 0
16-Bit
Compare Action Dead
Time-Base
Logic Qualifier Band
Counter
EPWMxSYNCI EPWMxSYNCO
Period
Register EPWMxA
PWM Trip
Shadowed EPWMxB
Chopper Zone
SYSCLKOUT TBPRD . 15 - 0
PCCTL . 10 - 0 TZx
TZSEL . 15 - 0
Note: x = 1, 2, 3, 4, 5, or 6
EPWMxB
CHPFREQ
EPWMxA
EPWMxB
Programmable
Pulse Width
OSHT (OSHTWTH)
Sustaining
EPWMxA Pulses
15 - 11 10 - 8 7-5 4-1 0
reserved CHPDUTY CHPFREQ OSHTWTH CHPEN
CMPA . 15 - 0 CMPB . 15 - 0
TBCTL . 12 - 7
Shadowed Shadowed
Clock Compare Compare
Prescaler Register Register
AQCTLA . 11 - 0
TBCTR . 15 - 0
AQCTLB . 11 - 0 DBCTL . 4 - 0
16-Bit
Compare Action Dead
Time-Base
Logic Qualifier Band
Counter
EPWMxSYNCI EPWMxSYNCO
Period
Register EPWMxA
PWM Trip
Shadowed EPWMxB
Chopper Zone
SYSCLKOUT TBPRD . 15 - 0
PCCTL . 10 - 0 TZx
TZSEL . 15 - 0
Note: x = 1, 2, 3, 4, 5, or 6
TZ4 EPWM5A U
TZ5 One-Shot EPWM5B T
TZ6 Mode EPWM6A S
EPWM6B
The power drive protection is a safety feature that is provided for the safe operation of systems
such as power converters and motor drives. It can be used to inform the monitoring program of
motor drive abnormalities such as overvoltage, over-current, and excessive temperature rise. If
the power drive protection interrupt is unmasked, the PWM output pins will be put in the high-
impedance state immediately after the pin is driven low. An interrupt will also be generated.
15 - 4 3-2 1-0
reserved TZB TZA
15 - 14 13 12 11 10 9 8
reserved OSHT6 OSHT5 OSHT4 OSHT3 OSHT2 OSHT1
7-6 5 4 3 2 1 0
reserved CBC6 CBC5 CBC4 CBC3 CBC2 CBC1
15 - 3 2 1 0
reserved OST CBC reserved
One-Shot Cycle-by-Cycle
Interrupt Enable Interrupt Enable
0 = disable 0 = disable
1 = enable 1 = enable
CMPA . 15 - 0 CMPB . 15 - 0
TBCTL . 12 - 7
Shadowed Shadowed
Clock Compare Compare
Prescaler Register Register
AQCTLA . 11 - 0
TBCTR . 15 - 0
AQCTLB . 11 - 0 DBCTL . 4 - 0
16-Bit
Compare Action Dead
Time-Base
Logic Qualifier Band
Counter
EPWMxSYNCI EPWMxSYNCO
Period
Register EPWMxA
PWM Trip
Shadowed EPWMxB
Chopper Zone
SYSCLKOUT TBPRD . 15 - 0
PCCTL . 10 - 0 TZx
TZSEL . 15 - 0
Note: x = 1, 2, 3, 4, 5, or 6
. . . . . . . .
TBPRD
CMPB
CMPA
EPWMA
EPWMB
CTR = 0
CTR = PRD
CTRU = CMPA
CTRD = CMPA
CTRU = CMPB
CTRD = CMPB
15 14 - 12 11 10 - 8 7-4 3 2-0
SOCBEN SOCBSEL SOCAEN SOCASEL reserved INTEN INTSEL
Regular
Device Clock PWM Step
(i.e. 100MHz) (i.e. 10ns)
HRPWM
Micro Step (~150ps)
⎛ switching period ⎞
Asymmetric PWM: period register = ⎜⎜ ⎟⎟ − 1
⎝ timer period ⎠
switching period
Symmetric PWM: period register =
2(timer period)
Notice that in the symmetric case, the period value is half that of the asymmetric case. This is
because for up/down counting, the actual timer period is twice that specified in the period register
(i.e. the timer counts up to the period register value, and then counts back down).
PWM resolution:
The PWM compare function resolution can be computed once the period register value is
determined. The largest power of 2 is determined that is less than (or close to) the period value.
As an example, if asymmetric was 1000, and symmetric was 500, then:
Note that for symmetric PWM, the desired duty cycle is only achieved if the compare registers
contain the computed value for both the up-count compare and down-count compare portions of
the time-base period.
ePWM Exercise
ePWM Exercise
eCAP
Capture Units
Timer
Trigger .
Timestamp
Values
The capture units allow time-based logging of external TTL signal transitions on the capture input
pins. The C28x has up to four capture units.
Capture units can be configured to trigger an A/D conversion that is synchronized with an
external event. There are several potential advantages to using the capture for this function over
the ADCSOC pin associated with the ADC module. First, the ADCSOC pin is level triggered,
and therefore only low to high external signal transitions can start a conversion. The capture unit
does not suffer from this limitation since it is edge triggered and can be configured to start a
conversion on either rising edges, falling edges, or both. Second, if the ADCSOC pin is held high
longer than one conversion period, a second conversion will be immediately initiated upon
completion of the first. This unwanted second conversion could still be in progress when a
desired conversion is needed. In addition, if the end-of-conversion ADC interrupt is enabled, this
second conversion will trigger an unwanted interrupt upon its completion. These two problems
are not a concern with the capture unit. Finally, the capture unit can send an interrupt request to
the CPU while it simultaneously initiates the A/D conversion. This can yield a time savings
when computations are driven by an external event since the interrupt allows preliminary
calculations to begin at the start-of-conversion, rather than at the end-of-conversion using the
ADC end-of-conversion interrupt. The ADCSOC pin does not offer a start-of-conversion
interrupt. Rather, polling of the ADCSOC bit in the control register would need to be performed
to trap the externally initiated start of conversion.
Capture 1 Polarity
Register Select 1
CAP2POL
CAP2 . 31 - 0 ECCTL . 2
Capture 4 Polarity
Register Select 4
Note: x = 1, 2, 3, or 4
Shadowed
Period CAP3 . 31 - 0
CAP1 . 31 - 0 Period Register shadow
immediate Register (CAP 3) mode
mode (Capture 1)
TSCTR . 31 - 0
SYSCLKOUT
CAP2 . 31 - 0 Compare
immediate Register Compare CAP4 . 31 - 0
mode (Capture 2) Register shadow
Shadowed (CAP 4) mode
Note: x = 1, 2, 3, or 4
Upper Register:
CAP1 – 4 Load
on Capture Event
0 = disable
1 = enable
15 - 14 13 - 9 8
FREE_SOFT PRESCALE CAPLDEN
Lower Register:
Counter Reset on Capture Event
0 = no reset (absolute time stamp mode)
1 = reset after capture (difference mode)
7 6 5 4 3 2 1 0
CTRRST4 CAP4POL CTRRST3 CAP3POL CTRRST2 CAP2POL CTRRST1 CAP1POL
Upper Register:
Capture / APWM mode
0 = capture mode
1 = APWM mode
15 - 11 10 9 8
reserved APWMPOL CAP_APWM SWSYNC
Lower Register:
Re-arm Continuous/One-Shot
Counter Sync-In (capture mode only) (capture mode only)
0 = disable 0 = no effect 0 = continuous mode
1 = enable 1 = arm sequence 1 = one-shot mode
7-6 5 4 3 2-1 0
SYNCO_SEL SYNCI_EN TSCTRSTOP REARM STOP_WRAP CONT_ONESHT
The capture unit interrupts offer immediate CPU notification of externally captured events. In
situations where this is not required, the interrupts can be masked and flag testing/polling can be
used instead. This offers increased flexibility for resource management. For example, consider a
servo application where a capture unit is being used for low-speed velocity estimation via a
pulsing sensor. The velocity estimate is not used until the next control law calculation is made,
which is driven in real-time using a timer interrupt. Upon entering the timer interrupt service
routine, software can test the capture interrupt flag bit. If sufficient servo motion has occurred
since the last control law calculation, the capture interrupt flag will be set and software can
proceed to compute a new velocity estimate. If the flag is not set, then sufficient motion has not
occurred and some alternate action would be taken for updating the velocity estimate. As a
second example, consider the case where two successive captures are needed before a
computation proceeds (e.g. measuring the width of a pulse). If the width of the pulse is needed as
soon as the pulse ends, then the capture interrupt is the best option. However, the capture
interrupt will occur after each of the two captures, the first of which will waste a small number of
cycles while the CPU is interrupted and then determines that it is indeed only the first capture. If
the width of the pulse is not needed as soon as the pulse ends, the CPU can check, as needed, the
capture registers to see if two captures have occurred, and proceed from there.
15 - 8 7 6 5 4 3 2 1 0
reserved CTR=CMP CTR=PRD CTROVF CEVT4 CEVT3 CEVT2 CEVT1 reserved
eQEP
What is an Incremental Quadrature
Encoder?
A digital (angular) position sensor
Ch. A
Ch. B
shaft rotation
The eQEP circuit, when enabled, decodes and counts the quadrature encoded input pulses. The
QEP circuit can be used to interface with an optical encoder to get position and speed information
from a rotating machine.
(00) (11)
increment decrement
(A,B) = counter 10 counter
(10) (01)
Quadrature
Ch. A 00 Decoder 11
State Machine
Ch. B
01
eQEP Connections
Ch. A
Quadrature Ch. B
Capture
EQEPxA/XCLK
32-Bit Unit
Time-Base EQEPxB/XDIR
Quadrature
QEP Decoder EQEPxI Index
Watchdog
EQEPxS Strobe
from homing sensor
SYSCLKOUT
Position/Counter
Compare
The objective of this lab is to apply the techniques discussed in module 7 and become familiar
with the programming and operation of the control peripherals and its interrupts. ePWM1A will
be setup to generate a 2 kHz, 25% duty cycle symmetric PWM waveform. The waveform will
then be sampled with the on-chip analog-to-digital converter and displayed using the graphing
feature of Code Composer Studio. Next, eCAP1 will be setup to detect the rising and falling
edges of the waveform. This information will be used to determine the width of the pulse and
duty cycle of the waveform. The results of this step will be viewed numerically in a memory
window.
ePWM1
TB Counter CPU copies
data
ADC memory
Compare connector result to
wire buffer during
Action Qualifier RESULT0
pointer rewind
ADC ISR
eCAP1 ADC-
Capture 1 Register INA0
...
Capture 2 Register
Capture 3 Register
Capture 4 Register
View ADC
buffer PWM
ePWM2 triggering ADC on
Samples
period match using SOC A
trigger every 20 µs (50 kHz)
ePWM2 Code Composer
Studio
¾ Procedure
Project File
Note: LAB7 files have been provided as a starting point for the lab and need to be
completed. DO NOT copy files from a previous lab.
1. A project named Lab7.pjt has been created for this lab. Open the project by clicking
on Project Æ Open… and look in C:\C28x\Labs\Lab7. All Build Options
have been configured like the previous lab. The files used in this lab are:
Main_7.c Labcfg.cmd
Lab.cdb DSP280x_Headers_BIOS.cmd
User_5_6_7.cmd CodeStartBranch.asm
SysCtrl.c Gpio.c
DSP280x_GlobalVariableDefs.c PieCtrl_5_6_7_8_9.c
DefaultIsr_5_6_7.c Adc.c
EPwm_7_8_9_10.c DelayUs.asm
6. Using a connector wire provided, connect the PWM1A (pin # P8-9) to ADCINA0 (pin #
P9-2) on the eZdsp™.
7. Run the code (real-time mode) using the GEL function: GEL Æ Realtime
Emulation Control Æ Run_Realtime_with_Reset. Watch the window
update. Verify that the ADC result buffer contains the updated values.
8. Open and setup a graph to plot a 50-point window of the ADC results buffer.
Click: View Æ Graph Æ Time/Frequency… and set the following values:
9. The graphical display should show the generated 2 kHz, 25% duty cycle symmetric
PWM waveform. The period of a 2 kHz signal is 500 μs. You can confirm this by
measuring the period of the waveform using the graph (you may want to enlarge the
graph window using the mouse). The measurement is best done with the mouse. The
lower left-hand corner of the graph window will display the X and Y-axis values.
Subtract the X-axis values taken over a complete waveform period (you can use the PC
calculator program found in Microsoft Windows to do this).
FFT Framesize 50
11. On the plot window, left-click the mouse to move the vertical marker line and observe the
frequencies of the different magnitude peaks. Do the peaks occur at the expected
frequencies?
12. Fully halt the DSP (real-time mode) by using the GEL function: GEL Æ Realtime
Emulation Control Æ Full_Halt.
14. In Main_7.c, add code to call the InitECap() function. There are no passed
parameters or return values, so the call code is simply:
InitECap();
15. Edit Gpio.c and adjust the shared I/O pin in GPIO5 for the ECAP1 function.
16. Open and inspect the eCAP1 interrupt service routine (ECAP1_INT_ISR) in the file
DefaultIsr_5_6_7.c. Notice that PWM_duty is calculated by CAP2 – CAP1
(rising to falling edge) and that PWM_period is calculated by CAP3 – CAP1 (rising to
rising edge).
18. Using the “PIE Interrupt Assignment Table” find the location for the
eCAP1 interrupt, “ECAP1_INT” and fill in the following information:
ECAP1_INT (use the information from step #18). Right click, select Properties, and
type _ECAP1_INT_ISR (with a leading underscore) in the function field. Click OK
and save all updates.
23. Set the memory window properties format to “32-Bit UnSigned Int”. Click OK.
24. Using the connector wire provided, connect the PWM1A (pin # P8-9) to ECAP1 (pin #
P8-14) on the eZdsp™.
25. Run the code (real-time mode) by using the GEL function: GEL Æ Realtime
Emulation Control Æ Run_Realtime_with_Reset. Notice the values for
PWM_duty and PWM_period.
26. Fully halt the DSP (real-time mode) by using the GEL function: GEL Æ Realtime
Emulation Control Æ Full_Halt.
Questions:
• How do the captured values for PWM_duty and PWM_period relate to the compare
register CMPA and time-base period TBPRD settings for ePWM1A?
• What is the value of PWM_duty in memory?
• What is the value of PWM_period in memory?
• How does it compare with the expected value?
End of Exercise
TPWM
50 kHz = 20 μs
Period
CPU clock = 10 ns
Compare
Counter
Output Pin
Introduction
In this module, numerical concepts will be explored. One of the first considerations concerns
multiplication – how does the user store the results of a multiplication, when the process of mul-
tiplication creates results larger than the inputs. A similar concern arises when considering accu-
mulation – especially when long summations are performed. Then, IQmath will be described as a
technique for implementing a “virtual floating-point” system to simplify the design process.
The IQmath Library is a collection of highly optimized and high precision mathematical
functions used to seamlessly port floating-point algorithms into fixed-point code. These C/C++
routines are typically used in computationally intensive real-time applications where optimal
execution speed and high accuracy is needed. By using these routines a user can achieve
execution speeds considerable faster than equivalent code written in standard ANSI C language.
In addition, by incorporating the ready-to-use high precision functions, the IQmath library can
shorten significantly a DSP application development time. (The IQmath user's guide is included
in the application zip file, and can be found in the /docs folder once the file is extracted and
installed).
Learning Objectives
Learning Objectives
Module Topics
Numerical Concepts & IQmath ............................................................................................................... 8-1
Binary Numbers
The binary numbering system is the simplest numbering scheme used in computers, and is the
basis for other schemes. Some details about this system are:
• It uses only two values: 1 and 0
• Each binary digit, commonly referred to as a bit, is one “place” in a binary number
and represents an increasing power of 2.
• The least significant bit (LSB) is to the right and has the value of 1.
• Values are represented by setting the appropriate 1's in the binary number.
• The number of bits used determines how large a number may be represented.
Examples:
01102 = (0 * 8) + (1 * 4) + (1 * 2) + (0 * 1) = 610
111102 = (1 * 16) + (1 * 8) + (1 * 4) + (1 * 2) + (0 * 1) = 3010
Examples:
01102 = (0 * -8) + (1 * 4) + (1 * 2) + (0 * 1) = 610
111102 = (1 * -16) + (1 * 8) + (1 * 4) + (1 * 2) + (0 * 1) = -210
The same binary values are used in these examples for two's complement as were used above for
binary. Notice that the decimal value is the same when the MSB is 0, but the decimal value is
quite different when the MSB is 1.
Examples:
Original No. 0 1 1 02 = 610 1 1 1 1 02 = -210
Binary Multiplication
Now that you understand two's complement numbers, consider the process of multiplying two
two's complement values. As with “long hand” decimal multiplication, we can perform binary
multiplication one “place” at a time, and sum the results together at the end to obtain the total
product.
Note: This is not the method the C28x uses in multiplying numbers — it is merely a way of observing
how binary numbers work in arithmetic processes.
The C28x uses 16-bit operands and a 32-bit accumulator. For the sake of clarity, consider the
example below where we shall investigate the use of 4-bit values and an 8-bit accumulation:
0100 4
x 1101 x -3
00000100
0000000
000100
11100
11110100 -12
Accumulator 11110100
11110100
Data Memory ?
Note: With two’s complement multiplication, the leading “1” in the second multiplicand is a
sign bit. If the sign bit is “1”, then take the 2’s complement of the first multiplicand.
Additionally, each partial product must be sign-extended for correct computation.
Note: All of the above questions except the final one are addressed in this module. The last
question may have several answers:
• Store the lower accumulator to memory. What problem is apparent using this
method in this example?
• Store the upper accumulator back to memory. Wouldn't this create a loss of
precision, and a problem in how to interpret the results later?
• Store both the upper and lower accumulator to memory. This solves the above
problems, but creates some new ones:
− Extra code space, memory space, and cycle time are used
− How can the result be used as the input to a subsequent calculation? Is such a
condition likely (consider any “feedback” system)?
From this analysis, it is clear that integers do not behave well when multiplied. Might some other
type of number system behave better? Is there a number system where the results of a
multiplication are bounded?
Binary Fractions
Given the problems associated with integers and multiplication, consider the possibilities of using
fractional values. Fractions do not grow when multiplied, therefore, they remain representable
within a given word size and solve the problem. Given the benefit of fractional multiplication,
consider the issues involved with using fractions:
• How are fractions represented in two's complement?
• What issues are involved when multiplying two fractions?
Four-Bit Multiplication
0100
. 1/2
x 1101
. x - 3/8
00000100
0000000
000100
11100
11110100 -3/16
Accumulator 11110100
11110100
To “read” the result of the fractional multiply, it is necessary to locate the binary point (the base 2
equivalent of the base 10 decimal point). Start by identifying the location of the binary point in
the input values. The MSB is an integer and the next bit is 1/2, therefore, the binary point would
be located between them. In our example, therefore, we would have three bits to the right of the
binary point in each input value. For ease of description, we can refer to these as “Q3” numbers,
where Q refers to the number of places to the right of the point.
When multiplying numbers, the Q values add. Thus, we would (mentally) place a binary point
above the sixth LSB. We can now calculate the “Q6” result more readily.
As with integers, the results are loaded low, and the MSB is a sign extension of the seventh bit. If
this value were loaded into the accumulator, we could store the results back to memory in a
variety of ways:
• Store both low and high accumulator values back to memory. This offers maximum
detail, but has the same problems as with integer multiply.
• Store only the high (or low) accumulator back to memory. This creates a potential for
a memory littered with varying Q-types.
• Store the upper accumulator shifted to the left by 1. This would store values back to
memory in the same Q format as the input values, and with equal precision to the
inputs. How shall the left shift be performed? Here’s three methods:
− Explicit shift (C or assembly code)
− Shift on store (assembly code)
− Use Product Mode shifter (assembly code)
Accumulator 11 11 11 11 00 11 00 00
Redundant
Sign Bit
Fraction Coding
Although COFF tools recognize values in integer, hex, binary, and other forms, they understand
only integer, or non-fractional values. To use fractions within the C28x, it is necessary to describe
them as though they were integers. This turns out to be a very simple trick. Consider the
following number lines:
½ 16K 4000
0
⇒ 0 0000
*32768
–½ –16K C000
–1 –32K 8000
Fractions Integers Hex
By multiplying a fraction by 32K (32768), a normalized fraction is created, which can be passed
through the COFF tools as an integer. Once in the C28x, the normalized fraction looks and
behaves exactly as a fraction. Thus, when using fractional constants in a C28x program, the coder
first multiplies the fraction by 32768, and uses the resulting integer (rounded to the nearest whole
value) to represent the fraction.
The following is a simple, but effective method for getting fractions past the assembler:
1. Express the fraction as a decimal number (drop the decimal point).
2. Multiply by 32768.
3. Divide by the proper multiple of 10 to restore the decimal position.
¾ Examples:
• To represent 0.62: 32768 x 62 / 100
• To represent 0.1405: 32768 x 1405 / 10000
This method produces a valid number accurate to 16 bits. You will not need to do the math
yourself, and changing values in your code becomes rather simple.
Range
Integers have a maximum range
determined by the number of bits
Fractions have a maximum range of ±1
Precision
Integers have a maximum precision of 1
Fractional precision is determined by
the number of bits
The C28x accumulator, a 32-bit register, adds extra range to integer calculations, but this
becomes a problem in storing the results back to 16-bit memory.
Conversely, when using fractions, the extra accumulator bits increase precision, which helps
minimize accumulative errors. Since any number is accurate (at best) to ± one-half of a LSB,
summing two of these values together would yield a worst case result of 1 LSB error. Four
summations produce two LSBs of error. By 256 summations, eight LSBs are “noisy.” Since the
accumulator holds 32 bits of information, and fractional results are stored from the high
accumulator, the extra range of the accumulator is a major benefit in noise reduction for long
sum-of-products type calculations.
IQmath
Implementing complex digital control algorithms on a Digital Signal Processor (DSP), or any
other DSP capable processor, typically come across the following issues:
• Algorithms are typically developed using floating-point math
• Floating-point devices are more expensive than fixed-point devices
• Converting floating-point algorithms to a fixed-point device is very time consuming
• Conversion process is one way and therefore backward simulation is not always possible
Natural development
Simulation
Platform starts with simulation in
Takes many days/weeks (i.e. MatLab) floating-point
to convert (one way
process)
Floating-Point DSP
Fix-Point DSP
The design may initially start with a simulation (i.e. MatLab) of a control algorithm, which
typically would be written in floating-point math (C or C++). This algorithm can be easily ported
to a floating-point device, however because of cost reasons, most likely a 16-bit or 32-bit fixed-
point device would be used in many target systems.
The effort and skill involved in converting a floating-point algorithm to function using a 16-bit or
32-bit fixed-point device is quite significant. A great deal of time (many days or weeks) would
be needed for reformatting, scaling and coding the problem. Additionally, the final
implementation typically has little resemblance to the original algorithm. Debugging is not an
easy task and the code is not easy to maintain or document.
Floating-Point Representation
IEEE Std. 754 Single Precision
Floating-Point
31 30 23 22 0
s eeeeeeee fffffffffffffffffffffff
1 bit sign 8 bit exponent 23 bit mantissa (fraction)
z = 10.000000238 WRONG!
RIGHT?
You cannot represent 10.000000238 with
single-precision floating point
0x412000000 = 10.000000000
10.000000238 ⇐ can’t represent!
0x412000001 = 10.000000950
IQ Fractional Representation
A new approach to fixed-point algorithm development, termed “IQmath”, can greatly simplify the
design development task. This approach can also be termed “virtual floating-point” since it looks
like floating-point, but it is implemented using fixed-point techniques.
IQ Fractional Representation
31 0
S IIIIIIII fffffffffffffffffffffff
32 bit mantissa
.
-2I + 2I-1 + … + 21 + 20 2-1 + 2-2 + … + 2-Q
The IQmath approach enables the seamless portability of code between fixed and floating-point
devices. This approach is applicable to many problems that do not require a large dynamic range,
such as motor or digital control applications.
z = 10.000000238 (0x0A000004)
s Q15 M
ss Q30
s Q15 X
sssssssssssss Q15 s Q15 B
Align Binary
<< 15 Point For Add
ss Q30
sI Q30
Align Binary
>> 15 Point For Store
ssssssssssssI Q15 s Q15 Y
I8 Q24 M
I16 Q48
I8 Q24 X
ssssssssssssssssssI8 Q24 I8 Q24 B
Align Decimal
<< 24 Point for Add
ssssI8 Q48
I16 Q48
Align Decimal
>> 24 Point for Store
sssssssssssssssssI16 Q24 I8 Q24 Y
The traditional approach to performing math operations, using fixed-point numerical techniques
can be demonstrated using a simple linear equation example. The floating-point code for a linear
equation would be:
float Y, M, X, B;
Y = M * X + B;
For the fixed-point implementation, assume all data is 32-bits, and that the "Q" value, or location
of the binary point, is set to 24 fractional bits (Q24). The numerical range and resolution for a
32-bit Q24 number is as follows:
Compared to the floating-point representation, it looks quite cumbersome and has little resem-
blance to the floating-point equation. It is obvious why programmers prefer using floating-point
math.
The slide shows the implementation of the equation on a processor containing hardware that can
perform a 32x32 bit multiplication, 64-bit addition and 64-bit shifts (logical and arithmetic) effi-
ciently.
The basic approach in traditional fixed-point "Q" math is to align the binary point of the operands
that get added to or subtracted from the multiplication result. As shown in the slide, the multipli-
cation of M and X (two Q24 numbers) results in a Q48 value that is stored in a 64-bit register.
The value B (Q24) needs to be scaled to a Q48 number before addition to the M*X value (low
order bits zero filled, high order bits sign extended). The final result is then scaled back to a Q24
number (arithmetic shift right) before storing into Y (Q24). Many programmers may be familiar
with 16-bit fixed-point "Q" math that is in common use. The same example using 16-bit numbers
with 15 fractional bits (Q15) would be coded as follows:
In both cases, the principal methodology is the same. The binary point of the operands that get
added to or subtracted from the multiplication result must be aligned.
IQmath Approach
32-bit IQmath Approach
y = mx + b
I8 Q24 M
I16 Q48
I8 Q24 X
Align Decimal
Point Of Multiply
>> 24
sssssssssssssssssI16 Q24
I8 Q24 B
I8 Q24 I8 Q24 Y
In the "IQmath" approach, rather then scaling the operands, which get added to or subtracted
from the multiplication result, we do the reverse. The multiplication result binary point is scaled
back such that it aligns to the operands, which are added to or subtracted from it. The C code
implementation of this is given by linear equation below:
int32 Y, M, X, B;
Y = ((int64) M * (int64) X) >> 24 + B;
The slide shows the implementation of the equation on a processor containing hardware that can
perform a 32x32 bit multiply, 32-bit addition/subtraction and 64-bit logical and arithmetic shifts
efficiently.
The key advantage of this approach is shown by what can then be done with the C and C++ com-
piler to simplify the coding of the linear equation example.
Lets take an additional step and create a multiply function in C that performs the following opera-
tion:
Y = _IQ24mpy(M , X) + B;
Already we can see a marked improvement in the readability of the linear equation.
Using the operator overloading features of C++, we can overload the multiplication operand "*"
such that when a particular data type is encountered, it will automatically implement the scaled
multiply operation. Lets define a data type called "iq" and assign the linear variables to this data
type:
iq operator * (const iq &M, const iq &X) { return ((int64) M * (int64) X) >> 24; }
Y = M * X + B;
This final equation looks identical to the floating-point representation. It looks "natural". The
four approaches are summarized in the table below:
Essentially, the mathematical approach of scaling the multiplier operand enables a cleaner and a
more "natural" approach to coding fixed-point problems. For want of a better term, we call this
approach "IQmath" or can also be described as "virtual floating-point".
IQmath Approach
Multiply Operation
IQmath Approach
It looks like floating-point!
float Y, M, X, B;
Floating-Point
Y = M * X + B;
long Y, M, X, B;
Traditional
Fix-Point Q Y = ((i64) M * (i64) X + (i64) B << Q)) >> Q;
“IQmath” _iq Y, M, X, B;
In C Y = _IQmpy(M, X) + B;
“IQmath” iq Y, M, X, B;
In C++ Y = M * X + B;
IQmath Approach
GLOBAL_Q simplification
User selects “Global Q” value for the whole application
GLOBAL_Q
based on the required dynamic range or resolution, for example:
GLOBAL_Q Max Val Min Val Resolution
28 7.999 999 996 -8.000 000 000 0.000 000 004
24 127.999 999 94 -128.000 000 00 0.000 000 06
20 2047.999 999 -2048.000 000 0.000 001
The basic "IQmath" approach was adopted in the creation of a standard math library for the Texas
Instruments TMS320C28x DSP fixed-point processor. This processor contains efficient hardware
for performing 32x32 bit multiply, 64-bit shifts (logical and arithmetic) and 32-bit add/subtract
operations, which are ideally suited for 32 bit "IQmath".
Some enhancements were made to the basic "IQmath" approach to improve flexibility. They are:
Setting Of GLOBAL_Q Parameter Value: Depending on the application, the amount of nu-
merical resolution or dynamic range required may vary. In the linear equation example, we used
a Q value of 24 (Q24). There is no reason why any value of Q can't be used. In the "IQmath"
library, the user can set a GLOBAL_Q parameter, with a range of 1 to 30 (Q1 to Q30). All func-
tions used in the program will use this GLOBAL_Q value. For example:
#define GLOBAL_Q 18
Y = _IQmpy(M, X) + B; // all values use GLOBAL_Q = 18
If, for some reason a particular function or equation requires a different resolution, then the user
has the option to implicitly specify the Q value for the operation. For example:
The Q value must be consistent for all expressions in the same line of code.
IQmath Approach
Targeting Fixed-Point or Floating-Point device
Y = _IQmpy(M, X) + B;
User selects target math type
(in “IQmathLib.h” file)
#if MATH_TYPE == IQ_MATH #if MATH_TYPE == FLOAT_MATH
Essentially, the programmer writes the code using the "IQmath" library functions and the code
can be compiled for floating-point or "IQmath" operations.
IQmath Library
IQmath Library: math & trig functions (v1.4)
Operation Floating-Point “IQmath” in C “IQmath” in C++
type float A, B; _iq A, B; iq A, B;
constant A = 1.2345 A = _IQ(1.2345) A = IQ(1.2345)
multiply A*B _IQmpy(A , B) A*B
divide A/B _IQdiv (A , B) A/B
add A+B A+B A+B
substract A-B A-B A–B
boolean >, >=, <, <=, ==, |=, &&, || >, >=, <, <=, ==, |=, &&, || >, >=, <, <=, ==, |=, &&, ||
trig sin(A),cos(A) _IQsin(A), _IQcos(A) IQsin(A),IQcos(A)
functions sin(A*2pi),cos(A*2pi) _IQsinPU(A), _IQcosPU(A) IQsinPU(A),IQcosPU(A)
atan(A),atan2(A,B) _IQatan(A), _IQatan2(A,B) IQatan(A),IQatan2(A,B)
atan2(A,B)/2pi _IQatan2PU(A,B) IQatan2PU(A,B)
sqrt(A),1/sqrt(A) _IQsqrt(A), _IQisqrt(A) IQsqrt(A),IQisqrt(A)
sqrt(A*A + B*B) _IQmag(A,B) IQmag(A,B)
saturation if(A > Pos) A = Pos _IQsat(A,Pos,Neg) IQsat(A,Pos,Neg)
if(A < Neg) A = Neg
Additionally, the "IQmath" library contains DSP library modules for filters (FIR & IIR) and Fast
Fourier Transforms (FFT & IFFT).
With DSP devices like the TMS320C28x processor, which can perform 16 bit and 32 bit sized
math with equal efficiency, the choice becomes more of productivity (time to market). Why
bother spending a whole lot of time trying to code using 16 bit numbers when you can simply use
32 bit numbers, pick one value of "Q" that will accommodate all cases and not worry about
spending too much time optimizing.
Of course there is a concern on data RAM usage if numbers that could be represented in 16 bits
all use 32 bits. This is becoming less of an issue in today's processors because of the finer tech-
nology used and the amount of RAM that can be cheaply integrated. However, in many cases,
this problem can be mitigated by performing intermediate calculations using 32 bit numbers and
converting the input from 16 bit to 32 bit and converting the output from 32 to 16 bit before stor-
ing the final results. In many problems, it is the intermediate calculations that require additional
accuracy to avoid quantization problems.
The "IQmath" approach is ideally suited for applications where a large numerical dynamic range
is not required. Motor control is an example of such an application (audio and communication
algorithms are other applications). As an example, the IQmath approach has been applied to the
sensor-less direct field control of an AC induction motor. This is probably one of the most chal-
lenging motor control problems and as will be shown later, requires numerical accuracy greater
then 16-bits in the control calculations.
The above slide is a block diagram representation of the key control blocks and their interconnec-
tions. Essentially this system implements a "Forward Control" block for controlling the d-q axis
motor current using PID controllers and a "Feedback Control" block using back emf's integration
with compensated voltage from current model for estimating rotor flux based on current and volt-
age measurements. The motor speed is simply estimated from rotor flux differentiation and open-
loop slip computation. The system was initially implemented on a "Simulator Test Bench" which
uses a simulation of an "AC Induction Motor Model" in place of a real motor. Once working, the
system was then tested using a real motor on an appropriate hardware platform.
Each individual block shown in the slide exists as a stand-alone C/C++ module, which can be
interconnected to form the complete control system. This modular approach allows reusability
and portability of the code.
The next few slides shows the coding of one particular block, PARK Transform, using floating-
point and "IQmath" approaches in C and C++:
#include “math.h”
#define TWO_PI 6.28318530717959
void park_calc(PARK *v)
{
float cos_ang , sin_ang;
sin_ang = sin(TWO_PI * v->ang);
cos_ang = cos(TWO_PI * v->ang);
#include “math.h”
#include “IQmathLib.h”
#define TWO_PI _IQ(6.28318530717959)
6.28318530717959
void park_calc(PARK *v)
{
float
_iq cos_ang , sin_ang;
sin_ang = _IQsin(_IQmpy(TWO_PI
sin(TWO_PI * v->ang);, v->ang));
cos_ang = _IQcos(_IQmpy(TWO_PI
cos(TWO_PI * v->ang);, v->ang));
#include “math.h”
extern “C” { #include “IQmathLib.h” }
#include “IQmathCPP.h”
As can be seen, the floating-point C and "IQmath" C++ code looks almost identical. It is quite a
simple and fast procedure to take any floating-point algorithm and convert it to an "IQmath" algo-
rithm.
The complete system was coded using "IQmath". Based on analysis of coefficients in the system,
the largest coefficient had a value of 33.3333. This indicated that a minimum dynamic range of 7
bits (+/-64 range) was required. Therefore, this translated to a GLOBAL_Q value of 32-7 = 25
(Q25). Just to be safe, the initial simulation runs were conducted with GLOBAL_Q = 24 (Q24)
value.
The code was compiled and run on the Texas Instruments TMS320C28x fixed-point DSP device
(IQ_MATH mode) and on the TMS320C3x floating-point DSP device (FLOAT_MATH mode).
The plots of speed and stator current for both devices matched and are shown below.
The plots start from a step change in reference speed from 0.0 to 0.5 and 1024 samples are taken.
The speed eventually settles to the desired reference value and the stator current exhibits a clean
and stable oscillation. The block diagram slide shows at which points in the control system the
plots are taken from.
IQmath: speed
IQmath: current
IQmath: speed
IQmath: current
With the ability to select the GLOBAL_Q value for all calculations in the "IQmath", an experi-
ment was conducted to see what maximum and minimum Q value the system could tolerate be-
fore it became unstable. The results are tabulated in the slide below:
Q18 to Q0 Unstable
(not enough resolution, quantization problems)
The above indicates that, the AC induction motor system that we simulated requires a minimum
of 7 bits of dynamic range (+/-64) and requires a minimum of 19 bits of numerical resolution (+/-
0.000002). This confirms our initial analysis that the largest coefficient value being 33.33333
required a minimum dynamic range of 7 bits. As a general guideline, users using IQmath should
examine the largest coefficient used in the equations and this would be a good starting point for
setting the initial GLOBAL_Q value. Then, through simulation or experimentation, the user can
reduce the GLOBAL_Q until the system resolution starts to cause instability or performance deg-
radation. The user then has a maximum and minimum limit and a safe approach is to pick a mid-
point.
What the above analysis also confirms is that this particular problem does require some calcula-
tions to be performed using greater then 16 bit precision. The above example requires a mini-
mum of 7 + 19 = 26 bits of numerical accuracy for some parts of the calculations. Hence, if one
were implementing the AC induction motor control algorithm using a 16 bit fixed-point DSP, it
would require the implementation of higher precision math for certain portions. This would take
more cycles and programming effort.
The great benefit of using GLOBAL_Q is that the user does not necessarily need to go into de-
tails to assign an individual Q for each variable in a whole system, as is typically done in conven-
tional fixed-point programming. This is time consuming work. By using 32-bit resolution and the
"IQmath" approach, the user can easily evaluate the overall resolution and quickly implement a
typical digital motor control application without quantization problems.
Notes: C28x compiled on CGT V3.03, V1.4c IQmath Lib (debug enabled (-g), max opt).
C3x compiled on CGT V5.12, RTS30R Lib (debug enabled (-g), max opt).
C67x compiled on CGT V4.20, RTSFast Lib (debug enabled (-g)/disabled, max opt).
On C67x, when debug is enabled (-g), parallel execution of operations are limited.
On C28x & C3x, turning off debug (no –g) has minimal impact on performance.
Using the profiling capabilities of the respective DSP tools, the table above summarizes the num-
ber of cycles and code size of the forward and feedback control blocks.
The MIPS used is based on a system sampling frequency of 20kHz, which is typical of such sys-
tems.
The IQmath approach, matched to a fixed-point processor with 32x32 bit capabilities enables the
following:
For uni-polar ADC inputs (i.e., 0 to 3 V inputs), a conversion to global IQ format can be achieved
with:
How can we modify the above to recover bi-polar inputs, for example +-1.5 volts? One could do
the following to offset the +1.5V analog biasing applied to the ADC input:
IQresult_bipolar =
_IQmpy(_IQ(3.0),_IQ16toIQ((_iq) AdcRegs.ADCRESULT0)) - _IQ(1.5);
However, one can see that the largest intermediate value the equation above could reach is 3.0.
This means that it cannot be used with an IQ data type of IQ30 (IQ30 range is -2 < x < ~2). Since
the IQmath library supports IQ types from IQ1 to IQ30, this could be an issue in some applica-
tions.
IQresult_bipolar =
_IQmpy(_IQ(1.5),_IQ15toIQ((_iq) ((int16) (AdcRegs.ADCRESULT0 ^ 0x8000))));
The largest intermediate value that this equation could reach is 1.5. Therefore, IQ30 is easily
supported.
The objective of this lab is to apply the techniques discussed in module 8 and to become familiar
with IQmath programming. In the previous lab, ePWM1A was setup to generate a 2 kHz, 25%
duty cycle symmetric PWM waveform. The waveform was then sampled with the on-chip
analog-to-digital converter. In this lab the sampled waveform will be passed through an IQmath
FIR filter and displayed using the graphing feature of Code Composer Studio.
ePWM1 ADC
TB Counter ADCINA0 RESULT0 IQmath
Compare
Action Qualifier FIR Filter
connector
wire
...
ADC ISR
Display
using CCS
¾ Procedure
Project File
Note: LAB8 files have been provided as a starting point for the lab and need to be
completed. DO NOT copy files from a previous lab.
1. A project named Lab8.pjt has been created for this lab. Open the project by clicking
on Project Æ Open… and look in C:\C28x\Labs\Lab8. All Build Options
have been configured like the previous lab. The files used in this lab are:
Main_8.c Labcfg.cmd
Lab.cdb DSP280x_Headers_BIOS.cmd
User_8_9.cmd CodeStartBranch.asm
SysCtrl.c Gpio.c
DSP280x_GlobalVariableDefs.c PieCtrl_5_6_7_8_9.c
DefaultIsr_8.c Adc.c
EPwm_7_8_9_10.c ECap_7_8_9_10.c
Filter.c DelayUs.asm
;c:\tidcs\c28\IQmath\cIQmath\include
3. Setup the library search path to include the IQmath library. Open the Build Options
and select the linker tab.
a. In the Basic Category, find the Library Search Path (-i) box and enter:
c:\tidcs\c28\IQmath\cIQmath\lib
Include IQmathLib.h
4. Open Lab.h and uncomment the line that includes the IQmathLib.h header file.
Next, in the Function Prototypes section, uncomment the function prototype for IQssfir(),
the IQ math single-sample FIR filter function.
Inspect User_8_9.cmd
5. Open and inspect User_8_9.cmd. First, notice that a section called “IQmath” is
being linked to H0SARAM. The IQmath section contains the IQmath library functions
(code). Second, notice that a section called “IqmathTables” is being linked to the
BOOTROM with a TYPE = NOLOAD modifier after its allocation. The IQmath tables are
used by the IQmath library functions. The NOLOAD modifier allows the linker to
resolve all addresses in the section, but the section is not actually placed into the .out
file. This is done because the section is already present in the device ROM (you cannot
load data into ROM after the device is manufactured!). The tables were put in the ROM
by TI when the device was manufactured. All we need to do is link the section to the
addresses where it is known to already reside (the tables are the very first thing in the
BOOT ROM, starting at address 0x3FF000).
Recall that this Q type will provide 8 integer bits and 24 fractional bits. Dynamic range
is therefore -128 < x < +128, which is sufficient for our purposes in the workshop.
Note: For the next step, check to be sure that the jumper wire connecting PWM1A (pin # P8-9)
to ADCINA0 (pin # P9-2) is in place on the eZdsp™.
10. Run the code in real-time mode using the GEL function: GEL Æ Realtime
Emulation Control Æ Run_Realtime_with_Reset, and watch the memory
window update. Verify that the ADC result buffer contains updated values.
11. Open and setup a dual time graph to plot a 50-point window of the filtered and unfiltered
ADC results buffer. Click: View Æ Graph Æ Time/Frequency… and set the
following values:
Q-value 24
12. The graphical display should show the generated IQmath FIR filtered 2 kHz, 25% duty
cycle symmetric PWM waveform in the upper display and the unfiltered waveform
generated in the previous lab exercise in the lower display. Notice the shape and phase
differences between the waveform plots (the filtered curve has rounded edges, and lags
the unfiltered plot by several samples). The amplitudes of both plots should run from 0
to 3.0.
13. Open and setup two (2) frequency domain plots – one for the filtered and another for the
unfiltered ADC results buffer. Click: View Æ Graph Æ Time/Frequency…
and set the following values:
GRAPH #1 GRAPH #2
FFT Framesize 50 50
Q-value 24 24
14. The graphical displays should show the frequency components of the filtered and
unfiltered 2 kHz, 25% duty cycle symmetric PWM waveforms. Notice that the higher
frequency components are reduced using the Low-Pass IQmath FIR filter in the filtered
graph as compared to the unfiltered graph.
15. Fully halt the DSP (real-time mode) by using the GEL function: GEL Æ Realtime
Emulation Control Æ Full_Halt.
End of Exercise
Introduction
This module discusses the basic features of using DSP/BIOS in a system. Scheduling threads,
periodic functions, and the use of real-time analysis tools will be demonstrated.
Learning Objectives
Learning Objectives
Introduction to DSP/BIOS
Periodic Functions
Module Topics
Using DSP/BIOS........................................................................................................................................ 9-1
Introduction to DSP/BIOS
Introduction to DSP/BIOS
What is DSP/BIOS?
A full-featured, scalable real-time kernel
System configuration tools
Preemptive multi-threading scheduler
Real-time analysis tools
void main(void)
{
/*** Initialization ***/
. . .
/*** Enable global interrupts ***/
// DSP/BIOS will enable global interrupts
/*** Main Loop ***/
// while() loop removed to enable DSP/BIOS
} //end of main()
SWI Properties
int2 rtn
SWI 2
rtn
SWI 1
rtn
MAIN
int1
IDLE
(lowest)
User sets the priority...BIOS does the scheduling
start
SEM_pend Pause
“run to (blocked
completion” state)
start
end end
Periodic Functions
Using Periodic Functions - PRD
tick
DSP/BIOS
CLK
period
period
Execution Graph
Software logic analyzer
Debug event timing
and priority
Message LOG
Send debug msgs to host
Doesn’t halt the DSP
Deterministic, low DSP
cycle count
More efficient than
traditional printf()
Lab 9: DSP/BIOS
¾ Objective
The objective of this lab is to apply the techniques discussed in module 9 and to become familiar
with DSP/BIOS. In this lab exercise, we are going to change the ADCINT_ISR HWI to a SWI.
Then, we will replace the LED blink routine with a Periodic Function. Also, some features of the
real-time analysis tools will be demonstrated.
Lab 9: DSP/BIOS
ePWM1 ADC
TB Counter ADCINA0 RESULT0 IQmath
Compare
Action Qualifier FIR Filter
connector
wire
pointer rewind
Objective: CPU copies
result to
buffer during
Change ADCINT_ISR
...
ADC ISR
HWI to SWI
Replace LED blink Display
routine with a using CCS
Periodic Function
It will be interesting to investigate the DSP computational burden of the various parts of our
application, as well as the different pieces of DSP/BIOS that we will be using in this lab.
The ‘CPU Load Graph’ feature of DSP/BIOS will provide a quick and easy method for doing
this. We will be tabulating these results in the table that follows at various steps throughout the
remainder of this lab.
¾ Procedure
Project File
Note: LAB9 files have been provided as a starting point for the lab and need to be
completed. DO NOT copy files from a previous lab.
1. A project named Lab9.pjt has been created for this lab. Open the project by clicking
on Project Æ Open… and look in C:\C28x\Labs\Lab9. All Build Options
have been configured like the previous lab. The files used in this lab are:
Main_9.c Labcfg.cmd
Lab.cdb DSP280x_Headers_BIOS.cmd
User_8_9.cmd CodeStartBranch.asm
SysCtrl.c Gpio.c
DSP280x_GlobalVariableDefs.c PieCtrl_5_6_7_8_9.c
DefaultIsr_9.c Adc.c
EPwm_7_8_9_10.c ECap_7_8_9_10.c
Filter.c DelayUs.asm
4. In Main_9.c, remove the endless while() loop from the end of main(). When using
DSP/BIOS, you must return from main(). In all DSP/BIOS programs, the main()
function should contain all one-time user-defined initialization functions. DSP/BIOS will
then take-over control of the software execution.
6. We will be running our code in real-time mode, and will have our window continuously
refresh. Run in Real-time Mode using the GEL function: GEL Æ Realtime
Emulation Control Æ Run_Realtime_with_Reset.
Note: For the next step, check to be sure that the jumper wire connecting PWM1A (pin # P8-9)
to ADCINA0 (pin # P9-2) is still in place on the eZdsp™.
7. Open and setup a dual time graph to plot a 50-point window of the filtered and unfiltered
ADC results buffer. Click: View Æ Graph Æ Time/Frequency… and set the
following values:
Q-value 24
8. The graphical display should show the generated IQmath FIR filtered 2 kHz, 25% duty
cycle symmetric PWM waveform in the upper display and the unfiltered waveform
generated in the previous lab exercise in the lower display. The results should be the
same as the previous lab.
Fully halt the DSP (real-time mode) by using the GEL function: GEL Æ Realtime
Emulation Control Æ Full_Halt.
9. Open the RTA Control Panel by clicking DSP/BIOS Æ RTA Control Panel.
Uncheck ALL of the boxes. This disables most of the realtime analysis tools. We will
selectively enable them later in the lab.
10. Open the CPU Load Graph by clicking DSP/BIOS Æ CPU Load Graph. The CPU
load graph displays the percentage of available CPU computing horsepower that the
application is consuming. The CPU may be running ISRs, software interrupts, periodic
functions, performing I/O with the host, or running any user routine. When the CPU is
not executing user code, it will be idle (in the DSP/BIOS idle thread).
Run the code (real-time mode) by using the GEL function: GEL Æ Realtime
Emulation Control Æ Run_Realtime_with_Reset.
This graph should start updating, showing the percentage load on the DSP CPU. Keep
the DSP running to complete steps 11 through 14.
11. Open and inspect DefaultIsr_9.c. Notice that the global variable DEBUG_FILTER
is used to control the FIR filter in ADCINT_ISR(). If DEBUG_FILTER = 1, the FIR
filter is called and the AdcBufFilter array is filled with the filtered data. On the other
hand, if DEBUG_FILTER = 0, the filter is not called and the AdcBufFilter array is
filled with the unfiltered data.
12. Open the watch window and add the variable DEBUG_FILTER to it. Change its value
to “0” to turn off the FIR filtering. Notice the decrease in the CPU Load Graph.
13. Record the value shown in the CPU Load Graph under “Case #1” in Table 9-1.
14. Change the value of DEBUG_FILTER back to “1” in the watch window in order to bring
the FIR filter back online. Notice the jump in the CPU Load Graph.
15. Record the value shown in the CPU Load Graph under “Case #2” in Table 9-1.
16. Fully halt the DSP (real-time mode) by using the GEL function: GEL Æ Realtime
Emulation Control Æ Full_Halt.
Create a SWI
17. Open Main_9.c and notice that space has been added at the end of main() for two new
functions which will be used in this module – AdcSwi() and LedBlink(). In the next few
steps, we will move part of the ADCINT_ISR() routine from DefaultIsr_9.c to this
space in Main_9.c.
18. Open DefaultIsr_9.c and locate the ADCINT_ISR() routine. Move the entire
contents of the ADCINT_ISR() routine to the AdcSwi() function in Main_9.c with the
following exceptions:
DO NOT MOVE:
Be sure to move the static local variable declaration at the top of ADCINT_ISR() that is
used to index into the ADC buffers.
Comment: In almost all appplications, the PIE group acknowledge code is left in the HWI
(rather than move it to a SWI). This allows other interrupts to occur on that PIE group
even if the SWI has not yet executed. On the other hand, we are leaving the GPIO and
LED toggle code in the HWI just as an example. It illustrates that you can post a SWI
and also do additional operations in the HWI. DSP/BIOS is extremely flexible!
Move the entire section contents that follow (e.g., all of the global variables, constant
definitions, and filter coefficients) to the space provided in Main_9.c, with the
following exception:
DO NOT MOVE:
20. Delete the interrupt key word from the ADCINT_ISR. The interrupt keyword is not
used when a HWI is under DSP/BIOS control. A HWI is under DSP/BIOS control when
it uses any DSP/BIOS functionality, such as posting a SWI, or calling any DSP/BIOS
function or macro.
Post a SWI
21. In DefaultIsr_9.c add the following SWI_post to the ADCINT_ISR(), just after the
structure used to acknowledge the PIE group:
This posts a SWI that will execute the ADC_swi() code you populated a few steps back
in the lab. In other words, the ADC interrupt still executes the same code as before.
However, most of that code is now in a posted SWI that DSP/BIOS will execute
according to the specified scheduling priorities.
23. Right click on SWI – Software Interrupt Manager and select Insert SWI.
SWI0 will be added. Right-click on it, and rename it to ADC_swi. This is just an
arbitrary name. We want to differentiate the AdcSwi() function itself (which is nothing
but an ordinary C function) from the DSP/BIOS SWI object which we are calling
ADC_swi.
24. Select the Properties for ADC_swi and type _AdcSwi (with a leading underscore)
in the function field. Click OK. This tells DSP/BIOS that it should run the function
AdcSwi() when it executes the ADC_swi SWI.
25. We need to have the PIE for the ADC interrupt use the dispatcher. The dispatcher will
automatically perform the context save and restore, and allow the DSP/BIOS scheduler to
have insight into the ISR. You may recall from an earlier lab that the ADC interrupt is
located at PIE_INT1_6.
Click on the plus sign (+) to the left of HWI – Hardware Interrupt Service
Routine Manager. Click the plus sign (+) to the left of PIE INTERRUPTS. Locate
the interrupt location for the ADC: PIE_INT1_6. Right click, select Properties, and
select the Dispatcher tab.
Now check the “Use Dispatcher” box and select OK. Close the configuration file
and click YES to save changes.
28. Confirm that the graphical display is showing the correct results. The results should be
the same as before (i.e., filtered PWM in the upper graph, unfiltered PWM in the lower
graph).
29. Record the value shown in the CPU Load Graph under “Case #3” in Table 9-1.
30. Fully halt the DSP (real-time mode) by using the GEL function: GEL Æ Realtime
Emulation Control Æ Full_Halt.
31. Open DefaultIsr_9.c and locate the ADCINT_ISR routine. Move the instruction
used to toggle the LED to the LedBlink() function in Main_9.c:
Now delete from the ADCINT_ISR() the code used to implement the interval counter for
the LED toggle (i.e., the GPIO34_count++ loop), and also delete the declaration of the
GPIO34_count itself from the beginning of ADCINT_ISR(). These are no longer
needed, as DSP/BIOS will implement the interval counter for us in the periodic function
configuration (next step in the lab).
32. In the configuration file Lab.cdb we need to add and setup the LedBlink_PRD. Open
Lab.cdb and click on the plus sign (+) to the left of Scheduling. Right click on
PRD – Periodic Function Manger and select Insert PRD. PRD0 will be
added. Right-click on it and rename it to LedBlink_PRD.
Select the Properties for LedBlink_PRD and type _LedBlink (with a leading
underscore) in the function field. This tells DSP/BIOS to run the LedBlink() function
when it executes the LedBlink_PRD periodic function object.
Next, in the period (ticks) field type 500. The default DSP/BIOS system timer
increments every 1 millisecond, so what we are doing is telling the DSP/BIOS scheduler
to schedule the LedBlink() function to execute every 500 milliseconds. A PRD object is
just a special type of SWI which gets scheduled periodically and runs in the context of
the SWI level at a specified SWI priority. Click OK. Close the configuration file and
click YES to save changes.
35. Record the value shown in the CPU Load Graph under “Case #4” in Table 9-1.
36. When done, fully halt the DSP (real-time mode) by using the GEL function: GEL Æ
Realtime Emulation Control Æ Full_Halt. If you would like, experiment
with different period (tick) values and notice that the blink rate changes.
We have actually been already using one piece of the RTA tools in this lab: the CPU Load Graph.
We will now utilize two other basic items from the RTA toolbox.
37. In the next few steps the Log Event Manager will be setup to capture an event in real-
time while the program executes. We will be using LOG_printf() to write to a log
Add the following to Main_9.c just after the static local variable declaration in
AdcSwi():
38. In the configuration file Lab.cdb we need to add and setup the trace buffer. Open
Lab.cdb and click on the plus sign (+) to the left of Instrumentation and again on
the plus sign (+) to the left of LOG – Event Log Manager.
39. Right click on LOG – Event Log Manager and select Insert LOG. LOG0 will
be added. Right-click on it and rename it to trace.
40. Select the Properties for trace and set the logtype to circular and the datatype to
printf. Click OK. Close the configuration file and click YES to save changes.
41. Since the configuration file was modified, we need to rebuild the project. Click the
“Build” button.
The message log dialog box is displaying the commanded LOG_printf() output, i.e. the
number of times (count value) that the AdcSwi() has executed.
44. Verify that all the check boxes in the RTA Control Panel window are still unchecked
(from step 9). Then, check the box marked “Global Host Enable.” This is the main
control switch for most of the RTA tools. We will be selectively enabling the rest of the
check boxes in this portion of the exercise.
45. Record the value shown in the CPU Load Graph under “Case #5” in Table 9-1.
Presently, the execution graph is not displaying anything. This is because we have it
disabled in the RTA Control Panel.
In the RTA Control Panel, check the top four boxes to enable logging of all event types to
the execution graph. Notice that the Execution Graph is now displaying information
about the execution threads being taken by your software. This graph is not based on
time, but the activity of events (i.e. when an event happens, such as a SWI or periodic
function begins execution). Notice that the execution graph simply records DSP/BIOS
CLK events along with other system events (the DSP/BIOS clock periodically triggers
the DSP/BIOS scheduler). As a result, the time scale on the execution graph is not linear.
The logging of events to the execution graph consumes CPU cycles, which is why the
CPU Load Graph jumped as you enabled logging.
47. Record the value shown in the CPU Load Graph under “Case #6” in Table 9-1.
48. Open the Statistics View window. On the menu bar, click:
Presently, the statistics view window is not changing with the exception of the statistics
for the IDL_busyObj row (i.e., the idle loop). This is because we have it disabled in the
RTA Control Panel.
In the RTA Control Panel, check the next five boxes (i.e., those with the word
“Accumulator” in their description) to enable logging of statistics to the statistics view
window. The logging of statistics consumes CPU cycles, which is why the CPU Load
Graph jumped as you enabled logging.
49. Record the value shown in the CPU Load Graph under “Case #7” in Table 9-1.
50. Table 9-1 should now be completely filled in. Think about the results. Your instructor
will discuss them when the lecture starts again.
51. Fully halt the DSP (real-time mode) by using the GEL function: GEL Æ Realtime
Emulation Control Æ Full_Halt.
Note: In this module only the basic features of DSP/BIOS and the real-time analysis tools have
been used. For more information and details, please refer to the DSP/BIOS user’s
manuals and other DSP/BIOS related training.
End of Exercise
Introduction
This module discusses various aspects of system design. Details of the emulation and analysis
block along with JTAG will be explored. Flash memory programming and the Code Security
Module will be described.
Learning Objectives
Learning Objectives
Flash Programming
Module Topics
System Design ...........................................................................................................................................10-1
Module Topics........................................................................................................................................10-2
Emulation and Analysis Block ...............................................................................................................10-3
Flash Configuration and Memory Performance ....................................................................................10-7
Flash Programming .............................................................................................................................10-10
Code Security Module (CSM) ..............................................................................................................10-12
Lab 10: Programming the Flash..........................................................................................................10-16
SCAN IN
Emulator TMS320F2000
Pod
H
E
Some Available Emulators A
D
Signum System JTAGjet-TMS-C2000
E
Spectrum Digital XDS510PP+ TMS320F2000
R
Spectrum Digital XDS510USB
Spectrum Digital PCI
BlackHawk USB
DSP Research PCI / USB / PCMCIA SCAN OUT
Multiprocessor Connections
JTAG Device JTAG Device
TDO TDI TDO TDI Vcc
Vcc
EMU0
EMU1
EMU0
EMU1
TRST
TRST
TMS
TMS
TCK
TCK Emulator Header
13 5
EMU0 PD
14
EMU1
2 4
TRST GND
1 6
TMS GND
3 8
TDI GND
7 10
TDO GND
11 12
TCK GND
9 GND
TCK_RET
Chained
breakpoint
selection
Bus selection
15 4 3 0
16
16 or 32
64 dispatched
64 C28x Core
decoder unit
Aligned 2-level deep
64-bit fetch buffer
fetch
Flash Pipeline Enable
0 = disable (default)
1 = enable
FlashRegs.FOPT.bit.ENPIPE = 1;
15 1 0
reserved ENPIPE
Internal RAM 1 1
Flash Programming
Flash Programming Basics
The DSP CPU itself performs the flash programming
The CPU executes Flash utility code from RAM that reads the
Flash data and writes it into the Flash
We need to get the Flash utility code and the Flash data into RAM
FLASH CPU
Flash
Utility
Code Emulator JTAG
RAM
RS232 SCI
SPI
Bootloader
ROM
Flash I2C
Data
eCAN
GPIO
F280x DSP
Algorithm Function
1. Erase - Set all bits to zero, then to one
2. Program - Program selected bits with zero
3. Verify - Verify flash contents
CSM Password
0x3E 8000
CSM Registers
Key Registers – accessible by user; EALLOW protected
Address Name Reset Value Description
0x00 0AE0 KEY0 0xFFFF Low word of 128-bit Key register
0x00 0AE1 KEY1 0xFFFF 2nd word of 128-bit Key register
0x00 0AE2 KEY2 0xFFFF 3rd word of 128-bit Key register
0x00 0AE3 KEY3 0xFFFF 4th word of 128-bit Key register
0x00 0AE4 KEY4 0xFFFF 5th word of 128-bit Key register
0x00 0AE5 KEY5 0xFFFF 6th word of 128-bit Key register
0x00 0AE6 KEY6 0xFFFF 7th word of 128-bit Key register
0x00 0AE7 KEY7 0xFFFF High word of 128-bit Key register
0x00 0AEF CSMSCR 0xFFFF CSM status and control register
PWL in memory – reserved for passwords only
Address Name Reset Value Description
0x3F 7FF8 PWL0 user defined Low word of 128-bit password
0x3F 7FF9 PWL1 user defined 2nd word of 128-bit password
0x3F 7FFA PWL2 user defined 3rd word of 128-bit password
0x3F 7FFB PWL3 user defined 4th word of 128-bit password
0x3F 7FFC PWL4 user defined 5th word of 128-bit password
0x3F 7FFD PWL5 user defined 6th word of 128-bit password
0x3F 7FFE PWL6 user defined 7th word of 128-bit password
0x3F 7FFF PWL7 user defined High word of 128-bit password
CSM Caveats
Never program all the PWL’s as 0x0000
Doing so will permanently lock the CSM
Flash addresses 0x3F7F80 to 0x3F7FF5,
inclusive, must be programmed to 0x0000 to
securely lock the CSM
Remember that code running in unsecured
RAM cannot access data in secured memory
Don’t link the stack to secured RAM if you have
any code that runs from unsecured RAM
Do not embed the passwords in your code!
Generally, the CSM is unlocked only for debug
Code Composer Studio can do the unlocking
Device unlocked
Correct Yes
password? User can access on-
chip secure memory
No
The objective of this lab is to use the techniques discussed in module 10 and program the on-chip
flash memory. The TMS320F2808 device has been designed for standalone operation in an
embedded system. Using the on-chip flash eliminates the need for external non-volatile memory
or a host processor from which to bootload. In this lab, the steps required to properly configure
the software for execution from internal flash memory will be covered.
ePWM1 ADC
TB Counter ADCINA0 RESULT0 IQmath
Compare
Action Qualifier FIR Filter
connector
wire
...
ADC ISR
Memory
Learn use of CCS Flash
Plug-in Display
using CCS
DO NOT PROGRAM
PASSWORDS
¾ Procedure
Project File
Note: LAB10 files have been provided as a starting point for the lab and need to be
completed. DO NOT copy files from a previous lab.
1. A project named Lab10.pjt has been created for this lab. Open the project by
clicking on Project Æ Open… and look in C:\C28x\Labs\Lab10. All Build
Options have been configured like the previous lab. The files used in this lab are:
Main_10.c Labcfg.cmd
Lab.cdb DSP280x_Headers_BIOS.cmd
User_10.cmd CodeStartBranch.asm
SysCtrl.c Gpio.c
DSP280x_GlobalVariableDefs.c PieCtrl_10.c
DefaultIsr_10.c Adc.c
EPwm_7_8_9_10.c ECap_7_8_9_10.c
Filter.c DelayUs.asm
Each initialized section actually has two addresses associated with it. First, it has a LOAD
address which is the address to which it gets loaded at load time (or at flash programming time).
Second, it has a RUN address which is the address from which the section is accessed at runtime.
The linker assigns both addresses to the section. Most initialized sections can have the same
LOAD and RUN address in the flash. However, some initialized sections need to be loaded to
flash, but then run from RAM. This is required, for example, if the contents of the section needs
to be modified at runtime by the code.
2. This step assigns the RUN address of those sections that need to run from flash. Using
the memory section manager in the DSP/BIOS configuration tool (Lab.cdb) link the
following sections to on-chip flash memory:
.sysinit .switch
.hwi .cinit
.rtdx_text .pinit
.econst / .const
.data
3. This step assigns the LOAD address of those sections that need to load to flash. Again
using the memory section manager in the DSP/BIOS configuration tool (Lab.cdb),
select the Load Address tab and check the “Specify Separate Load
Addresses” box. Then set all entries to the flash memory block.
4. The section named “IQmath” is an initialized section that needs to load to and run from
flash. Recall that this section is not linked using the DSP/BIOS configuration tool
(Lab.cdb). Instead, this section is linked with the user linker command file
(User_10.cmd). Open and inspect User_10.cmd. Previously the “IQmath”
section was linked to H0SARAM. Notice that this section is now linked to FLASH.
5. Open and inspect InitPieCtrl() (in PieCtrl_10.c file). Notice the memcpy() function
and the symbols used to initialize (copy) the .hwi_vec section.
The copying of .trcdata must be performed prior to main(). This is because DSP/BIOS modifies
the contents of .trcdata during DSP/BIOS initialization, which also occurs prior to main(). The
DSP/BIOS configuration tool provides a user initialization function which will be used to
perform the .trcdata section copy prior to both main() and DSP/BIOS initialization.
6. Open the DSP/BIOS configuration file (Lab.cdb) and select the Properties for the
Global Settings. Check the box “Call User Init Function” and enter
the UserInit() function name with a leading underscore: _UserInit. This will
cause the function UserInit() to execute prior to main().
7. Open and inspect the file Main_10.c. Notice that the function UserInit() is used
to copy the .trcdata section from its load address to its run address before main().
9. Open and inspect Flash.c. The C compiler CODE_SECTION pragma is used to place
the InitFlash() function into a linkable section named “secureRamFuncs”.
10. Since the DSP/BIOS configuration tool does not know about user defined sections, the
“secureRamFuncs” section will be linked using the user linker command file
User_10.cmd. Open and inspect User_10.cmd. The “secureRamFuncs” will
load to flash (load address) but will run from L1SARAM (run address). Also notice that
the linker has been asked to generate symbols for the load start, load end, and run start
addresses.
While not a requirement from a DSP hardware perspective (since the C28x DSP has a
unified memory architecture), Code Composer Studio generally prefers code to be linked
to program space (and data to be linked to data space). Therefore, notice that for the
L1SARAM memory we are linking “secureRamFuncs” to, we are specifiying
“PAGE = 0”(which is program space). The L1SARAM memory is currently defined in
data space in the Lab.cdb, but in the next step we will redefine it to exist in the
program space.
11. Using the DSP/BIOS configuration tool (Lab.cdb) modify the entry for L1SARAM so
that it is defined in the program space (code).
12. Open and inspect Main_10.c. Notice that the memory copy function memcpy() is
being used to copy the section “secureRamFuncs, which contains the initialization
function for the flash control registers.
13. Add a line of code to main() to call the InitFlash() function. There are no passed
parameters or return values. You just type
InitFlash();
The CSM module also requires programming values of 0x0000 into flash addresses 0x3F7F80
through 0x3F7FF5 in order to properly secure the CSM. Both tasks will be accomplished using a
simple assembly language program Passwords.asm.
15. Open and inspect Passwords.asm. This file specifies the desired password values
(DO NOT CHANGE THE VALUES FROM 0xFFFF) and places them in an initialized
section named “passwords”. It also creates an initialized section named
“csm_rsvd” which contains all 0x0000 values for locations 0x3F7F80 to 0x3F7FF5
(length of 0x76).
16. Open User_10.cmd and notice that the initialized sections for “passwords” and
“csm_rsvd” are linked to memories named PASSWORDS and CSM_RSVD,
respectively.
17. Using the DSP/BIOS configuration tool (Lab.cdb) define memory blocks for
PASSWORDS and CSM_RSVD. You will need to setup the MEM Properties for each
memory block with the proper base address and length. Set the space to code for both
memory blocks. (Uncheck the “create a heap in this memory” box for each block). You
may also need to modify the existing flash memory block to avoid conflicts. If needed, a
slide is available at the end of this lab showing the base address and length for the
memory blocks.
18. Open and inspect CodeStartBranch.asm. This file creates an initialized section
named “codestart” that contains a long branch to the C-environment setup routine.
This section needs to be placed in memory using the DSP/BIOS configuration tool.
19. Using the DSP/BIOS configuration tool (Lab.cdb) define a memory space named
BEGIN_FLASH.
20. Setup the MEM Properties with the proper base address, length, and space.
(Uncheck the “create a heap in this memory” box). Be sure to avoid memory section
conflicts. If needed, a slide is available at the end of this lab showing the base address
and length for the memory block.
21. In the earlier lab exercises, the section “codestart” was directed to the memory
named BEGIN_M0. Open and modify User_10.cmd so that the section
“codestart” will be directed to BEGIN_FLASH.
22. The eZdsp™ board needs to be configured for “Jump to Flash” bootmode. Move switch
SW1 positions 1, 2 and 3 to the “open” position to accomplish this. Details of switch
positions can be found in Appendix A. This switch controls the pullup/down resistor on
the GPIO18, GPIO29, and GPIO34 pins, which are the pins sampled by the bootloader to
determine the bootmode. (For additional information on configuring the “Jump to Flash”
bootmode see the TMS320x280x DSP Boot ROM Reference Guide, and also the eZdsp
F2808 Technical Reference).
Build – Lab.out
23. At this point we need to build the project, but not have CCS automatically load it since
CCS cannot load code into the flash! (the flash must be programmed). On the menu bar
click: Option Æ Customize… and select the “Program/Project Load” tab.
Uncheck “Load Program After Build”.
CCS has a feature that automatically steps over functions without debug information.
This can be useful for accelerating the debug process provided that you are not interested
in debugging the function that is being stepped-over. While single-stepping in this lab
exercise we do not want to step-over any functions. Therefore, select the “Debug
Properties” tab. Uncheck “Step over functions without debug
information when source stepping”, then click OK.
24. Click the “Build” button to generate the Lab.out file to be used with the CCS Flash
Plug-in.
26. Notice that the eZdsp™ board uses a 20 MHz oscillator (located on the board near LED
DS2). Confirm the “Clock Configuration” in the upper left corner has the OSCCLK set
to 20 MHz and the PLLCR value is set to 10. Recall that the PLL is divided by two,
which gives a SYSCLKOUT of 100 MHz.
27. Confirm that all boxes are checked in the “Erase Sector Selection” area of the plug-in
window. We want to erase all the flash sectors.
28. We will not be using the plug-in to program the “Code Security Password”. Do not
modify the Code Security Password fields.
29. In the “Operation” block, notice that the “COFF file to Program/Verify” field
automatically defaults to the current .out file. Check to be sure that “Erase, Program,
Verify” is selected. We will be using the default wait states, as shown on the slide in this
module.
30. Click “Execute Operation” to program the flash memory. Watch the programming status
update in the plug-in window.
31. After successfully programming the flash memory, close the programmer window.
33. Reset the DSP. The program counter should now be at 0x3FFB50, which is the start of
the bootloader in the Boot ROM.
34. Single-Step <F11> through the bootloader code until you arrive at the beginning of the
codestart section in the CodeStartBranch.asm file. (Be patient, it will take about
65 single-steps). Notice that we have placed some code in CodeStartBranch.asm
to give an option to first disable the watchdog, if selected.
35. Step a few more times until you reach the start of the C-compiler initialization routine at
the symbol _c_int00.
36. Now do Debug Æ Go Main. The code should stop at the beginning of your main()
routine. If you got to that point succesfully, it confirms that the flash has been
programmed properly, and that the bootloader is properly configured for jump to flash
mode, and that the codestart section has been linked to the proper address.
37. You can now RUN the DSP, and you should observe the LED on the board blinking. Try
resetting the DSP and hitting RUN (without doing all the stepping and the Go Main
procedure). The LED should be blinking again.
39. Disconnect the emulator (USB cable) from the eZdsp™ board.
42. The LED should be blinking, showing that the code is now running from flash memory.
44. Please return the settings of switch SW1 back to the default positions “Jump to
M0SARAM” bootmode (see Appendix A for switch position details):
End of Exercise
base =
0x3E 8000
FLASH
len = 0xFF80
space = code User_10.cmd
SECTIONS
{
0x3F 7F80 codestart :> BEGIN_FLASH, PAGE = 0
CSM_RSVD
len = 0x76 passwords :> PASSWORDS, PAGE = 0
space = code csm_rsvd :> CSM_RSVD, PAGE = 0
0x3F 7FF6
BEGIN_FLASH }
len = 0x2
space = code
0x3F 7FF8 PASSWORDS
len = 0x8
space = code
RESET
Introduction
The TMS320C28x contains features that allow several methods of communication and data
exchange between the C28x and other devices. Many of the most commonly used
communications techniques are presented in this module.
The intent of this module is not to give exhaustive design details of the communication
peripherals, but rather to provide an overview of the features and capabilities. Once these
features and capabilities are understood, additional information can be obtained from various
resources such as documentation, as needed. This module will cover the basic operation of the
communication peripherals, as well as some basic terms and how they work.
Learning Objectives
Learning Objectives
Module Topics
Communications.......................................................................................................................................11-1
Module Topics........................................................................................................................................11-2
Communications Techniques .................................................................................................................11-3
Serial Peripheral Interface (SPI) ...........................................................................................................11-4
SPI Registers .....................................................................................................................................11-7
SPI Summary.....................................................................................................................................11-8
Serial Communications Interface (SCI) .................................................................................................11-9
Multiprocessor Wake-Up Modes.....................................................................................................11-11
SCI Registers ...................................................................................................................................11-14
SCI Summary ..................................................................................................................................11-15
Inter-Integrated Circuit (I2C)..............................................................................................................11-16
I2C Operating Modes and Data Formats .........................................................................................11-17
I2C Summary...................................................................................................................................11-18
Enhanced Controller Area Network (eCAN) .......................................................................................11-19
CAN Bus and Node .........................................................................................................................11-20
Principles of Operation....................................................................................................................11-21
Message Format and Block Diagram...............................................................................................11-22
eCAN Summary ..............................................................................................................................11-23
Communications Techniques
Several methods of implementing a TMS320C28x communications system are possible. The
method selected for a particular design should reflect the method that meets the required data rate
at the lowest cost. Various categories of interface are available and are summarized in the
learning objective slide. Each will be described in this module.
C28x C28x
Port U2 Port
Destination
PCB PCB
In a multiprocessing system, they are an excellent choice when both devices have an available
serial port and the data rate requirement is relatively low. Serial interface is even more desirable
when the devices are physically distant from each other because the inherently low number of
wires provides a simpler interconnection.
Serial ports require separate lines to implement, and they do not interfere in any way with the data
and address lines of the processor. The only overhead they require is to read/write new words
from/to the ports as each word is received/transmitted. This process can be performed as a short
interrupt service routine under hardware control, requiring only a few cycles to maintain.
The C28x family of devices have both synchronous and asynchronous serial ports. Detailed
features and operation will be described next.
In its simplest form, the SPI can be thought of as a programmable shift register. Data is shifted in
and out of the SPI through the SPIDAT register. Data to be transmitted is written directly to the
SPIDAT register, and received data is latched into the SPIBUF register for reading by the CPU.
This allows for double-buffered receive operation, in that the CPU need not read the current
received data from SPIBUF before a new receive operation can be started. However, the CPU
must read SPIBUF before the new operation is complete of a receiver overrun error will occur. In
addition, double-buffered transmit is not supported: the current transmission must be complete
before the next data character is written to SPIDAT or the current transmission will be corrupted.
The Master can initiate a data transfer at any time because it controls the SPICLK signal. The
software, however, determines how the Master detects when the Slave is ready to broadcast.
SPI
SPIShift
ShiftRegister
Register SPI
SPIShift
ShiftRegister
Register
clock
RX FIFO_15
SPIRXBUF.15-0
MSB LSB
SPIDAT.15-0 SPISOMI
SPITXBUF.15-0
TX FIFO_0
TX FIFO_15
4. MSB of the Master’s shift register (SPIDAT) is shifted out, and LSB of the Slave’s shift
register (SPIDAT) is loaded
9. If data is in SPITXBUF (either Slave or Master), it is loaded into SPIDAT and transmission
starts again as soon as the Master’s SPIDAT is loaded
Since data is shifted out of the SPIDAT register MSB first, transmission characters of less than 16
bits must be left-justified by the CPU software prior to be written to SPIDAT.
Received data is shifted into SPIDAT from the left, MSB first. However, the entire sixteen bits
of SPIDAT is copied into SPIBUF after the character transmission is complete such that received
characters of less than 16 bits will be right-justified in SPIBUF. The non-utilized higher
significance bits must be masked-off by the CPU software when it interprets the character. For
example, a 9 bit character transmission would require masking-off the 7 MSB’s.
Programmable data
length of 1 to 16 bits
Transmitted data of less SPIDAT - Processor #1
than 16 bits must be left 11001001XXXXXXXX
justified 11001001XXXXXXXX
MSB transmitted first
SPI Registers
SPI Baud Rate Register
SpixRegs.SPIBRR
LSPCLK
, SPIBRR = 3 to 127
(SPIBRR + 1)
SPICLK signal =
LSPCLK
, SPIBRR = 0, 1, or 2
4
Baud Rate Determination: The Master specifies the communication baud rate using its baud rate
register (SPIBRR.6-0):
LSPCLK
• For SPIBRR = 3 to 127: SPI Baud Rate = bits/sec
( SPIBRR + 1)
LSPCLK
• For SPIBRR = 0, 1, or 2: SPI Baud Rate = bits/sec
4
Character Length Determination: The Master and Slave must be configured for the same
transmission character length. This is done with bits 0, 1, 2 and 3 of the configuration control
register (SPICCR.3-0). These four bits produce a binary number, from which the character length
is computed as binary + 1 (e.g. SPICCR.3-0 = 0010 gives a character length of 3).
Status SpixRegs.SPIST
RX Overrun Flag, Interrupt Flag, TX Buffer Full Flag
SPI Summary
SPI Summary
Provides synchronous serial
communications
Two wire transmit or receive (half duplex)
Three wire transmit and receive (full duplex)
Software configurable as master or slave
C28x provides clock signal in master mode
Data length programmable from 1-16 bits
125 different programmable baud rates
TX FIFO_15 TX FIFO_15
Transmitter-data Transmitter-data
buffer register buffer register
8 8
RX FIFO_15 RX FIFO_15
Addr/
Start LSB 2 3 4 5 6 7 MSB Parity Stop 1 Stop 2
Data
0 = Odd 0 = Disabled
1 = Even 1 = Enabled
The basic unit of data is called a character and is 1 to 8 bits in length. Each character of data is
formatted with a start bit, 1 or 2 stop bits, an optional parity bit, and an optional address/data bit.
A character of data along with its formatting bits is called a frame. Frames are organized into
groups called blocks. If more than two serial ports exist on the SCI bus, a block of data will
usually begin with an address frame which specifies the destination port of the data as determined
by the user’s protocol.
The start bit is a low bit at the beginning of each frame which marks the beginning of a frame.
The SCI uses a NRZ (Non-Return-to-Zero) format which means that in an inactive state the
SCIRX and SCITX lines will be held high. Peripherals are expected to pull the SCIRX and
SCITX lines to a high level when they are not receiving or transmitting on their respective lines.
When configuring the SCICCR, the SCI port should first be held in an inactive state. This
is done using the SW RESET bit of the SCI Control Register 1 (SCICTL1.5). Writing a 0 to this
bit initializes and holds the SCI state machines and operating flags at their reset condition. The
SCICCR can then be configured. Afterwards, re-enable the SCI port by writing a 1 to the SW
RESET bit. At system reset, the SW RESET bit equals 0.
• Start bit valid if 4 consecutive SCICLK periods of zero bits after falling edge
• Majority vote taken on 4th, 5th, and 6th SCICLK cycles
Majority
Vote
SCICLK
(Internal)
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2
SCIRXD
The SCI interrupt logic generates interrupt flags when it receives or transmits a complete
character as determined by the SCI character length. This provides a convenient and efficient
way of timing and controlling the operation of the SCI transmitter and receiver. The interrupt
flag for the transmitter is TXRDY (SCICTL2.7), and for the receiver RXRDY (SCIRXST.6).
TXRDY is set when a character is transferred to TXSHF and SCITXBUF is ready to receive the
next character. In addition, when both the SCIBUF and TXSHF registers are empty, the TX
EMPTY flag (SCICTL2.6) is set. When a new character has been received and shifted into
SCIRXBUF, the RXRDY flag is set. In addition, the BRKDT flag is set if a break condition
occurs. A break condition is where the SCIRXD line remains continuously low for at least ten
bits, beginning after a missing stop bit. Each of the above flags can be polled by the CPU to
control SCI operations, or interrupts associated with the flags can be enabled by setting the
RX/BK INT ENA (SCICTL2.1) and/or the TX INT ENA (SCICTL2.0) bits active high.
Additional flag and interrupt capability exists for other receiver errors. The RX ERROR flag is
the logical OR of the break detect (BRKDT), framing error (FE), receiver overrun (OE), and
parity error (PE) bits. RX ERROR high indicates that at least one of these four errors has
occurred during transmission. This will also send an interrupt request to the CPU if the RX ERR
INT ENA (SCICTL1.6) bit is set.
SCI Registers
SCI Baud Rate Registers
LSPCLK
, BRR = 1 to 65535
(BRR + 1) x 8
SCI baud rate =
LSPCLK
, BRR = 0
16
Baud Rate Determination: The values in the baud-select registers (SCIHBAUD and SCILBAUD)
concatenate to form a 16 bit number that specifies the baud rate for the SCI.
LSPCLK
• For BRR = 1 to 65535: SCI Baud Rate = bits/sec
( BRR + 1) × 8
LSPCLK
• For BRR = 0: SCI Baud Rate = bits/sec
16
Note that the CLKOUT for the SCI module is one-half the CPU clock rate.
Control 2 ScixRegs.SPICTL2
TX Buffer Full / Empty Flag, TX Ready Interrupt Enable
RX Break Interrupt Enable
SCI Summary
SCI Summary
Asynchronous communications format
65,000+ different programmable baud rates
Two wake-up multiprocessor modes
Idle-line wake-up & Address-bit wake-up
Programmable data word format
1 to 8 bit data word length
1 or 2 stop bits
even/odd/no parity
Error Detection Flags
Parity error; Framing error; Overrun error; Break detection
Double-buffered transmit and receive
Individual interrupts for transmit and receive
I2CXSR I2CDXR
TX FIFO
SDA
RX FIFO
I2CRSR I2CDRR
Clock
SCL
Circuits
I2C Arbitration
If two or more master-transmitters simultaneously
start transmission, an arbitration procedure is
invoked
Procedure uses data presented on serial data bus (SDA) by
competing transmitters
First master-transmitter which drives SDA high is overruled
by another master-transmitter that drives SDA low
Procedure gives priority to the data stream with the lowest
binary value
SCL
Device #1 lost arbitration
and switches to master-
Data from 1 0 receiver mode
device #1
Data from Device #2
1 0 0 1 0 1 drives SDA
device #2
SDA 1 0 0 1 0 1
I2C Summary
I2C Summary
Compliance with Philips I2C-bus
specification (version 2.1)
Support for 1-bit to 8-bit format
transfers
7-bit and 10-bit addressing modes
Data transfer rate from 10 kbps up to
400 kbps
16-bit receive FIFO
16-bit transmit FIFO
Module enable/disable
D E
CAN does not use physical addresses to address stations. Each message is sent with an identifier
that is recognized by the different nodes. The identifier has two functions – it is used for message
filtering and for message priority. The identifier determines if a transmitted message will be
received by CAN modules and determines the priority of the message when two or more nodes
want to transmit at the same time.
CAN_H
120Ω 120Ω
CAN_L
The DSP communicates to the CAN Bus using a transceiver. The CAN bus is a twisted pair wire,
and the transmission rate depends on the bus length. If the bus is less than 40 meters the
transmission rate is capable up to 1 Mbit/second.
CAN Node
Wired-AND Bus Connection
CAN_H
120Ω 120Ω
CAN_L
CAN Transceiver
(e.g. TI SN65HVD23x)
TX RX
CAN Controller
(e.g. TMS320F2808)
Principles of Operation
Principles of Operation
Data messages transmitted are identifier based,
not address based
Content of message is labeled by an identifier that
is unique throughout the network
(e.g. rpm, temperature, position, pressure, etc.)
All nodes on network receive the message and
each performs an acceptance test on the identifier
If message is relevant, it is processed (received);
otherwise it is ignored
Unique identifier also determines the priority of the
message
(lower the numerical value of the identifier, the higher the
priority)
When two or more nodes attempt to transmit at the
same time, a non-destructive arbitration technique
guarantees messages are sent in order of priority
and no messages are lost
Start
Bit
Node A Node A wins
arbitration
Node B
Node C
CAN Bus
S 11-bit R I E
O Identifier T D r0 DLC 0…8 Bytes Data CRC ACK O
F R E F
S I R
11-bit S 18-bit E
O R D T r1 r0 DLC 0…8 Bytes Data CRC ACK O
Identifier Identifier
F R E R F
The DSP CAN module is a full CAN Controller. It contains a message handler for transmission
and reception management, and frame storage. The specification is CAN 2.0B Active – that is,
the module can send and accept standard (11-bit identifier) and extended frames (29-bit
identifier).
A message mailbox
32
Identifier – MID
Control – MCF
Data low – MDL Receive Buffer
Data high - MDH Transmit Buffer
Control Buffer
Status Buffer
SN65HVD23x
3.3-V CAN Transceiver
.
. CAN Bus
The CAN controller module contains 32 mailboxes for objects of 0 to 8-byte data lengths:
• configurable transmit/receive mailboxes
• configurable with standard or extended indentifier
The CAN module contains registers which are divided into five groups. These registers are
located in data memory from 0x006000 to 0x0061FF. The five register groups are:
• Mailboxes
eCAN Summary
eCAN Summary
Fully CAN protocol compliant, version 2.0B
Supports data rates up to 1 Mbps
Thirty-two mailboxes
Configurable as receive or transmit
Configurable with standard or extended identifier
Programmable receive mask
Uses 32-bit time stamp on messages
Programmable interrupt scheme (two levels)
Programmable alarm time-out
Programmable wake-up on bus activity
Self-test mode
Introduction
This module contains various references to support the development process.
Learning Objectives
Learning Objectives
Module Topics
Development Support ..............................................................................................................................12-1
Module Topics........................................................................................................................................12-2
TI Support Resources.............................................................................................................................12-3
TI Support Resources
C28x Signal Processing Libraries
Signal Processing Libraries & Applications Software Literature #
ACI3-1: Control with Constant V/Hz SPRC194
ACI3-3: Sensored Indirect Flux Vector Control SPRC207
ACI3-3: Sensored Indirect Flux Vector Control (simulation) SPRC208
ACI3-4: Sensorless Direct Flux Vector Control SPRC195
ACI3-4: Sensorless Direct Flux Vector Control (simulation) SPRC209
PMSM3-1: Sensored Field Oriented Control using QEP SPRC210
PMSM3-2: Sensorless Field Oriented Control SPRC197
PMSM3-3: Sensored Field Oriented Control using Resolver SPRC211
PMSM3-4: Sensored Position Control using QEP SPRC212
BLDC3-1: Sensored Trapezoidal Control using Hall Sensors SPRC213
BLDC3-2: Sensorless Trapezoidal Drive SPRC196
DCMOTOR: Speed & Position Control using QEP without Index SPRC214
Digital Motor Control Library (F/C280x) SPRC215
Communications Driver Library SPRC183
DSP Fast Fourier Transform (FFT) Library SPRC081
DSP Filter Library SPRC082
DSP Fixed-Point Math Library SPRC085
DSP IQ Math Library SPRC087
DSP Signal Generator Library SPRC083
DSP Software Test Bench (STB) Library SPRC084
C280x C/C++ Header Files and Peripheral Examples SPRC191
FAQ: http://www-k.ext.ti.com/sc/technical_support/knowledgebase.htm
Device information my.ti.com
Application notes News and events
Technical documentation Training
Enroll in Technical Training: http://www.ti.com/sc/training
Email: [email protected]
Note: This appendix only provides a description of the eZdsp™ F2808 interfaces used in this
workshop. For a complete description of all features and details, please see the eZdsp™
F2808 USB Technical Reference manual.
Module Topics
Appendix ....................................................................................................................................................A-1
eZdsp™ F2808
eZdsp™ F2808 Connector / Header and Pin Diagram
P8 – I/O Interface
P5 / P9 – Analog Interface
SW1 - Switch
J1 / J2 – Test Points
Introduction
Appendix B will describe the data addressing modes on the C28x. Immediate addressing allows
for constant expressions which are especially useful in the initialization process. Indirect
addressing uses auxiliary registers as pointers for accessing organized data in arrays. Direct
addressing is used to access general purpose memory. Techniques for managing data pages,
relevant to direct addressing will be covered as well. Finally, register addressing allows for
interchange between CPU registers.
Learning Objectives
Learning Objectives
Module Topics
Appendix B – Addressing Modes .............................................................................................................B-1
Assembly Directives
Begin with a period (.) and are
lower case .ref start
.sect “vectors”
¾Used by the linker to locate ;make reset vector address 'start'
code and data into specified reset: .long start
sections
Directives allow you to: .def start
¾ Define a label as global count .set 9
; create an array x of 10 words
¾ Reserve space in memory x .usect “mydata”, 10
for un-initialized variables
.sect “code”
¾ Initialized memory start:C28OBJ ;operate in C28x mode
Directives MOV ACC,#1
initialized section next: MOVL XAR1,#x
.sect “name” MOV AR2,#count
loop: MOV *XAR1++,AL
used for code or constants
BANZ loop,AR2--
uninitialized section bump: ADD ACC,#1
label .usect “name”,5 SB next,UNC
used for variables
Addressing Modes
Addressing Modes
Four main categories of addressing modes are available on the C28x. Register addressing mode
allows interchange between all CPU registers, convenient for solving intricate equations.
Immediate addressing is helpful for expressing constants easily. Direct addressing mode allows
information in memory to be accessed. Indirect addressing allows pointer support via dedicated
‘auxiliary registers’, and includes the ability to index, or increment through a structure. The C28x
supports a true software stack, desirable for supporting the needs of the C language and other
structured programming environments, and presents a stack-relative addressing mode for
efficiently accessing elements from the stack. Paged direct addressing offers general-purpose
single cycle memory access, but restricts the user to working in any single desired block of
memory at one time.
Instruction Formats
Instruction Formats
INSTR dst ,src Example
INSTR REG NEG AL
INSTR REG,#imm MOV ACC,#1
INSTR REG,mem ADD AL,@x
INSTR mem,REG SUB AL,@AR0
INSTR mem,#imm MOV *XAR0++,#25
What is a “REG”?
16-bit Access = AR0 through AR7, AH, AL, PH, PL, T and SP
32-bit Access = XAR0 through XAR7, ACC, P, XT
What is an “#imm”?
an immediate constant stored in the instruction
What is a “mem”?
A directly or indirectly addressed operand from data memory
Or, one of the registers from “REG”!
loc16 or loc32 (for 16-bit or 32-bit data access)
The C28x follows a convention that uses instruction, destination, then source operand order
(INSTR dst, src). Several general formats exist to allow modification of memory or registers
based on constants, memory, or register inputs. Different modes are identifiable by their leading
characters (# for immediate, * for indirect, and @ for direct). Note that registers or data memory
can be selected as a ‘mem’ value.
Register Addressing
Register Addressing
32-bit Registers
XAR0 – XAR7 ACC P XT
16-bit Registers
AR0 – AR7 AH AL PH PL T TL DP SP
Register addressing allows the exchange of values between registers, and with certain instructions
can be used in conjunction with other addressing modes, yielding a more efficient instruction set.
Remember that any ‘mem’ field allows the use of a register as the operand, and that no special
character (such as @, *, or #) need be used to specify the register mode.
Immediate Addressing
Immediate Addressing – “#”
Immediate addressing allows the user to specify a constant within an instruction mnemonic. Short
immediate are single word, and execute in a single cycle. Long (16-bit) immediate allow full
sized values, which become two-word instructions - yet execute in a single instruction cycle.
AND ACC,#16Bit,<<0-16
AND ACC shift
#16Bit
Direct Addressing
Direct addressing allows for access to the full 4-Meg words space in 64 word “page” groups. As
such, a 16-bit Data Page register is used to extend the 6-bit local address in the instruction word.
Programmers should note that poor DP management is a key source of programming errors.
Paged direct addressing is fast and reliable if the above considerations are followed. The watch
operation, recommended for use whenever debugging, extracts the data page and displays it as the
base address currently in use for direct addressing.
0 0 0 1 F F
Z=X+Y 0000 0000 0000 0001 1111 1111
DP offset
Data Memory
x .usect “samp”,3
address data
.sect “code”
Page7[00] 0001C0 0001
MOVW DP,#x … …
64 ...
MOV AL,@x Page7[3D] x: 0001FD 1000
ADD AL,@y Page7[3E] y: 0001FE 0500
MOV @z, AL Page7[3F] z: 0001FF 1500
DP=0007 Accumulator
- - - - - - - -
variations: MOV AL,@x 0 0 0 0 1 0 0 0
¾ MOVW DP,#imm ;2W, 16-bit (4 Meg) ADD AL,@y 0 0 0 0 1 5 0 0
¾ MOVZ DP,#imm ;1W, 10-bit (64K)
¾ MOV DP,#imm ;DP(15:10) unchanged MOV @z,AL
Indirect Addressing
Indirect Addressing – “*”
Data Memory
XAR0
XAR1
XAR2
XAR3
XAR4
XAR5
XAR6
XAR7
ARAU
Any of eight hardware pointers (ARs) may be employed to access values from the first 64K of
data memory. Auto-increment or decrement is supported at no additional cycle cost. XAR register
formats offer larger 32-bit widths, allowing them to access across the full 4-Giga words data
space.
Indexed addressing offers the ability to select operands from within an array without modification
to the base pointer. Stack-based operations are handled with a 16-bit Stack Pointer register, which
operates over the base 64K of data memory. It offers 6-bit non-destructive indexing to access
larger stack-based arrays efficiently.
XAR2 x x0
x[2] = x[1] + x[3] x1
[3]
x2
x3
x4
x .usect “.samp”,5
.sect “.code”
x .usect “.samp”,5
MOVL XAR2,#x
.sect “.code”
MOV AR0,#1
MOV AR1,#3 MOVL XAR2,#x
MOV ACC,*+XAR2[AR0] MOV ACC,*+XAR2[1]
ADD ACC,*+XAR2[AR1] ADD ACC,*+XAR2[3]
MOV *+XAR2[2],AL
MOV *+XAR2[2],AL
16 bit offset 3 bit offset
Allows offset into arrays with fixed base pointer
Data Memory
x2 = x1 + x3 0 1 2 0 x3
0
? 3
0 2
? ? x2
5 0
?
0 2 0 0 x1
- SP - empty
empty
Instr. 3
.sect “.code”
Accumulator
MOV AL,*-SP[1]
Instr. 1 0 0 0 0 0 2 0 0
ADD AL,*-SP[3]
MOV *-SP[2],AL Instr. 2 0 0 0 0 0 3 2 0
MAC P,*AR6%++,*XAR7++
LINKER.CMD
SECTIONS
{ Buf_Mem: align(256) { } > RAM PAGE 1
. . .
}
Review
Addressing Range Review
0x000000
0x00003F
Stack
Addressing
Direct
SP Addressing
64K DP(16+6) Indirect
Addressing
4M
XARn
0x00FFFF
4G
0x3FFFFF
0xFFFFFFFF
Exercise B
Exercise B: Addressing
Given: DP = 4000 DP = 4004 DP = 4006
Address/Data (hex) 100030 0025 100100 0105 100180 0100
Fill in the 100031 0120 100101 0060 100181 0030
table below 100032 100102 0020 100182 0040
In the table above, fill in the values for each of the registers for each of the instructions. Three
areas of data memory are displayed at the top of the diagram, showing both their addresses and
contents in hexadecimal. Watch out for surprises along the way. First, you should answer the
addressing mode for the source operand. Then, fill in the change values as the result of the in-
struction operation.
Lab B: Addressing
Note: The lab linker command file is based on the F2812 memory map – modify as needed, if
using a different F28xx device memory map.
¾ Objective
The objective of this lab is to practice and verify the mechanics of addressing. In this process we
will expand upon the ASM file from the previous lab to include new functions. Additionally, we
learn how to run and observe the operation of code using Code Composer Studio.
In this lab, we will initialize the “vars” arrays allocated in the previous lab with the contents of
the “const” table. How is this best accomplished? Consider the process of loading the first
“const” value into the accumulator and then storing this value to the first “vars” location,
and repeating this process for each of the succeeding values.
• What forms of addressing could be used for this purpose?
• Which addressing mode would be best in this case? Why?
• What problems could arise with using another mode?
¾ Procedure
3. It is good practice to trap the end of the program (i.e. use either “end: B end,UNC” or
“end: B start,UNC”). Save your work.
If you wish, right click on the LabB.asm source window and select Mixed Mode to
debug using both source and assembly.
Note: Code Composer Studio can automatically load the output file after a successful build. On
the menu bar click: Option Æ Customize… and select the “Program Load
Options” tab, check “Load Program After Build”, then click OK.
6. Single-step your routine. While single-stepping, it is helpful to see the values located in
table[9] and data[9] at the same time. Open two memory windows by using the “View
Memory” button on the vertical toolbar and using the address labels table and data.
Setting the properties filed to “Hex – TI style” will give you more viewable data in the
window. Additionally, it is useful to watch the CPU core (and status) registers. Open the
CPU core (and status) registers by using the “View Æ CPU Registers”. Deselect
“Allow Docking” and move/resize the window as needed. Check to see if the program is
working as expected.
You might want to use your workspace from the previous lab. Look under File Æ Recent
Workspaces on the menu bar to select your saved workspace quickly. If needed, reload your
project.
End of Exercise
¾ Objective
The objective of this lab is to practice and verify the mechanics of initialization using C.
Additionally, we learn how to run and observe the operation of C code using Code Composer
Studio. In this lab, we will initialize the “vars” arrays with the contents of the “const” table.
¾ Procedure
Note: Have Code Composer Studio automatically load the output file after a successful build. On
the menu bar click: Option Æ Customize… and select the “Program Load Options”
tab, check “Load Program After Build”, then click OK.
4. Under Debug on the menu bar click “Go Main”. Single-step your routine. While single-
stepping, it is helpful to see the values located in table[9] and data[9] at the same time. Open
two memory windows by using the “View Memory” button on the vertical toolbar and
using the address labels table and data. Setting the properties filed to “Hex – TI style”
will give you more viewable data in the window. Additionally, you can watch the CPU (and
Status) registers. Open the CPU core and status registers by using the “View Æ CPU
Registers”. Deselect “Allow Docking” and move/resize the window as needed.
Check to see if the program is working as expected.
End of Exercise
Solutions
Introduction
Appendix C discusses the details of programming in assembly. It shows you how to use
different instructions that further utilize the advantage of the architecture data paths. It gives
you the ability to analyze the instruction set and pick the best instruction for the application.
Learning Objectives
Learning Objectives
Perform simple program control using
branch and conditional codes
Write C28x code to perform basic
arithmetic
Use the multiplier to implement
sum-of-products equations
Use the RPT instruction (repeat) to
optimize loops
Use MAC for long sum-of-products
Efficiently transfer the contents of one
area of memory to another
Examine read-modify-write operations
Module Topics
Appendix C – Assembly Programming ...................................................................................................C-1
Module Topics.........................................................................................................................................C-2
Program Control.....................................................................................................................................C-3
Branches .............................................................................................................................................C-3
Program Control Instructions .............................................................................................................C-4
ALU and Accumulator Operations..........................................................................................................C-6
Simple Math & Shift...........................................................................................................................C-7
Multiplier ................................................................................................................................................C-9
Basic Multiplier ................................................................................................................................C-10
Repeat Instruction.............................................................................................................................C-11
MAC Instruction...............................................................................................................................C-12
Data Move.............................................................................................................................................C-13
Logical Operations ...............................................................................................................................C-15
Byte Operations and Addressing ......................................................................................................C-15
Test and Change Memory Instructions.............................................................................................C-16
Min/Max Operations.........................................................................................................................C-17
Read Modify Write Operations .............................................................................................................C-18
Lab C: Assembly Programming............................................................................................................C-20
OPTIONAL Lab C-C: Sum-of-Products in C........................................................................................C-22
Program Control
The program control logic and program address generation logic work together to provide proper
program flow. Normally, the flow of a program is sequential: the CPU executes instructions at
consecutive program memory addresses. At times, a discontinuity is required; that is, a program
must branch to a nonsequential address and then execute instructions sequentially at that new
location. For this purpose, the C28x supports interrupts, branches, calls, returns, and repeats.
Proper program flow also requires smooth flow at the instruction level. To meet this need, the
C28x has a protected pipeline and an instruction-fetch mechanism that attempts to keep the
pipeline full.
Branches
Branch Types and Range
¾ 3 Branch Types
0x000000
Long
Short Branch Branch
offset +127/- Branch
Program 128
offset +/-32K
absolute 4M
Memory 1-word 2-word
instruction instruction 2-word
instruction
PC
0x3FFFFF
The PC can access the entire 4M words (8M bytes) range. Some branching operations offer 8-
and 16-bit relative jumps, while long branches, calls, and returns provide a full 22-bit absolute
address. Dynamic branching allows a run-time calculated destination. The C28x provides the fa-
miliar arithmetic results status bits (Zero, oVerflow, Negative, Carry) plus a Test Control bit
which holds the result of a binary test. The states of these bits in various combinations allow a
range of signed, unsigned, and binary branching conditions offered.
Condition Code
NEQ LT LO (NC) NTC Condition flags are set on
EQ LEQ LOS TC the prior use of the ALU
GT HI NOV UNC
GEQ The assembler will optimize
HIS (C) OV NBIO
B to SB if possible
Func
PC
Ret Addr
4
y = ∑ xn len .set 5
n =0 Data x .usect “samp”,6
y .set (x+len)
x x0 XAR2
x1
.sect “code”
x2
MOVL XAR2,#x
x3
MOV AR3,#len-2
x4
y MOV AL,*XAR2++
sum: ADD AL,*XAR2++
BANZ sum,AR3--
AR3
MOV *(0:y),AL
COUNT
ACC
AH (31-16) AL (15-0)
AH.MSB AH.LSB AL.MSB AL.LSB
One of the major components in the execution unit is the Arithmetic-Logical-Unit (ALU). To
support the traditional Digital Signal Processing (DSP) operation, the ALU also has the zero
cycle barrel shifter and the Accumulator. The enhancement that the C28x has is the additional
data paths added form the ALU to all internal CPU registers and data memory. The connection to
all internal registers helps the compiler to generate efficient C code. The data path to memory
allows the C28x performs single atomic instructions read-modify-write to the memory.
The following slides introduce you to various instructions that use the ALU hardware. Word,
byte, and long word 32-bit operation are supported.
Format
xxx Ax, #16b ;word xxx = instruction: MOV, ADD, SUB, ...
xxxB Ax, #8b ;byte Ax = AH, or AL
Assembler will automatically convert to 1
xxxL ACC, #32b ;long word instruction.
}
Variation
15 ……… 0
LSL
Shift AL or AH C Ax 0
LSL AX <<shift
LSR AX <<shift 15 ……… 0
ASR AX >>shift SXM Ax C ASR
LSL AX <<T
LSR AX <<T 15 ……… 0
ASR AX >>T 0 Ax C LSR
31 ……… 0
C ACC 0
Examples:
Logical Shift Left – Long: LSLL LSLL ACC, T
LSRL ACC, T
31 ……… 0
0 ACC C
ASRL ACC, T
Multiplier
Multiply Unit
XT Register Data Mem
or Register
T Register
MUX
16x16 Prog Mem (16)
or
Immed (8,16)
P Register (32)
Shift (PM)
ACC (32)
Digital signal processors require many multiply and add math intensive operations. The single
cycle multiplier is the second major component in the execution unit. The C28x has the
traditional 16-bit-by-16-bit multiplier as previous TI DSP families. In-addition, the C28x has a
single cycle 32-bit-by-32-bit multiplier to perform extended precision math operations. The large
multiplier allows the C28x to support higher performance control systems requirement while
maintaining small or reduce code.
The following slides introduce instructions that use the 16-bit-by-16-bit multiplier and multiply
and add (MAC) operations. The 32-bit-by-32-bit multiplication will be covered in the appendix.
Basic Multiplier
Multiplier Instructions
Instruction Execution Purpose
MOV T,loc16 T = loc16 Get first operand
MPY ACC,T,loc16 ACC = T*loc16 For single or first product
MPY P,T,loc16 P = T*loc16 For nth product
MPYB ACC,T,#8bu ACC = T*8bu Using 8-bit unsigned const
MPYB P,T,#8bu P = T*8bu Using 8-bit unsigned const
MOV ACC,P ACC = P Move 1st product<<PM to ACC
ADD ACC,P ACC += P Add nth product<<PM to ACC
SUB ACC,P ACC -= P Sub nth product<<PM fr. ACC
Instruction Execution
MOVP T, loc16 ACC = P<<PM T = loc16
MOVA T, loc16 ACC += P<<PM T = loc16
MOVS T, loc16 ACC - = P<<PM T = loc16
MPYA P, T, #16b ACC += P<<PM then P = T*#16b
MPYA P, T, loc16 ACC += P<<PM then P = T*loc16
MPYS P, T, loc16 ACC - = P<<PM then P = T*loc16
Sum-of-Products
Y = A*X1 + B*X2 + C*X3 + D*X4
Repeat Instruction
Repeat Next: RPT
Options:
¾ RPT #8bit up to 256 iterations
¾ RPT loc16 location “loc16” holds count value
Features: Example :
¾ Next instruction iterated N+1 times int x[5]={0,0,0,0,0};
¾ Saves code space - 1 word
¾ Low overhead - 1 cycle
x .usect “samp”,5
MOV AR1,#x
¾ Easy to use
RPT #4
¾ Non-interruptible
|| MOV *XAR1++,#0
¾ Requires use of | | before next line
¾ May be nested within BANZ loops
Instruction Cycles
RPT 1
BANZ 4 .N
Refer to User Guide for more repeatable instructions
Single repeat instruction (RPT) is used to reduce code size and speed up many operations in the
DSP application. Some of the most popular operations that use the RPT instruction to perform
multiple taps digital filters or perform block of data transfer.
MAC Instruction
Sum-of-Products: RPT / MAC
x .usect “sample”,20
19
y = ∑ xn an
y .usect “result”,2
.sect “coefficient”
a0: .word 0x0101
n =0 .word 0x0202
• • •
XAR1++ X0 .word 0x2020
X1 .sect “code”
SOP: SPM 0
... MOVW DP,#y
MOVL XAR1,#x
X19 MOVL XAR7,#a0
ZAPA Zero ACC & P
XAR7++ A0 RPT #19 Repeat single
Second operand || MAC P,*XAR1++,*XAR7++ Dual operand
must use XAR7 A1
ADDL ACC,P<<PM last ADD
... MOVL @y,ACC
A19 B SOP,UNC
MOV
ADD
T,loc16
ACC,P
MOVA T,loc16
MPY P,T,loc16
MAC { ACC+=P
T=*ARn++
P=T*(*ARn++)
Data Move
Data Move Instructions
DATA ↔ DATA (4G ↔ 64K) DATA ↔ PGM (4G ↔ 4M)
MOV loc16, *(0:16bit) PREAD loc16 ,*XAR7
MOV *(0:16bit), loc16 PWRITE *XAR7, loc16
.sect “.code”
START: MOVL XAR5,#x
MOVL XAR7,#TBL
RPT #len-1
|| PREAD *XAR5++,*XAR7
...
x .usect “.samp”,4
.sect “.coeff”
TBL: .word 1,2,3,4
len .set $-TBL
Optimal with RPT (speed and code size) Faster than Load / Store, avoids
In RPT, non-mem address is auto- accumulator
incremented in PC Allows access to program memory
Conditional Moves
Instruction Execution (if COND is met)
MOV loc16,AX,COND [loc16] = AX
MOVB loc16,#8bit,COND [loc16] = 8bit
Instruction Execution (if COND is met)
MOVL loc32,ACC,COND [loc32] = AX
Example
If A<B, Then B=A
Accumulator
A .usect “var”,2,1 0 0 0 0 0 1 2 0
B .set A+1
.sect “code”
Data Memory Data Memory
MOVW DP, #A
MOV AL, @A 0 1 2 0 A 0 1 2 0 A
CMP AL, @B 0 3 2 0 B 0 1 2 0B
MOV @B, AL, LT Before After
The conditional move instruction is an excellent way to avoid a discontinuity (branch or call)
based upon a condition code set prior to the instruction. In the above example, the 1st step is to
place the contents of A into the accumulator. Once the Ax content is tested, by using the CMP
instruction, the conditional move can be executed.
If the specified condition being tested is true, then the location pointed to by the “loc16” address-
ing mode or the 8–bit zero extended constant will be loaded with the contents of the specified AX
register (AH or AL): if (COND == true) [loc16] = AX or 0:8bit;
Note: Addressing modes are not conditionally executed. Hence, if an addressing mode performs a
pre or post modification, it will execute regardless if the condition is true or not. This instruction
is not repeatable. If this instruction follows the RPT instruction, it resets the repeat counter
(RPTC) and executes only once.
Flags and Modes
N - If the condition is true, then after the move, AX is tested for a negative condition. The nega-
tive flag bit is set if bit 15 of AX is 1, otherwise it is cleared.
Z - If the condition then after the move, AX is tested for a zero condition. The zero flag bit is set
if AX = 0, otherwise it is cleared.
V - If the V flag is tested by the condition, then V is cleared.
C-Example
; if ( VarA > 20 )
; VarA = 0;
Logical Operations
Byte Operations and Addressing
Byte Operations
Byte Addressing
AH.MSB AH.LSB AL.MSB AL.LSB
12 34 56 78
16 bit memory
01
78 00 AR2
03 02
56
05
34 04
07 06
12
Min/Max Operations
MIN/MAX Operations
Instruction Execution
MAX ACC,loc16 if ACC < loc16, ACC = loc16
if ACC >= loc16, do nothing
MIN ACC,loc16 if ACC > loc16, ACC = loc16
if ACC <= loc16, do nothing
MAXL ACC,loc32 if ACC < loc32, ACC = loc32
if ACC >= loc32, do nothing
MINL ACC,loc32 if ACC > loc32, ACC = loc32
if ACC <= loc32, do nothing
MAXCUL P,loc32 if P < loc32, P = loc32
(for 64 bit math) if P >= loc32, do nothing
MINCUL P,loc32 if P > loc32, P = loc32
(for 64 bit math) if P <= loc32, do nothing
Read-Modify-Write Instructions
Read-Modify-Write Examples
update with a mem update with a constant update by 1
¾ Objective
The objective of this lab is to practice and verify the mechanics of performing assembly language
programming arithmetic on the TMS320C28x. In this process we will expand upon the .asm file
from the previous lab to include new functions. Code will be to added to obtain the sum of the
products of the values from each array.
Perform the sum of products using a MAC-based implementation. In a real system application,
the coeff array may well be constant (values do not change), therefore one can modify the
initialization routine to skip the transfer of this arrays, thus reducing the amount of data RAM and
cycles required for initialization. Also, there is no need to copy the zero to clear the result
location. The initialization routine from the previous lab using the load/store operation will be
replaced with a looped BANZ implementation.
As in previous lab, consider which addressing modes are optimal for the tasks to be performed.
You may perform the lab based on this information alone, or may refer to the following
procedure.
¾ Procedure
3. Save your work. If you would like, you can use Code Composer Studio to verify the
correct operation of the block initialization before moving to the next step.
6. If the “Load program after build” option was not selected in Code Composer
Studio, load the output file onto the target. Click: File Æ Load Program…
If you wish, right click on the source window and select Mixed Mode to debug using
both source and assembly.
7. Single-step your routine. While single-stepping, open memory windows to see the values
located in table [9] and data [9] . Open the CPU Registers. Check to see if the program is
working as expected. Debug and modify, if needed.
Optional Exercise
After completing the above, edit LabC.asm and modify it to perform the initialization
process using a RTP/PREAD rather than a load/store/BANZ.
End of Exercise
¾ Objective
The objective of this lab is to practice and verify the mechanics of performing C programming
arithmetic on the TMS320C28x. The objective will be to add the code necessary to obtain the
sum of the products of the n-th values from each array.
¾ Procedure
Note: Have Code Composer Studio automatically load the output file after a successful build. On
the menu bar click: Option Æ Customize… and select the “Program Load Options”
tab, check “Load Program After Build”, then click OK.
4. Under Debug on the menu bar click “Go Main”. Single-step your routine. While
single-stepping, open memory windows to see the values located in table [9] and data
[9] . (Note: data[9] consists of the allocated arrays of data, coeff, and result). Open the
CPU Registers. Check to see if the program is working as expected. Debug and modify,
if needed.
End of Exercise
Introduction
The C28x architecture, hardware, and compiler has been designed to efficiently support C code
programming.
Appendix D will focus on how to program in C for an embedded system. Issues related to
programming in C and how C behaves in the C28x environment will be discussed. Also, the C
compiler optimization features will be explained.
Learning Objectives
Learning Objectives
Module Topics
Appendix D – C Programming.................................................................................................................D-1
Module Topics.........................................................................................................................................D-2
Linking Boot code from RTS2800.lib ......................................................................................................D-3
Set up the Stack .......................................................................................................................................D-4
C28x Data Types.....................................................................................................................................D-5
Accessing Interrupts / Status Register.....................................................................................................D-6
Using Embedded Assembly .....................................................................................................................D-7
Using Pragma .........................................................................................................................................D-8
Optimization Levels ................................................................................................................................D-9
Volatile Usage ..................................................................................................................................D-11
Compiler Advanced Options ............................................................................................................D-12
Optimization Tips Summary.............................................................................................................D-13
Lab D: C Optimization..........................................................................................................................D-14
OPTIONAL Lab D2: C Callable Assembly...........................................................................................D-17
Solutions................................................................................................................................................D-20
_main ...
The boot routine is used to establish the environment for C before launching main. The boot
routine begins with the label _c_int00 and the reset vector should contain a ".long" to this address
to make boot.asm the reset routine. The contents of the boot routine have been extracted and
copied on the following page so they may be inspected. Note the various functions performed by
the boot routine, including the allocation and setup of the stack, setting of various C-requisite
statuses, the initialization of global and static variables, and the call to main. Note that if the link
was performed using the "–cr" option instead of the "–c" option that the global/static variable
initialization is not performed. This is useful on RAM-based C28x systems that were initialized
during reset by some external host processor, making transfer of initialization values unnecessary.
Later on in this chapter, there is an example on how to do the vectors in C code rather than
assembly.
Data Memory
The Stack
The C/C++ compiler uses a
stack to:
Allocate local variables
SP 0x400 Caller’s
(reset) local vars Pass arguments to
Arguments functions
passed on
stack Save the processor status
Return Save the function return
address .stack
address
Function
return addr Save temporary results
Temp results
The compiler uses the hardware
stack pointer (SP) to
64K manage the stack.
SP defaults to 0x400 at reset.
4M The run-time stack grows from
low addresses to higher
addresses.
The C28x has a 16-bit stack pointer (SP) allowing accesses to the base 64K of memory. The stack
grows from low to high memory and always points to the first unused location. The compiler
uses the hardware stack pointer (SP) to manage the stack. The stack size is set by the linker.
In order to allocate the stack the linker command file needs to have “align = 2.”
Interrupt Enable & Interrupt Flag Registers (IER, IFR) are not
memory mapped
Only limited instructions can access IER & IFR (more in interrupt
chapter)
The compiler provides extern variables for accessing the IER & IFR
The assembly function allows for C files to contain 28x assembly code. Care should be taken not
to modify registers in use by C, and to consider the label field with the assembly function. Also,
any significant amounts of assembly code should be written in an assembly file and called from
C.
There are two examples in this slide – the first one shows how to embed a single assembly
language instruction into the C code flow. The second example shows how to define a C term that
will invoke the assembly language instruction.
Using Pragma
Pragma is a preprocessor directive that provides directions to the compiler about how to treat a
particular statement. The following example shows how the DATA_SECTION pragma is used
to put a specific buffer into a different section of RAM than other buffers.
The example shows two buffers, bufferA and bufferB. The first buffer, bufferA is treated
normally by the C compiler by placing the buffer (512 words) into the ".bss" section. The second,
bufferB is specifically directed to go into the “my_sect” portion of data memory. Global
variables, normally ".bss", can be redirected as desired.
When using CODE_SECTION, code that is normally linked as ".text", can be identified
otherwise by using the code section pragma (like .sect in assembly).
Pragma Examples
User defined sections from C :
#pragma CODE_SECTION (func, ”section name”)
#pragma DATA_SECTION (symbol, “section name”)
Optimization Levels
Optimization Scope
FILE1.C
-o0, -o1 -o2 -o3 -pm -o3
{
{
SESE
} LOCAL
single block
{ FUNCTION
... across FILE
} SESE: Single Entry, Single Exit blocks across
} functions PROGRAM
across files
{
. . .
}
FILE2.C
{
. . .
}
Optimizations fall into 4 categories. This is also a methodology that should be used to invoke the
optimizations. It is recommended that optimization be invoked in steps, and that code be verified
before advancing to the next step. Intermediate steps offer the gradual transition from fully sym-
bolic to fully optimized compilation. Compiler switched may be invoked in a variety of ways.
Optimization Performance
–o0 Performs control-flow-graph simplification
Allocates variables to registers
LOCAL Performs loop rotation
Eliminates unused code
Simplifies expressions and statements
Expands calls to functions declared inline
–o1 Performs local copy/constant propagation
Removes unused assignments
Eliminates local common expressions
–o2 Default (-o)
FUNCTION Performs loop optimizations
Eliminates global common sub-expressions
Eliminates global unused assignments
–o3 Removes all functions that are never called
FILE Simplifies functions with return values that are never used
Inlines calls to small functions
Identifies file-level variable characteristics
PROGRAM –o3 –pm
Optimizer levels zero through three, offer an increasing array of actions, as seen above. Higher
levels include all the functions of the lower ones. Increasing optimizer levels also increase the
scope of optimization, from considering the elements of single entry, single-exit functions only,
through all the elements in a file. The “-pm” option directs the optimizer to view numerous input
files as one large single file, so that optimization can be performed across the whole system.
Volatile Usage
Optimization Issue: “Volatile” Variables
Problem: The compiler does not know that this pointer may refer to a
hardware register that may change outside the scope of the C program.
Hence it may be eliminated (optimized out of existence!)
The first thing to notice under advanced options is the Auto Inlining Threshold.
Note: To prevent code size increases when using –o3, disable auto inlining with -oi0
The next point we will cover is the Normal Optimization with Debug (-mn).
Note: Some symbolic debug labels will be lost when –mn option is used.
[-mf] : Optimize for speed instead of the default optimization for code size
[-mi] : Avoid RPT instruction. Prevent compiler from generating RPT instruction. RPT instruc-
tion is not interruptible
[-mt] : Unified memory model. Use this switch with the unified memory map of the 281x &
280x. Allows compiler to generate the following:
-RPT PREAD for memory copy routines or structure assignments
-MAC instructions
-Improves efficiency of switch tables
The list above documents the steps that can be taken to achieve increasingly higher coding effi-
ciency. It is recommended that users first get their code to work with no optimization, and then
add optimizations until the required performance is obtained.
Lab D: C Optimization
Note: The lab linker command file is based on the F2812 memory map – modify as needed, if
using a different F28xx device memory map.
¾ Objective
The objective of this lab is to practice and verify the mechanics of optimizing C programs. Using
Code Composer Studio profile capabilities, different routines in a project will be benchmarked.
This will allow you to analyze the performance of different functions. This lab will highlight the
profiler and the clock tools in CCS.
¾ Procedure
2. Setup the Build Options. Select the Linker tab and in the middle of the screen select
“Run-time Autoinitialization” under “Autoinit Model:”. Create a
map file by typing .\Debug\LabD.map in the Map Filename [-m] field. Do
not enter anything in the “Code Entry Point (-e):” field (leave it blank). Set
the stack size to 0x400. Next, select the Compiler tab. Note that “Full Symbolic
Debug (-g)” under “Generate Debug Info:” in the Basic Category is
selected. On the Feedback Category pull down the interlisting options and select “C
and ASM (-ss)”. On the Assembly Category check the Keep generated .asm
Files (-k), Keep Labels as Symbols(-as) and Generate Assembly
Listing Files (-al). The –as will allow you to see symbols in the memory
window and the –al will generate an assembly listing file (.lst file). The listing file has
limited uses, but is sometime helpful to view opcode values and instruction sizes. (The
.lst file can be viewed with the editor). Both of these options will help with debugging.
Then select OK to save the Build Options.
5. Set a breakpoint on the NOP in the while(1) loop at the end of main() in LabD.c.
8. Select F5 or the run icon. Observe the values present in the profiling window. What do
the numbers mean? Click on each tab to determine what each displays.
Benchmarking Code
9. Let’s benchmark (i.e.count the cycles need by) only a portion of the code. This requires
you to set a breakpoint pair on the starting and ending points of the benchmark. Open the
file sop-c.c and set a breakpoint on the “for” statement and the “return”
statement.
10. In CCS, select profiler Æ enable clock (must be checked). Then select
profiler Æ view clock.
11. Now “Restart” the program and then “Run” the program. The program should be
stopped at the first breakpoint in sop. Double click on the clock window to set the clock
to zero. Now you are ready to benchmark the code. “Run” to the second breakpoint.
The number of cycles are displayed in the clock window. Record this value in the table
at the end of the lab under “C Code - Cycles”.
C Optimization
12. To optimize C code to the highest level, we must set up new Build Options for our
Project. Select the Compiler tab. In the Basic Category Panel, under “Opt Level”
select File (-o3). Then select OK to save the Build Options.
13. Now “Rebuild” the program and then “Run” the program. The program should be
stopped at the first breakpoint in sop. Double click on the clock window to set the clock
to zero. Now you are ready to benchmark the code. “Run” to the second breakpoint.
The number of cycles are displayed in the clock window. Record this value in the table
at the end of the lab under “Optimized C (-o3) - Cycles”.
14. Look in your profile window at the code size of sop. Record this value in the table at the
end of this lab.
16. Start a new profile session and set it to profile all functions. Run to the first breakpoint
and study the profiler window. Record the code size of the assembly code in the table.
17. Double Click on the clock to reset it. Run to the last breakpoint. Record the number of
cycles the assembly code ran.
18. How does assembly, C code, and oprimized C code compare on the C28x?
Code Size
Cycles
End of Exercise
¾ Objective
The objective of this lab is to practice and verify the mechanics of implementing a C callable
assembly programming. In this lab, a C file will be used to call the sum-of-products (from the
previous Appendix LabC exercise) by the “main” routine. Additionally, we will learn how to use
Code Composer Studio to configure the C build options and add the run-time support library to
the project. As in previous labs, you may perform the lab based on this information alone, or may
refer to the following procedure.
¾ Procedure
2. Do not add LabC.asm to the project (copy of file from Appendix Lab C). It is only
placed here for easy access. Parts of this file will be used later during this lab exercise.
3. Setup the Build Options. Select the Linker tab and in the middle of the screen select
“Run-time Autoinitialization” under “Autoinit Model:”. Create a
map file by typing .\Debug\LabD2.map in the Map Filename [-m] field.
Do not enter anything in the “Code Entry Point (-e):” field (leave it blank).
Set the stack size to 0x400. Next, select the Compiler tab. Note that “Full
Symbolic Debug (-g)” under “Generate Debug Info:” in the Basic
Category is selected. On the Feedback Category pull down the interlisting options and
select “C and ASM (-ss)”. On the Assembly Category check the Keep
generated .asm Files (-k), Keep Labels as Symbols(-as) and
Generate Assembly Listing Files (-al). The –as will allow you to see
symbols in the memory window and the –al will generate an assembly listing file (.lst
file). The listing file has limited uses, but is sometime helpful to view opcode values and
instruction sizes. (The .lst file can be viewed with the editor). Both of these options will
help with debugging. Then select OK to save the Build Options.
5. Under Debug on the menu bar click “Go Main”. This will run through the C
initialization routine in Boot.asm and stop at the main routine in LabD2.c.
10. Look for the _sop function that is generated by the compiler. This code is the basis for
the C-callable assembly routine that is developed in this lab. Notice the comments
generated by the compiler on which registers are used for passing parameters. Also,
notice the C code is kept as comments in the interlisted file.
11. Create a new file (File → New, or clicking on the left most button on the horizontal
toolbar “New”) and save it as an assembly source file with the name sop-asm.asm.
Next copy ONLY the sum of products function from LabC.asm into this file. Add a
_sop label to the function and make it visible to the linker (.def). Also, be sure to add a
.sect directive to place this code in the “code” section. Finally, add the following
instruction to the end:
12. Next, we need to add code to initialize the sum-of-products parameters properly, based
on the passed parameters. Add the following code to the first few lines after entering the
_sop routine: (Note that the two pointers are passed in AR4 and AR5, but one needs to
be placed in AR7. The loop counter is the third argument, and it is passed in the
accumulator.)
Before beginning the MAC loop, add statements to set the sign extension mode, set the
SPM to zero, and a ZAPA instruction. Use the same MAC statement as in Lab 4, but use
XAR4 in place of XAR2. Make the repeat statement use the passed value of n-1 (i.e.
AR5).
Now we need to return the result. To return a value to the calling routine you will need to
place your 32-bit value in the ACC. What register is the result currently in? Adjust your
code, if necessary.
13. Save the assembly file as sop-asm.asm. (Do not name it LabD2.asm because the
compiler has already created with that name from the original LabD2.c code).
16. Rebuild and verify that the new assembly sum-of-products routine produces the same
results as the C function.
End of Exercise
Solutions
Lab D Solutions
Cycles 118 32 22