...
SECTIONS
{
#ifdef USE_369_hdr
seg_rth
{
INPUT_SECTIONS( $OBJECTS(seg_rth) $LIBRARIES(seg_rth))
} > seg_rth
#else
//if your own header and start-up is used
seg_rth
{
INPUT_SECTIONS( $OBJECTS(seg_rth) ) //assume your header segment name remains as seg_rth
} > seg_rth
#endif
...
}
If your runtime header is larger than 256 words (48-bit), you must also increase the seg_rth memory space in the MEMORY section of the ldf file. The linker preprocessor directive USE_369_hdr shall be set in the Linker Preprocessing item in the Project Oprions window. If you set the macro, the default 369_hdr is linked, otherwise, your own header will be linked.
3 SHARC PLL Programming
For ADSP-2126x, ADSP-2136x, and ADSP-2137x SHARC processors, in addition to the external CLKCFG signals, the PLL can be configured in software. Thus, various programmable ratios are possible in software by using the PLL multiplier and divisor counts, which are programmed in the power management control register (PMCTL). This also provides flexibility to the user to change the core frequency in software. For proper PLL configuration, follow the recommended sequence, as described in Managing the Core PLL on ADSP-2136x SHARC Processors (EE-290)[3]. Ensure that the DIVEN bit is cleared before switching to bypass mode and before switching out of by-pass mode.
SDRAM frequency (SDCLK) is derived from core clock fCORE devided by SDCKR, where SDCKR = 2, 2.5, 3, 3.5, 4, configured in PMCTL.
Example:
System crystal frequency is 20 MHz, and we want to have core clock frequency at 320 MHz, we shall configure PMCTL as follows.
PMCTL.BIT.PLLM = 16; //PLL 16x
PMCTL.BIT.PLLD = 0; //divided by 1
PMCTL.BIT.DIVEN = 1; //PLL Divider enable
PMCTL.BIT.SDCKR = 1; //CCLK_SDCLK_RATIO 2.5
Wait at least 4096 cycles for the PLL to lock the frequency.
4 JTAG Design
Most systems are initially designed for JTAG connectivity, so that the prototypes and pre-production units may be tested and debugged with a JTAG ICE (in-circuit emulator). In this case, the JTAG /TRST signal (TAP reset) is driven by the ICE. However, if the system runs in standalone mode by booting operation or whenever the ICE is not used, connect the /TRST signal to board ground. Failing to ground the /TRST signal can lead to boot failures and memory access failures during runtime. Furthermore, pull-down resistors on /TRST are not recommended because SHARC processors already have an on-chip pull-up resistor on this signal.
5 Interrupts
There are a few special interrupt handling issues that are worth your attention.
5.1 Double SPORT/SPI Interrupts
Consider a scenario where SPI is used in core mode to transmit data. When the core encounters a transmit buffer empty condition, a transmit interrupt is generated. Inside the transmit interrupt service routine, the software writes a new value to the transmit buffer and returns from interrupt. In such a situation, after returning from an ISR, the processor again detects a transmit buffer empty condition and sequences to SPI transmit ISR. This happens due to highly pipelined IOP writes. After writing in to transmit buffer it takes 10 core clock cycles for the actual value to be written and update the transmit buffer status to "not empty". Therefore, under such scenarios, delay the return from interrupt routine for at least 10 core clock cycles.
5.2 DAI Interrupts
Unlike other interrupts, the DAI interrupt is not cleared automatically inside the DAI interrupt service routine. Once latched, the interrupt remains latched until the latch status is cleared explicitly by reading the DAI interrupt latch register. Reading the DAI interrupt latch register clears DAI interrupts. If this does not occur, the program will keep sequencing to the DAI interrupt service routine every time after exit from it.
5.3 Special Interrupts
There are some interrupts, UART0, UART1, TWI and PWM, which are not connected to the processor core interrupts by default. To use any of those interrupts, the Peripheral Interrupt Control Register (PICRx) must be programmed explicitly to substitute the default interrupt with the value of one of the above interrupt sources. For example, PWM interrupt select value is 0x18, you can use any segment of PICRx for substitution. See example shown below, supposing that PWM_ISR() is the Interrupt Service Routine for PWM.
//use PICR0 segment 0
PICR0 = 0x18; // PICR0[4:0] = 0x18
interrupt(SIG_P0, PWM_ISR); //route PWMI at Peripheral Interrupt Priority 0
//use PICR1 segment 1
PICR1 = 0x300; // PICR1[9:5] = 0x18
interrupt(SIG_P7, PWM_ISR); //route PWMI at Peripheral Interrupt Priority 7
//use PICR2 segment 4
PICR2 = 0x30000000; //PICR2[24:20] = 0x18
interrupt(SIG_P16, PWM_ISR); //route PWMI at Peripheral Interrupt Priority 16
//use PICR3 segment 0
PH_PICR3 = 0x18; //PICR3[4:0] = 0x18
interrupt(SIG_P18, PWM_ISR); //route PWMI at Peripheral Interrupt Priority 18
PWM period completion status bits are set in PWMGSTAT regardless if the PWM.IRQEN is set. However, interrupt occurs only if the IRQEN is set. The status bit must be cleared by writing 1 to the bit, even though PWMGSTAT does not reflect the clear status.
5.4 Disabling Peripheral inside Its DMA Interrupt Service Routine
SHARC processor peripherals support DMA mode for data transfer. The DMA interrupt is generated when the DMA transfer count expires. When a peripheral is configured to receive data, the DMA count expires when the entire data is received and moved in to the internal memory. When a peripheral is configured to transmit data out, data remains in the DMA FIFO of the peripheral even though the DMA count expires and generates an interrupt. If the software intends to disable the DMA and the peripheral inside the ISR, it should poll the DMA FIFO status first. When the FIFO shows empty status, the peripheral can be safely disabled; otherwise, data loss may occur.
6 Data Length
With the VisualDSP++ 4.5 C compiler, regardless data type as byte, word or long, each of them occupies 32-bit memory. Thus, if you need to have byte or word length, use bit definition structure.
Example:
typedef union st_ditusrbit0 // User Bits Buffer Registers for Subframe A/B Registers
{
int ALL; // All 32 bits
struct // Word Access
{
int H :16;
int L :16;
} WORD;
struct
{
int BYTE3 :8; // bit[31:24], byte 3
int BYTE2 :8; // bit[23:16], byte 2
int BYTE1 :8; // bit[15:8], byte 1
int BYTE0 :8; // bit[7:0], byte 0
} BYTE;
}ST_DITUSRBIT0;
Then, if you declare a variable
ST_DITUSRBIT0 var1;
var1.BYTE.BYTE0 = 0xFF; //byte access
var1.WORD.H = 0xFFFF; //word access
var1.ALL = 0xFFFFFFFF; //long access
7 Include Relative Path
Include relative path is relative to the make file, which is in the same directory as the project file. If you have header files in different directory, you need to include the directory paths appropriately to the “Additional include directories” field on Project Options->Compiler->Preprocessor page.
Example:
Project: Robot Eye
Directory structure:

