Data memory, program memory and
TMS320C50 memory maps
Memory maps – microprocessor mode (pg. 6.3):
Program space Data space
0000h interrupts and 0000h memory-mapped
reserved area 005Fh registers
002Fh (external)
0030h external 0060h on-chip
07FFh memory 007Fh DARAM B2
0800h on-chip 0080h reserved
SARAM 00FFh area
(RAM=1)
or external RAM 0100h on-chip DARAM B0 (CNF=0)
2BFFh (RAM=0) 02FFh reserved (CNF=1)
2C00 external 0300h on-chip DARAM
FDFF memory space 04FFh Block B1
FE00h on-chip DARAM B0 0500h reserved
(CNF=1) 07FFh area
FFFFh external (CNF=0)
0800h on-chip SARAM (OVLY=1)
2BFFh external (OVLY=0)
2C00h external
FFFFh memory space
For
the DSK module we shall normally load our programs starting from 0A00h
and data from 0F00h.
Data memory access – the paged memory and direct addressing
The TMS320C50 can address 64k words of data memory. Because 64k positions would require 16 bits for addressing, Texas instruments decided to organise the memory as 512 blocks of 128 words each, and when using direct addressing mode the programmer would first specify the page and then use the memory within that page, giving only an off-set address (off-set from the base address of the particular page).
The data page can be selected with the command ‘load data page immediate’, for instance
LDP #2 ; for loading the data page register with page 2
; (base address = 100h).
Page 0 corresponds to positions 0 to 127 (7Fh), page 1 to positions 80h to 0FFh, and page 2 to 100h to 17Fh. After specifying the page, whenever the programmer uses direct addressing mode the DSP assumes that all accesses are made to that particular page and the address (for the 128 positions) only needs 7 bits and can be packed together with the op-code for instructions such as ‘load accumulator, or ‘store accumulator’.
The following program uses immediate addressing mode to select page 2, and then direct addressing to write 1 to data memory 100h, 101h and 17Fh:
LDP #2 ; Page 2 (base address = 0100h)
LACC #1 ; Load accumulator immediate with value 1
SACL 0 ; Save accumulator to memory position 0 in the
;current page (100h)
SACL 1 ; Save accumulator to memory position 1 in the
; current page (101h)
SACL 7Fh ; Save accumulator to memory position 7Fh in the
; current page (17Fh)
Notice that the
arguments can be in decimal (default), hexadecimal (as on 7Fh), or binary.
Addressing modes – Indirect addressing
There are three modes of addressing available on the 320C50:
1. Immediate (argument follows with a # in front, i.e., argument is in program memory)
2. Direct (using a data page and addressing using off-set only)
3. Indirect
Examples of immediate and direct addressing mode have been given above.
An alternative addressing mode, which is offers a very powerful and efficient way of dealing with arrays is also provided: the indirect addressing mode makes use of one of the eight Auxiliary Registers to address the memory. It is done like this: First we select which of the eight Auxiliary Registers we want to use, then we load the address we want to access into that register, and finally we use it:
LARP AR7 ; Load Auxiliary register pointer with 7,
; i.e., choose register 7
LAR AR7,#074Fh ; Load Auxiliary Register Long Immediate
LACC * ; Load accumulator with content of memory 74Fh
The method of indirect addressing allows auto-increment, auto-decrement, and re-loading of ARP with a different register in the same single instruction and shows its muscle in do-loops such as:
* Let’s copy 20 values from 820h onwards into the internal memory of the chip 100h onwards
*
LARP AR1 ; Use AR1 as pointer of source
LAR AR0,#19 ; AR0 = Number of values -1
LAR AR1,#820h ; AR1 = pointer of source values starting in 820h
LAR AR2,#100h ; AR2 = pointer of destinations starting in 100h
CCRRL:
LACC *+,0,AR2 ; Notice the auto-increment, zero-shifts, and
; ARP=2
SACL *+,0,AR0 ; Notice the auto-increment, zero-shifts, and
; ARP=0
BANZ CCRRL,*-,AR1 ; Branch if AR0 not zero, decrement AR0,
; ARP = AR1
The same result of
the extract of program above could be obtained using a ‘Block-move’ instruction
(TMS320C5x User’s Guide 1993, pg. 6.37).
Interrupt vectors and priorities:
Interrupt name Vector priority function
RESET 0 1 (highest) external reset signal
INT1 2 3 external user interrupt #1
INT2 4 4 external user interrupt #2
INT3 6 5 external user interrupt #3
. . . .
. . . .
. . . .
INT16 32 (20h) 18 external user interrupt #16
TRAP 34 (22h) N/A TRAP instruction vector
NMI 36 (24h) 2 non-maskable interrupt
RINT 080Ah 7 serial port receive interrupt
XINT 080Ch 8 serial port transmit interrupt
(TMS320C5x User’s Guide 1993, p. 5-5)
TMS320C50 INTERNAL
TIMER OPERATION
(TMS320C5x User’s Guide 1993, pg. 5-45-5.47, 6-15)
The TMS320C50 provides an on-chip timer that can be used to generate sample clock (sampling frequency) for an analogue interface chip (AIC).
The sampling frequency is given by, and the master clock was programmed to be MCLK = 10 MHz (please take my word for it).
Obs: There is a reconstruction low-pass filter on the D/A part of the AIC whose cut-off frequency is , so make sure that Flp is greater than fsam/2.
NB: This is NOT your filter it is just to smooth out the D/A output!
2.1 – Try the program:
DSK5L ECHOINT.DSK -C2 (or -C1)
2.2 – Read the source code of ECHOINT and make sure you understand the ISR, especially the LAMM and the SAMM instructions. Follows the extract for the ISR of the receiver serial interrupt (RINT):
RINT: PUSH ; We are going to change the accumulator
LAMM DRR ; Load Acc with Data Rx Register (i.e. read A/D)
AND #0FFFCh ; IMPORTANT!! Make d00=d01=0
SAMM DXR ; Store Acc into Data Tx Register (echo to D/A)
POP ; restore Acc
XINT: NOP ; No operation …
NOP ; … again
RETE ; return from interrupt & re-enable interrupts
FILT1:
The program FILT1 given is a simple modification of ECHOINT. In FILT1 the interrupt service routine RINT
i) reads a sample from the A/D (LAMM DRR),
ii) applies a low-pass filter to the input signal x(n) using the equation
y(n) = a0 x(n) + a1 x(n-1) +a2 x(n-2) + a3 x(n-3)
with a0 = a1 = a2 = a3 = 0.25, that is,
y(n) = [x(n) + x(n-1) + x(n-2) + x(n-3)] / 4, and then
iii) echoes the result y(n) to the D/A (SAMM DXR).
– Try the program out and observe the result on the oscilloscope:
DSK5L FILT1
4.2 – Read the source code of FILT1.ASM and make sure you understand the ISR RINT, especially the DMOV instructions. Follows the extract for the ISR of the receiver serial interrupt (RINT):
RINT: PUSH ; save accumulator
ZAC ; Acc = 0
LDP #X0 ; load data page of X0
DMOV X2 ; X2 becomes X3
DMOV X1 ; X1 ages to X2
DMOV X0 ; X0 -> X1
LAMM DRR ; Load Acc with Data Rx Register (i.e. read A/D)
SACL X0 ; Save new sample onto X0
ZAC ; Acc = 0
ADD X0
ADD X1
ADD X2
ADD X3
SFR ; divide by two
SFR ; and again, i.e. y(n) = y(n) / 4
AND #0fffch ; IMPORTANT!! Make d00=d01=0
SAMM DXR ; Store Acc into Data Tx Register (echo to D/A)
POP ; restore Acc
XINT: NOP
NOP
RETE ;
return from interrupt & re-enable interrupts
PRODUCT MODES (pp. 3-41, 4-220, TMS320C5x User’s Guide 1993)
00 No shift ; normal, ‘vanilla’ use
01 left shift 1 bit ; for use when using fractions with Q15 notation
10 Left shift 4 bits ; for use with MPYK, which uses 13 bits (Q12 * Q15 = Q27)
11 Right shift 4 bits ; to avoid overflow when using MAC with up to 128 products.
Please read a brief explanation about a few special instructions:
SPM 1 sets Product mode to 1. This means that all products are left-shifted one position for correcting the result to fit into the 32 bits of P using Q30 notation. This is done when using the Q15 and 31 notations for making the best possible use of the 16 bit values available to represent fractions. Try to multiply +1 by +1 in the Q15 notation. You get 7FFFh * 7FFFh, and when you do it you will see that you’ve got two zeroes as the most significant bits, i.e., the sign bit gets duplicated. If you try to read this number in Q31 notation it will be +0.5 and not the +1 we would like to see there. In other words Q15 * Q15 = Q30 and not Q31. And because we are to save as the result the 16 most significant bits of the result (SACH) we use SPM 1 to give us the extra shift left. Alternatively we could have done it with no shifts on the P register, but one shift when saving: SACH YN,1.
LT <dma> = load T with the content of data memory addressed by
MPY <dma> = multiplies T by contents of data memory addressed by
APAC = add P to Acc
The LTD instruction does the following:
1) PC = PC+1 (program counter is incremented)
2) T register is loaded with value in data memory
3) contents of the data memory are copied into next memory position
4) Acc = Acc + P
register
Use the following code as a starting point:
.ds 0F00h
A0 .word 8192 ; 0.25 in Q15 notation
A1 .word 8192
A2 .word 8192
A3 .word 8192
X0 .word 0 ; storage for sample X(n)
X1 .word 0 ; x(n-1)
X2 .word 0 ; x(n-2)
X3 .word 0 ; x(n-3)
dummy .word 0 ; just in case you do an LTD by mistake…
Y0 .word 0 ; y(n)
; …
RINT:
PUSH ; save accumulator
SPM 1 ; to correct for multiplications (Q15*Q15 = Q30)
LDP #X0 ; load data page of X0
FIR: ZAC ; initialise Accumulator to zero (ZERO ACC)
LT X3 ; load T with X3
MPY A3 ; P = a3 x(n-3)
LTD X2 ; LTD = accumulate previous P into Acc so that
; Acc = a3 * x(n-3),
; load T with X2, and
; DMOV X2 to X3, i.e., ‘age’ it (* 1/z)
MPY A2 ; Acc = a3 x(n-3), P =a2 x(n-2)
LTD X1 ; Acc = a2 x(n-2) + a3 x(n-3), T = X1, X1 moved to X2
MPY A1 ; P = a1 x(n-1)
LTD X0 ; Acc = a1 x(n-1) +a2 x(n-2) + a3 x(n-3), T = X0, X0 ‘aged’
MPY A0 ; P = a0 x(n)
APAC ; Acc = a0 x(n) + a1 x(n-1) +a2 x(n-2) + a3 x(n-3)
SACH Y0 ; Save result onto y(n)
LAC Y0 ; bring it into low ACCU
AND #0FFFCh ;IMPORTANT!!. Make d00=d01=0
SAMM DXR ; Store Acc into Data Tx Register (echo to D/A)
LAMM DRR ; Load Acc with Data Rx Register (read x(n) fromA/D)
SACL X0 ; Save new input value. Notice how all others ‘aged’ by
; falling 1 place in memory
POP ; restore Acc
XINT:
NOP
NOP
RETE ; return from interrupt & re-enable interrupts
Hint: Use my program firfilt.m, for MATLAB
to obtain the coefficients for the filter.
Exercise 6:
The program you have written for exercises 4 (FILT2) and 5 (FILT3) applies a low-pass filter to the input signal x(n) using the general FIR equation
but it does the multiplications one by one, using in-line code. Examine the code for ‘LOPASS.ASM’ which implements a filter of 80 coefficients using the ‘repeat’ instruction as below and modify your code accordingly.
LAR AR0,#XNLAST ; load AR0 with address of last
; element
ZAP ; ZERO ACC AND PRODUCT REGISTERS
MAR *,AR0 ; AR0 is the current AR register.
; (this is the same as LARP AR0)
RPT #79 ; Repeat the next instruction 80 times
MACD #a0,*- ; the complete coefficients table.
APAC ; Accumulate last product
(hint: read MACD_instruction_and_recursive_filters.docx, available in Blackboard, as it will help… a lot!).
Exercise 7:
Now modify the code to implement a high-pass transfer function, with 21 taps (21 coefficients). Hint: Use my firfilt.mscript again – choose order 10.
Exercise 8:
Modify the code to a general recursive structurecapable of implementing either FIR or IIR filters, i.e. one that filters the signal according to the general expression
Test it with the 2 examples below:
8.1
yn = yn-1 + 0.2 xn – 0.2 xn-5
8.2
…and with the filter that implements the following z-transfer function:
NB: On the numerator the coefficients for the terms in z3 and z1 are zero.
NUMdp =0.1026 0.0000 -0.2052 0.0000 0.1026
DENdp = 1.0000 -1.2481 1.3227 -0.6676 0.3227
For the sampling rate of 10 kHz, plot the frequency response for (8.1) and for (8.2) from DC to 5 kHz.
Hint #1: 8.2 is a band-pass filter.
Hint #2: 1.2481 = 1 + 0.2481.
SACH Y0 ; save high ACCU into y0
LAC Y0 ; bring it into low ACCU
and #0fffch ; just in case, make d00=d01=0
SAMM DXR ; Store acc into Data Tx Register (echo to D/A)
LAMM DRR ; read new sample
SACL X0 ; Save new sample onto X0
POP ; restore Acc
XINT:
NOP
NOP
RETE ; return from interrupt & re-enable interrupts