Technical Notes on using Analog Devices' DSP components and development tools
a
SHARC SPI Booting
Contributed by B. Mitchell and M. Walsh February 27, 2003
Contact our technical support by phone: (800) ANALOG-D or e-mail: dsp.support@analog.com
Or visit our on-line resources http://www.analog.com/dsp and http://www.analog.com/dsp/EZAnswers
Introduction
Upon power-up, the ADSP-21161 can be bootloaded as an SPI slave device. Although the
hardware interface is simple, there is a
complication that arises when using this boot
scheme. The SPI protocol does not provide an
obvious way for the booting, SPI-slave to
“pause” the boot-stream being transmitted by the
SPI-master device. This causes a problem when
SPI-booting because when performing “zeroinitializations”, the DSP executes code rather
than emptying the SPIRX buffer of the slave
DSP.
To save space in the .LDR file, sections of
memory with a large number of contiguous zeros
are truncated: Instead of storing these zeros in
the .LDR file, the loader only includes the
destination address and the number of zeros
required. (Consecutive zeros often occur because
of unitialized data arrays or several (5)
consecutive
which is
upon identifying one of these zero-init sections,
simply runs a small loop to write zeros to each
address specified. If the core stays in this loop
for a too long while the SPI-Master device
continues to transmit, then the 2-deep SPI FIFO
may overflow, and data may be lost. This EEnote describes three ways to avert this potential
problem.
“nop;” instructions, the opcode for
0x000000000000.) The kernel then,
Hardware Solution
There are two ways to pause the SPI master
device by implementing a HW feedback scheme,
either using a fifth pin as a FLAG signal, or
using the MISO pin. In both scenarios the DSP
would drive a hand-shake signal back to the SPImaster. This signal should be connected to a Flag
or Interrupt pin on the SPI-master. The SPImaster would monitor this FLAG or Interrupt
pin, and pause transmission when necessary.
Similarly, the feedback signal may also be
interpreted by the host as a “start transmission”
signal. Regardless of the protocol, implementing
a solution in HW would require a small change
to the loader kernel, 161_SPI.asm as well.
Described below is the former case, where the
feedback signal indicates that the SPI-master
should “pause” transmission. In the loaderkernel, the small sections of code that performs
the zero initializations are simply modified to
drive an output flag pin low until it finishes
executing the zero-initialization loop. The
before and after modification can be seen in
Listing-1 and Listing-2.
Copyright 2003, Analog Devices, Inc. All rights reserved. Analog Devices assumes no responsibility for customer product design or the use or application of
customers’ products or for any infringements of patents or rights of others which may result from Analog Devices assistance. All trademarks and logos are
property of their respective holders. Information furnished by Analog Devices Applications and Development Tools Engineers is believed to be accurate and
reliable, however no responsibility is assumed by Analog Devices regarding the technical accuracy and topicality of the content provided in all Analog Devices’
Engineer-to-Engineer Notes.
DM_zero:
K
R0=R0-R0, I0=R3; //r0=0& I0=address
//as held in R3.
LCNTR=R2, DO dm_zero.end UNTIL LCE;
dm_zero.end:
DM(I0,M6)=R0;
JUMP read_boot_info;
Listing-1. Standard Zero-init code from SPI bootloader kernel, 161_SPI.asm
#include <def21161.h>
R0=R0-R0,I0=R3; //r0=0 & I0=address
//as held in R3.
USTAT1=DM(IOFLAG);
BIT SET USTAT1 FLG4O; //make output
dm(IOFLAG)=USTAT1;
BIT CLR USTAT1 FLG4; //flag4 = low
dm(IOFLAG)=USTAT1;
LCNTR=R2, DO dm_zero.end UNTIL LCE;
dm_zero.end:
DM(I0,M6)=R0;
BIT SET USTAT1 FLG4; //flag4 = high
dm(IOFLAG)=USTAT1;
JUMP read_boot_info;
Listing-2. Zero-init code with HW feedback added
using DSP Flag 4.
Included with this application note is a version of
the kernel modified in the manner described in
this section, as well as a project to be used on a
master ADSP-21161 to boot a slave in this
manner. It is important to note that when the
master is “paused”, care must be taken to ensure
that the transmission stops only after an entire
word has been sent. In the case of the ADSP21161, this will cause the host to need to resend
the last two words before the pause occurred.
Alternatively, as shown in Figure-1, the slave
DSP’s MISO pin may be connected to the
Flag/Interrupt pin of the SPI-master. The DSP’s
SPI port may then transmit all 1’s or all 0’s
a
depending on the protocol implemented. The
SENDZ bit of the SPICTL register determines
what is sent when the DSP’s transmit buffer is
not refilled. If SENDZ is cleared, then the SPI
port will continue to retransmit the last word
written to the SPITX buffer. If SENDZ is set,
then the MISO pin will be driven low (sending
zeros) until a new word is written to the SPITX
buffer.
ADSP-21161SPI-Master
MISO
MOSI
SPICL
SPIDS
Figure-1. Hardware feedback mechanism using the
DSP’s MISO pin.
The modifications to the loader kernel would be
similar to those in Listing-4. The actual code is
dependant on the host, and whether logic high or
logic low means “pause” or “resume”. In either
case, the code would write a data-word to the
SPITX register, rather than toggling a flag. This
word may be all ones, all zeros, or some other
mix to shape the waveform accordingly.
In this second implementation, where the MISO
pin is used as a handshake signal and as a dataline would require some software modifications
on the SPI-master side. This software would
need to be configured to monitor the flag-in
(handshake) pin in certain circumstances (during
booting), and then ignore it in others (when it is
receiving data over the MISO pin).
FLAG_IN
MISO
MOSI
SPICLK
SPIDS
SHARC SPI Booting (EE-177)
Page 2 of 20
a
Software solution
Alternatively, the SPI-master device may insert
pauses on it’s own, without any feedback from
the booting slave device. The .LDR file which is
produced by the VisualDSP Loader is divided
into multiple “initialization sections”. Each
piece of contiguous, homogeneous data from the
executable is grouped together and given a threeword descriptive header. This header and
following data make up an “initialization
section”. The initialization header is used by the
loader kernel to correctly initialize the
subsequent data, and can also be used by the SPImaster to throttle the boot-stream when
necessary. The header is made of three words:
the WORD COUNT, the destination ADDRESS,
and finally a TAG identifying the data-type.
Listing-3 shows the 27 different data-types that
the loader uses:
Interpreting this header, the kernel would
recognize that there are 19 (0x13) instructions
that are located at address 0x40100. (The TAG of
0x0000000E signifies non-zero 48-bit PM data).
One way to implement a software solution
requires the SPI master device to read this
header. Instead of streaming the entire .LDR
image in one shot, it would send it one
initialization section at a time. It would read the
init-header and send the appropriate number of
words. The COUNT included in each init-header
can be used by the SPI master to figure out how
many words to “skip ahead” in the .LDR to find
the next init-header. When a header contains the
tag for one of the zero-initialization sections,
then the master should pause after sending the
header. Again, this is because these sections of
contiguous zeros are going to be initialized in
software by the loader kernel. The length of the
pause required is dependant upon the size of the
initialization section (the number of zeros to be
initialized) and the SPI baud rate. It takes one
DSP core cycle (10ns min) to for each zero
a
initialization. If the SPI port were running at
10MHz (100ns), then it would take 320 core
SPI port. You will get an SPIRX buffer overflow
if more than two SPI words are received.
cycles for a single 32-bit word to arrive over the
161_spi.asm
Serial Peripheral Interface compatible port based boot loader for the
ADSP21161 processor
Copyright (c) 2002 Analog Devices Inc. All rights reserved.
version 0.1 6/21/01 - Zero initializations and external memory sections
have not been tested. Check for newest version of the SPI kernel at
ftp.analog.com/pub/dsp/211xx/dev_tools/loader.
version 0.2 8/1/01 - All sections of kernel have been tested.
version 1.0 10/17/01 - R14 = 0xA001F81; was improperly initialized to
R14 = 0xA801F81; in the previous version of the kernel.
version 1.1 1/14/02 - changed some comments and fixed wait state init in
SDRAM init section
version 2.0 05.Sept.02 MSW
- Added initialization of all external memory types
-Added code to patch SPI IVT entry in final init
- Added final-init comments
- Added comments regarding tag info for each section
version 2.1 17.Oct.02 MSW
- Added comments regarding spi overflow errors possible during zero
initialization sections
- Added code to trap on spi overflow
version 2.2 20.DEC.2002 - M.Walsh
- Changed #define SDRAM 1 to #define SDRAM 0
SPI Feedback version 1.0 24.FEB.2003 - B.Mitchell
reset:
nop; // - Instruction specified here is never executed. The core implicitly
// executes
// an IDLE instruction here until 256 instructions are booted. Once the
// kernel is booted, execution resumes at 0x40040 (the SPI Rx ISR). This
// address (0x40005) and the next (0x40006) are also used as a temporary
// buffer to DMA-in words from the SPI port
nop; // scratch memory2
//turn off SPI dma while kernel is executing
ustat1=dm(SPICTL);
bit clr ustat1 RDMAEN; //clear DMA bit in SPICTL
dm(SPICTL)=ustat1;
call user_init; // call subroutine at end of kernel in which users can insert
// initalization code, such as SDRAM, waitstates, etc.
R5=2; // used to decrement tag by two during loading.
L0=0; L1=0; L4=0; // Zero out L-registers so they can be used without wrap
L8=0; L12=0;L15=0; // ie. no circular buffering
M5=0;M6=1; // Setup M-registers to use for various memory transfers
M13=0; M14=1; M15=3;// use to load count in read_dma_info
I15 = 0x40006; // scratch DMA destination address for 32 bit words;
R14 = 0xA001F83; // sets up and enables SPI port with DMA,
// this is also the default setting
R11=DM(SYSCON); // Read current SYSCON setting
R12=PASS R11; // Hold Initial SYSCON setting
I12 = SYSCON; // Address of SYSCON
// ========================== READ_BOOT_INFO =======================================
// Places TAG in R8, Word Count in R2, and Destination Address in R3
// ----------------------------------------------------------------------------------read_boot_info:
call read_dma_info; // place two 48-bit words into 0x40004 and 0x40005
// equivalent to placing three 32-bit words into 0x40006,7,& 8
R2=dm(0x40006); //r2 passes section length
R3=dm(0x40007); //r3 passes destination address
SHARC SPI Booting (EE-177) Page 5 of 20
a
R8=dm(0x40008); //r8 passes data-type tag
// -----------------------------------------------------------------------------------
// ========================== SPI Overflow Detect ====================================
// Monitor the SPI Status register to ensure that no overflow has ocurred. The RBSY
// (receiver busy) bit in SPI is set to 1 when the SPI port receive buffer is full and
// another word is clocked into the shift register. This may happen if the core is
// performing a zero-initialization section, and the SPI-master device continues to
// send data. RBSY is a sticky bit, so it will stay set until the spi port is
// disabled.
// If an overflow is detected the kernel will trap in an infinite loop so that user
// intervention can determine the problem. If this problem occurs, the SPI-master
// device must be configured to pause while the DSP performs the zero initializations.
// This can be done in software by looking at the .LDR section headers, or in hardware
// by configuring the kernel to set a DSP flag pin while it is performing zero// initializations. More information can be found in an EE note on the ADI website
// titled "21161 SPI Booting". http://www.analog.com/dsp
// ---------------------------------------------------------------------------------- USTAT1=DM(SPISTAT);
bit tst USTAT1 RBSY;
if tf JUMP (pc,0);
jump start_loader;
// ============================= FINAL_INIT =========================================
// This code is the very last piece run in the kernel. It uses a DMA to initialize the
// 256 instructions that reside in the interrupt vector table.
// ----------------------------------------------------------------------------------final_init:
R9=0xb16b0000; /* Load instruction PM(0,I8)=PX; */
R11=BSET R11 BY 9; /* Set IMDW to 1 for inst write */
DM(SYSCON)=R11; /* Setup for instruction write */
I4=0x40004; /* Point to 0x040004 for self modifing code*/
PX=pm(0x40004); /* Load instruction to be patched into 0x40040*/
I8=0x40040; /* Point to DMA8 vector to patch */
R9=pass R9, R11=R12; /* Clear AZ, hold initial SYSCON */
DO reset UNTIL EQ; /* set top of loop value to 0x40004 (see comments below)*/
PCSTK=0x40004; /* Set top of PC-stack, so RTI after final DMA goes to 0x40004;*/
//setup DMA parameters
DM(IMSRX)=M6; /* Set to increment internal ptr */
SHARC SPI Booting (EE-177) Page 6 of 20
Loading...
+ 14 hidden pages
You need points to download manuals.
1 point = 1 manual.
You can buy points or you can get point for every manual you upload.