Project file “Robot Eye.dpj” is in Robot Eye directory, there are header files in General directory, Source\Action, and Source\BIT IF directories. To include all those header files, the following relative paths shall be added to the “Additional include directories” field.
.\Source\Action; ..\General; “.\Source\BIT IF”;
Relative path is referenced to the project location. The dot (.\) in the relative path refers to the project directory. Double dots (..\) refer to the directory one level above the project. The double quote is needed if any directory name has space within. Use semicolon to separate paths.

8 Allocate Program/Data Section
Open the linker description file (app.ldf) from your project. The ldf file can be imported from another project, or created by using menu Tools -> Expert Linker -> Create LDF tool. By default, PM is allocated in internal RAM block 0, but if the code size exceeds the block size, linker error would occur. In that case, other RAM block can be used for more code space. For example, RAM block 1 can be used for PM. To do so, you need to add a new memory segment by right-clicking the Memory Map section, and click the popup menu New -> Memory Segment, which opens Memory Segment Properties window. Give a name for the memory segment, such as seg_pmco2 in the example below, and assign start address and end address. Since it is used for program, the width shall be 48 bits.
Then drag-n-drop the object files from the Input Sections to the block in the Memory Map section. You may also adjust the start / end address and size for other memory segments.

9 Precision Clock Generators
PCG clock input source can be one of the XTAL buffer, PCLK or external input on any DAI pins.
9.1 Clock Input Source
Setting up the clock source has a little trick. If XTAL buffer is used as the clock source, set PCG_CTLx1. CLKxSOURCE = 0; if PCLK is used as the clock source, set PCG_SYNCx. CLKx_SOURCE_IOP = 1. This setting overwrites PCG_CTLx1. CLKxSOURCE setting. If clock input comes from external source, set PCG_CTLx1. CLKxSOURCE = 1, which sets the clock input from PCG_EXTx_I, which is from one of the DAI pins. To route a DAI pin to PCG_EXTx_I, you need to set SRU_CLK4 or SRU_CLK5 registers.
9.2 Clock Output
PCG clock and frame sync output can be routed to any DAI pins or internal modules such as SPORT or S/PDIF, but cannot be fed to its own input.
9.3 Clock Divisor
The output clock frequency is derived from the input to the PCG with a 20-bit divisor. If the divisor is zero or one, the PCG’s clock generation unit is bypassed, and the clock input is connected directly to the clock output. Otherwise, the PCG unit clock output frequency is equal to the input clock frequency, divided by a 20-bit integer as shown in the following equation.
Frequency of Clock Output = Frequency of Clock Input / Clock Divisor
This integer is specified in bits 19–0 of the PCG_CTLx1 registers for units A, B, C and D respectively, as PCG_CTLA1.BIT.CLK_DIV in the example below.
9.4 Example 1
In this example, clock input comes from the peripheral clock, PCLK = 160 MHz, and output to DAI pin 20, at frequency 80 MHz.
//set clock input from PCLK
PCG_SYNC.BIT.CLKA_SOURCE_IOP = 1; //this setting overwrites PCG_CTLA1.CLK_SOURCE setting
//set up clock frequency
PCG_CTLA1.BIT.CLK_DIV = 2; //PCLK / 2 = 160 / 2 = 80 MHz
//set up clock output to DAI20
SRU(HIGH, PBEN20_I);
SRU(PCG_CLKA_O, DAI_PB20_I);
//enable PCGA
PCG_CTLA0.BIT.ENCLK = 1;
9.5 Example 2
In this example, clock input comes from DAI pin 1 with frequency 80 MHz, output to SPORT6 clock input at frequency 20 MHz.
//set up clock input from DAI01
SRU (LOW, PBEN01_I); //DAI01 is used for input
SRU (LOW, DAI_PB01_I); //low the pin buffer input
SRU (DAI_PB01_O, PCG_EXTA_I); //route DAI01 signal to PCGA clock input
PCG_CTLA1.BIT.CLKASOURCE = 1;
//set up clock frequency
PCG_CTLA1.BIT.CLK_DIV = 4; //80 / 4 = 20 MHz
//set up clock output to SPORT6 clock input
SRU(PCG_CLKA_O, SPORT6_CLK_I);
//enable PCGA
PCG_CTLA0.BIT.ENCLK = 1; //enable clock
10 UART Configurations
Regarding UART baud rate configurations, there was an error on page 11-11 in the ADSP-21368 SHARC Processor Hardware Reference, Rev. 1.0. It says that
Divisor = 1 when UARTxDLL = UARTxDLH = 1
as shown in the excerpt below.

