A FAIRE A LA FIN DE CHAQUE SEANCE POUR COPIER VOS FICHIERS SUR UN DISQUE PARTAGE (ET PERMETTRE LA RECUPERATION DES FICHIERS SI UN MEMBRE DU BINOME EST ABSENT) copier coller dans une console:
rsync -av --delete ~/workspace_ac6 /mnt/etu/s4
et completer la ligne en appuyant 3 fois sur la touche Tabulation, puis entrée.
Les informations nécessaires au lancement de l'outil SystemWorkbench utilisé pour ce tp sont disponibles sur Mise en place du projet architecture pour le TNS sur plateforme Nucléo
Fermer les outils eclipse et STM32CubeMX.
Copier/coller dans une console:
echo commence mv ~/workspace_ac6 ~/workspace_ac6_etu cd ~/ mkdir -p ~/workspace_ac6 cd ~/workspace_ac6 wget https://bvdp.inetdoc.net/files/iut/tp_tns/nucleo_tns_etu2018.zip echo fini
Ensuite:
Seulement après avoir importé le projet depuis l'archive dans eclipse, saisir dans une nouvelle console:
echo commence cd ~/workspace_ac6/ rm nucleo_tns_etu2018.zip cd ~/workspace_ac6/nucleo_tns/ git init git add * git commit -m'initial version' gitk echo fini
Afin de valider le fonctionnement du timer, nous allons utiliser la fonction d'interruption mise en place lors du TD pour générer des signaux périodiques sur des broches (dont on mesurera le signal à l'oscilloscope) et sur une LED (dont on observera le clignotement). L'interruption timer doit survenir à la fréquence de 48kHz (arrondi au plus proche). Pour cela, il faut modifier la fonction static void MX_TIM1_Init(void) déjà mise en place par l'outils STM32CubeMX dans le fichier Src/tim.c
Vous devrez affecter une bonne valeur à htim1.Init.Period pour obtenir la fréquence demandée. Il s'agit de la valeur correspondant au nombre de cycle -1 de décomptage du timer (chargée dans le registre nommé ARR lors du TD précédent), le prédiviseur étant réglé sur un facteur 1. Vous avez effectué un tel calcul lors du TD précédent.
Il faut ensuite compléter la fonction d'interruption dans le fichier Src/main.cpp:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ //Ecrire ici votre code exécuté à la fréquence d'interruption }
Vous disposez de 2 connecteurs sur la face avant du circuit imprimé de la carte de sortie connectés aux sorties PB11 et PB12 du STM32. Ces broches vont être utilisées pour mesurer à l'aide d'un oscilloscope le temps passé dans différentes parties du programme. Dans un premier temps, vous allez générer un signal sur la broche PB11 qui sera à 1 pendant la durée d'exécution de la fonction d'interruption timer et à 0 le reste du temps. La figure suivante présente les différentes broches des connecteurs de la carte:
Au verso de la carte, les signaux en sortie directe du DAC sont accessibles sur la broches PA6 (et éventuellement PA5 pour un second signal dans le TP suivant):
Les autres broches des connecteurs sont organisées tel que le montre le schéma suivant (la carte étant vue depuis le haut, composants face à vous):
Pour générer le signal demandé, vous utiliserez la fonction void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState). La valeur pour l'argument GPIOx est GPIOB, et pour l'argument GPIO_Pin, la valeur est GPIO_PIN_11. Le troisième argument peut prendre la valeur GPIO_PIN_SET ou GPIO_PIN_RESET selon que l'on souhaite activer ou désactiver la sortie.
Après l'ouverture du projet, il est nécessaire de le compiler une première fois avant de pouvoir le debbuguer. Pour cela, cliquez sur le bouton:
Brancher la carte Nucleo au port USB du PC.
Pour activer le mode Debug :
Par la suite, pour exécuter votre application, il suffit de cliquer sur Run→Debug (ou raccourci touche F11).
Important: Il faut quitter le mode debug avant de pouvoir recompiler et tester à nouveau votre programme, pour cela, cliquer sur Run→Terminate (ou raccourci CTRL+F2).
Le logiciel va vous proposer d'ouvrir la “perspective” de Debug (agencement des fenêtres facilitant le Debug), répondre “ok”. Par défaut le programme est arrêté sur la première ligne de la fonction main(), vous pouvez ensuite lancer l'exécution en appuyant sur F8 ou faire du pas à pas en utilisant F5 et F6. Pour positionner un point d'arrêt sur une ligne, il suffit de double cliquer sur son numéro.
Une fois le code mis en place et compilé, il vous faut mesurer la fréquence et la durée à l'état haut du signal généré à l'oscilloscope pour valider le bon fonctionnement. Reporter ces valeurs sur le compte rendu. ATTENTION :le signal généré est haute fréquence (par rapport à la fréquence analogique max de l'oscilloscope), il faut donc désactiver le filtrage HF dans le menu Mode/Coupling.
Une fois le fonctionnement validé par un enseignant, mettre à jour le suivi de version en saisissant dans une console:
echo commence cd ~/workspace_ac6/nucleo_tns/ git commit -a -m'timer ok' gitk & echo fini
Vous devez maintenant faire clignoter la LED rouge présente sur la carte de sortie. Pour cela, à chaque 24000 exécutions de la fonction d'interruption, changer l'état de la broche pilotant la LED. Vous pourrez utiliser la fonction void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin). La valeur pour l'argument GPIOx est GPIOB, et pour l'argument GPIO_Pin, la valeur est GPIO_PIN_13.
Conseil: Implémenter un compteur à l'aide d'une variable static définie dans la fonction void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim).
Vérifier que la LED s'allume bien une fois par seconde.
Une fois le fonctionnement validé par un enseignant, mettre à jour le suivi de version en saisissant dans une console:
echo commence cd ~/workspace_ac6/nucleo_tns/ git commit -a -m'led ok' gitk & echo fini
————————————————————————————
Nous allons utiliser le DAC pour générer un signal sinusoïdal (480Hz).
Les fonctions de la librairies math (sin, cos, tan …) ne sont pas utilisables dans la fonction de gestion d'interruption timer du fait de leur lenteur. Il faut donc définir un tableau contenant les échantillons précalculés d'une période de la fonction sinus pour la fréquence demandée.
Pour cela, copier dans le fichier main.cpp et compléter le code suivant:
#include <math.h> #define SAMPLING_RATE ( 48000.0f) #define SIN_FREQ ( 480.0f) #define SIN_AMP 1024.0f #define SIN_TAB_SAMPLES_PER_PERIOD ((unsigned int) (SAMPLING_RATE / SIN_FREQ)) //Taille du tableau pour une période du signal sinus uint32_t sin_tabbed[SIN_TAB_SAMPLES_PER_PERIOD]; void init_sin_tabbed(){ unsigned int k ; for(k = 0 ; k < SIN_TAB_SAMPLES_PER_PERIOD; k ++ ){ sin_tabbed[k] = ???; //Compléter ici par le calcul de la valeur des échantillons } }
Pour déterminer la valeur des différents échantillons, vous pouvez vous inspirer du code écrit lors du TP4 de TNS qui est rappelé ci-dessous. Les échantillons ainsi générés doivent être compris dans la dynamique du convertisseur DAC (0 < = échantillon < = 4095) et leur valeur moyenne doit être réglée au milieu cette plage. La constante $\pi$ est définie sous le nom M_PI. Dans la formule suivante, Tech est obtenue en inversant SAMPLING_RATE.
Ecrivez d'abord l'expression mathématique du signal: Ex : signal(t)=A.sin(2Π.fo.t) + Vmoy Déterminez alors la valeur du signal aux instants d'échantillonnages: Ex : signal(k.Tech)=A.sin(2Π.fo.k.Tech) + Vmoy Créez ensuite un tableau de taille nbEch (qui dépend de la durée voulue. Ex : tmax=duree=kmax.Tech d’où kmax=duree.Fech) par signal et remplissez-le avec les valeurs pour chaque k Ex : nbEch = kmax+1 double signal[nbEch] for(int k=0; k<nbEch; k++) signal[k]= ..................;
La fonction void init_sin_tabbed() est à appeler une seule fois au bon endroit dans le code de la fonction main(), avant le lancement du timer, afin d'éviter qu'une interruption timer ne survienne avant que le tableau soit initialisé:
//Insérez ici l'appel de votre fonction **init_sin_tabbed** HAL_TIM_Base_Start_IT(&htim1); //Déjà mis en place HAL_DAC_Start(&hdac2, DAC2_CHANNEL_1); //Déjà mis en place
Ainsi, le tableau sin_tabbed contient les échantillons à utiliser dans la fonction d'interruption.
Complétez la fonction d'interruption pour :
La fonction à utiliser pour écrire sur la sortie du DAC est: HAL_StatusTypeDef HAL_DAC_SetValue(DAC_HandleTypeDef* hdac, uint32_t Channel, uint32_t Alignment, uint32_t Data);. Cette fonction écrit une valeur “Data” sur canal “Channel” du DAC “hdac” avec l'alignement “Alignement”. Utiliser comme valeur de premier argument DAC_HandleTypeDef* hdac configuré à &hdac2. Pour le canal du DAC utiliser DAC2_CHANNEL_1 et pour l'alignement 0.
Une fois le code complet, observez le signal généré à l'oscilloscope sur la broche PA6 (indiquée par une étiquette sous la carte Nucléo). Mesurez la valeur moyenne, la fréquence et l'amplitude crête à crête du signal sinusoïdal généré. Mesurez aussi le nouveau temps d'exécution de la fonction d'interruption sur la boche PB11 et reportez ces valeurs sur votre compte rendu. Mesurer la valeur moyenne, la fréquence et l'amplitude crête à crête du signal en sortie du circuit de mise en forme sur la broche A1 de la carte LINE_OUT et en déduire le facteur d'atténuation.
Une fois le fonctionnement validé par un enseignant, mettre à jour le suivi de version en saisissant dans une console:
echo commence cd ~/workspace_ac6/nucleo_tns/ git commit -a -m'dac ok' gitk & echo fini
Nous allons utiliser l'ADC pour échantillonner un signal d'entrée analogique. Pour vérifier le bon fonctionnement de l'ADC, les échantillons acquis seront recopiés sur le DAC. La broche PB11 est utilisée pour mesurer le temps total passé dans l'interruption tandis que PB12 est maintenant utilisé pour mesurer la durée de la conversion numérique→analogique.
Complétez la fonction d'interruption void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) pour :
L'ADC du micro-controleur s'utilise avec les fonctions suivantes :
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc); // Lance la conversion HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef* hadc); // Stoppe la conversion HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout); //Attend le résultat de la conversion, le deuxième paramètre permet de limiter le temps d'attente. //Vous pouvez le régler à 10 uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc) //Lit le résultat de la conversion
Les valeurs possibles du paramètre de retour HAL_StatusTypeDef sont : HAL_OK , HAL_ERROR , HAL_BUSY et HAL_TIMEOUT.
Pour la valeur effective de l'argument ADC_HandleTypeDef* hadc des fonctions ADC, vous utiliserez la valeur &hadc1, par exemple : HAL_ADC_Start(&hadc1);
Une fois le code mis en place il vous faut le tester. Pour ce test, la carte Nucléo est associée à deux cartes : LINE_IN, LINE_OUT pour adapter les niveaux et protéger l'entrée ADC du micro-controleur. L'adaptation en entrée applique un gain de 4.54 sur le signal mis en entrée et le centre sur 1.65v.
La procédure de test est la suivante :
Une fois le fonctionnement validé par un enseignant, mettre à jour le suivi de version en saisissant dans une console:
echo commence cd ~/workspace_ac6/nucleo_tns/ git commit -a -m'adc ok' gitk & echo fini
Vous pouvez maintenant passer au TP suivant dans lequel vous allez insérer le filtre dans le programme du microcontroleur: tns_nucleo_filtre
Pour tuer le processus du debugguer au cas où vous n'auriez pas arreté le mode Debug avant de le relancer, copier coller dans une console:
kill -9 $(lsof -t ~/workspace_ac6/nucleo_tns/Debug/nucleo_tns.elf) kill -9 $(lsof -t -c arm-none-)