TP C54 PDF
TP C54 PDF
TP C54 PDF
DSP TMS320C54
1 Implantation assembleur du filtrage FIR
1.1 Objectifs
Cette première partie du TP permet de :
- Parcourir l’architecture du noyau de calcul du DSP C54 (Architecture Harward, mémoire
programme et mémoire donnée, multiplieur, accumulateurs, scaler, bits de garde) et le
mode d’adressage indirect.
- Prendre en main une partie de l’environnement de développement du
CodeComposerStudio : Edition, Build, Load, Run, Debug, Probe, Graph, Display
- Comprendre l’implantation assembleur d’un filtre FIR en utilisant l’instruction MACD
(Cycle Read/Write) associé à un Repeat Buffer (via l’instruction RPTZ)
- Revoir les notions de réponse impulsionnelle, indicielle, fréquentielle et l’opération de
convolution.
2
Figure 2 : Diagramme d’ensemble du noyau de calcul du TMS320C54.
3
programmer et configurer l’environnement logiciel complexe associé à la carte DSP (Figure 3).
N’hésitez pas à vous reporter à l’aide (touche F1). Vous pouvez accéder à de nombreuses
commandes via les icônes de l’interface.
1.3.1 Projet
- Via moodle, récupérer les sources du TP : TP-C54.zip et désarchiver sur une clé USB.
Changer les permissions sur ces fichiers : autoriser l’écriture.
- Lancer la machine virtuelle. Passer les droits d’accès à la clé USB du système hôte à la
machine virtuelle.
- Alimenter la carte DSP, puis quand la séquence d’initialisation est finie connecter la carte
au PC avec le câble USB.
- Lancer CCS.
- Ouvrez le projet firmacd2.pjt désarchivé (attention au chemin d’accès) qui se trouve dans
le répertoire TPC54/firmacd2 via le menu Project/Open. Un projet contient les fichiers
sources (C, assembleur), les librairies, les fichiers de configuration de la mémoire de la
carte DSP et tout ce qui est nécessaire pour construire un programme exécutable.
- Ouvrez (double click) le fichier firmacd.asm qui se trouve dans source.
4
a. Faire un schéma des opérations et transferts mémoires effectués dans la boucle de
traitement.
b. Illustrer les liens entre cet algorithme et le produit de convolution.
Vous devez avoir (sauf les deux graphes) l’écran ci-dessous (Figure 4).
Figure 4 : Filtrage FIR sous CodeComposerStudio. Visualisation de la mémoire programme et data, des registres
CPU, du fichier source, de la réponse impulsionnelle et fréquentielle du filtre implanté.
5
Votre code ayant été chargé sur le DSP, il est prêt à être exécuté. Il suffit de lancer Debug/Run.
Il ne se passe rien sauf l’affichage de CPU RUNNING en bas à gauche de la fenêtre. Arrêtez le
calcul via Debug/Halt. S’affiche alors CPU HALTED.
Le DSP a bien travaillé mais vous n’avez pas mis de signal à l’entrée de la carte, ni récupéré la
sortie sur un oscilloscope. Quand bien même, vous n’auriez rien vu, car votre boucle de calcul
prend en entrée ce qui se trouve à une case mémoire étiquetée in et envoie la sortie sur une case
étiquetée out. Or, rien ne relie ces deux cases mémoires aux registres d’entrée (DRR) et de sortie
(DXR) de la carte.
Nous verrons dans la deuxième partie du TP comment accéder aux entrée/sortie analogique de la
carte, mais ici nous allons étudier la fonctionnalité Probe offerte par le CCS.
6
Nous allons maintenant exécuter le programme en mode pas à pas (touche F10). Le fichier
infir.dat contient un échantillon de valeur 0x4000, suivi de 39 échantillons de valeur nulle.
- En mode pas à pas, faites dérouler sur une dizaine d’échantillons infir.dat. Observez
l’évolution de la mémoire et des différents registres. Commentaires ?
- Rajoutez un point d’arrêt avec l’icône ‘main’ sur la dernière ligne du code. Continuez à
dérouler le fichier infir.dat en utilisant l’icône Run.
- Rembobinez infir.dat.
1.3.5 Graphes
CCS inclut un outil graphique permettant de représenter des zones de mémoire sous forme de
graphe temporel, fréquentiel, constellation ….
- Insérez un graphe via le menu View/Graph/TimeFrequency. On positionnera les champs
suivants : StartAddress = out, Page=Data, AcquisitionBufferSize=1, IndexIncrement=1,
DisplayDataSize=40, DSPDataType=16 bit integer signed. N’hésitez pas à cliquez sur
Help pour avoir des informations sur les différents champs.
- Insérez un deuxième graphe identique au précédent en modifiant le champ DisplayType à
FFT magnitude.
- Le fichier ayant été rembobiné et un point d’arrêt en fin de boucle ayant été positionné, ré
exécuter votre programme en utilisant Restart dans le menu Debug.
On peut également utiliser les graphes sur les fichiers de sortie associés à un Probe point. Au
préalable, il suffit de charger ce fichier en mémoire.
- Chargez le fichier outfir.dat en mémoire à l’adresse 0x8000 via le menu File/Data/Load.
Address=0x8000, Length=0x0029.
- Créez un nouveau graphe avec les paramètres de votre choix.
1.3.6 Filtrage
5) Que venez-vous de tracer ?
6) Quelles sont les caractéristiques du filtre implanté dans ce code ?
- Copiez le fichier infir.dat dans un autre fichier. Modifiez-le, de telle sorte que vous puissiez
tracer la réponse indicielle de ce filtre.
7) Réalisez les manipulations nécessaires pour tracer la réponse indicielle. Quelle est sa
forme ?
8) En fin du fichier firmacd.asm, on donne les coefficients d’un autre filtre. Modifiez le
fichier pour que ce soit ce nouveau filtre qui soit utilisé. Réalisez les manipulations
nécessaires (Build, Load ….).
a. Tracer sa réponse impulsionnelle et fréquentielle sous CCS.
b. Quelles sont les propriétés de ce filtre ?
7
Vous devez être capable de comprendre un petit code assembleur qui implante du filtrage et de
l’adapter pour changer de filtre.
Vous devez avoir en tête les principaux éléments concernant les filtres FIR (Coeff de la fonction de
transfert, réponse impulsionnelle, réponse fréquentielle, phase linéaire).
8
2 Partie 2 : Programmation C et filtrage FIR
2.1 Objectifs
Cette deuxième partie va vous permettre de découvrir :
- comment accéder en C au hardware de la carte (codec, switch, LED),
- comment implanter la convolution en C,
- comment implanter un filtre en C
- comment caractériser en fréquence un système linéaire.
La fonction UserTask() est la fonction principale qui va être appelée par le gestionnaire de
tâche du DSP.
9) Repérez dans cette fonction les appels de fonctions associées au codec, aux interrupteurs et
aux LED.
9
- Générez l’executable via la commande Build. Chargez le programme sur le DSP
(File/LoadProgram)
- Connectez un signal en entrée (signal audio, ou signal du générateur), observez la sortie
(via un oscilloscope ou avec vos oreilles)
- Exécutez le programme (Debug/Run).
- Manipulez les interrupteurs pour décroître progressivement le nombre de bits de
quantification
10) A partir de combien de bits percevez vous une différence (visuelle sur l’oscilloscope,
qualitative avec vos oreilles)
- Fermez ce projet.
- Vous pouvez faire rapidement la même manipulation avec le projet sampling_rate pour
étudier l’effet de la fréquence d’échantillonnage et du repliement de spectre associé.
12) Analysez le contenu de la fonction UserTask(). Quelles sont les fonctions appelées pour
réaliser le filtrage ? Où sont définis les coefficients des filtres ?
13) Mais au fait, pourquoi utilisez des fenêtres pour synthétiser des filtres FIR ?
- Ouvrez le fichier fir_filters_asm.asm. Dans la section _FIR_filter_asm, repérez la boucle de
convolution.
14) Quelles sont les instructions utilisées ? Quel adressage spécifique est utilisé ?
15) Ouvrez le fichier fir_filters.c. Dans la fonction FIR_filter(), comment est calculé le produit
de convolution ?
10
16) En utilisant la méthode proposée à la question précédente, tracez la réponse en fréquence
du système correspondant à la carte. Un filtre est-il présent ? Si oui, d’où vient-il ?
17) Positionnez les switchs pour choisir un filtre. Tracez en la réponse en fréquence.
18) Pour une fréquence dans la bande passante du filtre, quel phénomène observez vous si vous
augmentez progressivement l’amplitude du signal d’entrée ?
Pour la question 17), on pourra vérifier les résultats obtenus en utilisant les probe points et les
graphes vues dans la partie 1 pour tracer les réponses des filtres.
- L’utilisation des probe points perturbe la lecture des switchs. Dé-commentez la ligne
switch_value=6, (Mettez la valeur du filtre que vous voulez étudier)
- Build, Load …
- Positionnez un probe point sur la ligne 124 à l’appel de bargraph_6dB().
- Connectez le au fichier inpulse.dat (il contient une impulsion et 80 zéro), avec
Address=&mono_input et Length=1
- Positionnez un point d’arrêt sur le premier if ()
- Créer deux graphes, l’un en temps, l’autre en FFT magnitude avec les réglages suivants :
Start_Address=&left_output, Acq.BufferSize=1, DisplayDataSize=82, DSPDataType=16-
bit signed integer.
- On peut faire un View/Memory à partir de l’adresse &left_input.
- Run, Run, Run …. Run et on obtient quelque chose comme la Figure 6. On rembobine, et
encore un coup pour le plaisir !
21) Analysez le contenu de la fonction UserTask(). Quelles sont les fonctions appelées pour
réaliser le filtrage ? Où sont définis les coefficients des filtres ?
22) Ouvrez le fichier IIR_filters_first_order.c. Analyser les fonctions de calcul
first_order_IIR_direct_form_I() et first_order_IIR_direct_form_II(). Quels sont les
différences entre ces deux modes de calcul ?
On pourra aller voir les modifications de ces fonctions pour des filtres d'ordre 2 et 4 en allant
voir les fichiers IIR_filters_second_order.c et IIR_filters_fourth_order.c .
11
- Chargez le sur la carte (File/Load) et exécutez le (Debug/Run). On choisira la position ad
hoc pour les switchs.
Figure 6 : Réponse impulsionnelle et fréquentielle d’un FIR synthétisé par une méthode de fenêtre.
3 Conclusion
Vous avez mis un orteil dans le monde des DSP, à suivre …
12
4 Annexe : Architecture mémoire du C54
13
5 Annexe : Fichier firmacd.asm
.mmregs
.def _start
.global adr_debut_dat, adr_fin_dat, adr_coef,_start
.global adr_coef
.sect ".coef"
adr_coef .word 0X400
.word 0X400,0X400,0X400,0X400,0X400
.word 0X400,0X400,0X400,0X400,0X400
.word 0X400,0X400,0X400,0X400,0X400
N .set 16
.bss adr_debut_dat,N+1
adr_fin_dat .set adr_debut_dat+N-1
.bss in,1
.bss out,1
.text
* Initialisation de DP à 0 et de FRCT à 1
_start: LD #0, DP
SSBX FRCT ; Fractional Mode -> left shifting of the
multiplier
* Boucle de filtrage
RPTZ A, #N-1
MACD *AR1-, adr_coef, A
14
6 Annexe : Fichier fir_filter_asm.asm
;******************************************************************************
;* FUNCTION DEF: _FIR_filter_asm *
;******************************************************************************
_FIR_filter_asm:
;Start by shuffling values in buffer along and inserting new value at buffer[0]
FRAME #1
POPM AR4 ; Restore registers
POPM AR3
POPM ST1 ; Restore flags
POPM ST0
15
7 Annexe : Fichier fir_filter.c
short int FIR_filter(signed int * filter_constants, signed int input)
{
static int value[FIR_FILTER_SIZE]; /* Retain value between calls */
signed int return_value;
signed int i; /* Index into filter constants */
long product;
static signed int j = 0; /* Index into input array */
product = 0;
return(return_value);
}
16
8 Annexe : Fichier IIR_filters_first_order.c
/*****************************************************************************/
/* A first order infinite impulse response (IIR) filter can be represented */
/* by the following equation: */
/* H(z) = b0 + b1.z^-1 */
/* ------------ */
/* a0 + a1.z^-1 */
/* where H(z) is the transfer function. a0 is always 1.000 */
/* In order to implement this function on a fixed point processor, the value */
/* 32767 is used to represent 1.000 */
/*****************************************************************************/
#include <stdio.h>
/* Numerator coefficients */
#define B0 0
#define B1 1
/* Denominator coefficients */
#define A0 2
#define A1 3
/*****************************************************************************/
/* first_order_IIR_direct_form_I() */
/* First order direct form I IIR filter. */
/* PARAMETER 1: Coefficients in order B0 B1 A0 A1. */
/* This implmentation uses two buffers, one for x[n] and the other for y[n] */
/*****************************************************************************/
17
/*****************************************************************************/
/* first_order_IIR_direct_form_II() */
/* First order IIR (canonic) filter. */
/* Uses 32767 to represent 1.000. */
/* Note that input is divided by 2 to prevent overload. */
/*****************************************************************************/
18