In fact, to make divisor equal to 1 in order to achieve the highest baud rate, UARTxDLL shall be 1, while UARTxDLH shall be 0. To be general, one can use the following macros to configure UARTxDLL and UARTxDLH registers.
#define DSP_SCLK (CCLK / 2) //CCLK is the CPU clock
#define DSP_UART_BAUD_RATE_DIVISOR(baud) (DSP_SCLK / (baud * 16)) //baud is the desired baud rate
//assume pUart points to the UART to be used
pUart->LCR->BIT.UARTDLAB = 1; //enable baud rate setting
*pUart->DLL = DSP_UART_BAUD_RATE_DIVISOR(baud) & 0xFF; //UARTxDLL setting
*pUart->DLH = (DSP_UART_BAUD_RATE_DIVISOR(baud) & 0xFF00) >> 8; //UARTxDLH setting
pUart->LCR->BIT.UARTDLAB = 0; //disable baud rate setting
11 Generate Bootable App Image
To enable the DSP run from an external device such as flash, we need to use the loader tool (elfloader.exe) that adds a loader kernel to your application code to create a bootable application image (the loader file app.ldr), and then program the image to your flash. You can use either the IDE tool or post-build command to generate the ldr file.
11.1 Use the IDE Interface
Select Loader file type on Project General category.

Specify the Load property.

Click OK to save the selections. Selecting Build Project from the Project menu generates a loader file. VisualDSP++ invokes the elfloader utility to build the output file.
11.2 Use Post-Build Command
Use the following syntax for the SHARC loader command line.
elfloader inputfile -proc processor -switch [-switch …]
Example:
elfloader ".\Debug\Robot Eye.dxe" -proc ADSP-21369 -bprom -o ".\Debug\Robot Eye.ldr"

You also need to make sure that the loader executable directory has been added to the environment PATH variable.

* App notes and source code from Analog Devices are copyrighted by Analog Devices, and provided here for your reference only.