Thierry

Emulation d’un port COM avec l’USB

Il est possible d’émuler un port COM avec la prise USB OTG (connecteur micro-AB).

usb

Cet exemple utilise l’USB CDC (USB Communications Device Class) disponible dans le STM32 Cube F4.

 

Cet exemple contient les modules suivants :

  • La LED 5 clignotte avec une période de 2 secondes (1 sec. on, 1 sec. off)
  • La LED 4 correspond au statut du bouton utilisateur (appuyé ou relaché)
  • L’USB OTG émule un nouveau port de communication qui recopie les caractères entrant sur la sortie

Vous pouvez télécharger le code ICI ou sur mon dépots GitHub

Pour compiler les fichiers source avec em::Blocks, vous devez :

  1. Télécharger les fichiers source et les dé-zipper
  2. Ouvrir un projet existant en sélectionnant le projet « Usb-HAL.ebp »
  3. Vérifier que la constants USE_USB_FS est bien défnine au niveau du projet.

Pour faire cette vérifiaction, faites un clique droit sur le projet dans la fenêtre « management « , puis sélectionner l’option « build Option… » dans le menu contextuel.

USB_Constant

Cliquer sur « Usb-Hal » dans la partie gauche de la boite de dialogue pour sélectionner les paramètres globaux du projet.

Dans l’onglet « #defines » des options du compilateur, vérifier que USE_USB_FS est présent.

 

Attention: Il y a un bug dans la distribution STM32 Cube F4 (corrigé ici)

Dans le fichier usbd_cdc.c, dans la fonction USBD_CDC_TransmitPacket(), la mise à jour de l’état de la transmission est faite après l’appel de la fonction d’émission (qui fonctionne sous interruption et met à jour également cet état).

USBD_LL_Transmit(...);
hcdc->TxState = 1;

Donc en cas de transmission courte (1 octet par exemple), la fonction Transmit peut se terminer avant que la fonction en cours mette à jour l’état avec une mauvaise valeur dans ce cas. La solution : inverser les 2 lignes pour indiquer la transmission avant d’envoyer les octets.

hcdc->TxState = 1;
USBD_LL_Transmit(...);

FreeRTOS pour em::Blocks & STM32F4

Dans l’environnement em::Blocks, il est possible de créer des templates qui permettent d’initialiser facilement des nouveaux projets.

Cet article décrit comment créer un nouveau template pour em::Blocks contenant :

  • FreeRTOS V8.12
  • STM32F4xx HAL Driver (la nouvelle couche d’abstraction STM32CubeF4 de ST)
  • La configuration spécifique pour la carte the STM32F4-Discovery

 

Installation du template téléchargé

Comme il est un peu long de créer ce template, vous pouvez l’installer directement dans em::Blocks à partir de la version téléchargée.

  1. Télécharger le template ICI ou sur mon repertoire GitHub
  2. Dézipper le fichier pour créer le répertoire « STM32F4-Discovery-Template »
  3. Copier « STM32F4-Discovery-Template » dans le répertoire Windows %AppData% pour em::Blocks en lançant la commande suivante :
xcopy /S /I STM32F4-Discovery-Template %APPDATA%\EmBlocks\2.00\UserTemplates\STM32F4-Discovery

Pour créer un nouveau projet dans em::Blocks, utilisez le menu « File / New / From template… » et sélectionnez le nouveau template. Ensuite sélectionnez le répertoire cible et entrez le nom du projet.

 

Comment créer ce template

Créez un nouveau projet comme décrit dans la première partie de l’article « Utiliser em::Blocks avec la STM32F4-Discovery« .
Nommez votre projet « STM32F4-Discovery » et ne pas faire la fin « Adaptation pour la STM32F4-Discovery ».

 

Ajout des fichiers à ce template

Créer un répertoire STM32F4 directory sous C:\

Dézipper le fichier stm32cube_fw_f4_v130.zip dans ce répertoire (voir l’article précédent pour le télécharger)

Télécharger et lancer le programme FreeRTOSV8.1.2.exe pour dézipper les fichiers dans ce répertoire

Le résultat pour ce répertoire STM32F4 est:

  • FreeRTOSV8.1.2 : La distribution freeRTOS
  • STM32Cube_FW_F4_V1.3.0 : Le firmware STM32Cube F4
  • STM32F4-Discovery : Le nouveau projet créé pour réaliser ce template

Aller dans « STM32F4-Discovery » et supprimer le répertoire « SPL » qui contient l’ancien frimware.

Supprimer le contenu du répertoire « Inc ». Les fichiers seront remplacés par la version HAL.

Creation de la partie FreeRTOS

– Aller dans « c:\STM32F4\STM32F4-Discovery » (le répertoire de votre nouveau projet) et y créer le répertoire « Firmware ».

– Aller dans ce répertoire « Firmware » et y créer le répertoire « FreeRTOS ».

– Se positionner dans « FreeRTOS ».

– Copier les fichiers sources (*.c) de « c:\STM32F4\FreeRTOSV8.1.2\FreeRTOS\Source\*.c ».

– Copier les fichiers d’inclusion (*.h) de « c:\STM32F4\FreeRTOSV8.1.2\FreeRTOS\Source\include\*.h ».

– Copier le contenu de « c:\STM32F4\FreeRTOSV8.1.2\FreeRTOS\Source\portable\GCC\ARM_CM4F\*.* ».

Le fchier source de la gestion mémoire doit être ajouté (5 fichiers existent, consultez la documentation pour plus de détails).
– La première version convient dans la plus part des cas, donc copier le fichier « c:\STM32F4\FreeRTOSV8.1.2\FreeRTOS\Source\portable\MemMang\heap_1.c » dans ce répertoire « FreeRTOS ».

– Copier le fichier « c:\STM32F4\FreeRTOSV8.1.2\FreeRTOS\Demo\CORTEX_M4F_STM32F407ZG-SK\FreeRTOSConfig.h » dans ce répertoire « FreeRTOS ».

Un fichier supplémentaire doit être créé:
– Créer dans le répertoire « FreeRTOS » un fichier appelé « FreeRTOS-hook.c », l’éditer pour ajouter le code suivant :

#include "FreeRTOS.h"
#include "task.h"
#include "stm32f4xx_hal.h"

void vApplicationTickHook( void )
{
    HAL_IncTick();
}
/*-----------------------------------------------------------*/

void vApplicationMallocFailedHook( void )
{
	/* vApplicationMallocFailedHook() will only be called if
	configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h.  It is a hook
	function that will get called if a call to pvPortMalloc() fails.
	pvPortMalloc() is called internally by the kernel whenever a task, queue,
	timer or semaphore is created.  It is also called by various parts of the
	demo application.  If heap_1.c or heap_2.c are used, then the size of the
	heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
	FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
	to query the size of free heap space that remains (although it does not
	provide information on how the remaining heap might be fragmented). */
	taskDISABLE_INTERRUPTS();
	for( ;; );
}
/*-----------------------------------------------------------*/

void vApplicationIdleHook( void )
{
	/* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
	to 1 in FreeRTOSConfig.h.  It will be called on each iteration of the idle
	task.  It is essential that code added to this hook function never attempts
	to block in any way (for example, call xQueueReceive() with a block time
	specified, or call vTaskDelay()).  If the application makes use of the
	vTaskDelete() API function (as this demo application does) then it is also
	important that vApplicationIdleHook() is permitted to return to its calling
	function, because it is the responsibility of the idle task to clean up
	memory allocated by the kernel to any task that has since been deleted. */
}
/*-----------------------------------------------------------*/

void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
{
	( void ) pcTaskName;
	( void ) pxTask;

	/* Run time stack overflow checking is performed if
	configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2.  This hook
	function is called if a stack overflow is detected. */
	taskDISABLE_INTERRUPTS();
	for( ;; );
}
/*-----------------------------------------------------------*/

 

Création de la partie STM32CubeF4

– Remonter dans « c:\STM32F4\STM32F4-Discovery\Firmware »

– Copier le répertoire « STM32F4xx_HAL_Driver » situé dans « c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Drivers ».

– Copier le répertoire « STM32F4-Discovery » situé dans « c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Drivers\BSP ».

– Copier le répertoire « Components » situé dans « c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Drivers\BSP ».

– Copier le répertoire « STM32_Audio » situé dans « c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Middlewares\ST ».

– Se positionner dans le répertoire « c:\STM32F4\STM32F4-Discovery\inc »

– Copier le fichier « stm32f4xx_hal_conf.h » situé dans « c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Projects\STM32F4-Discovery\Templates\Inc ».

– Copier le fichier « stm32f407xx.h » situé dans « c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Drivers\CMSIS\Device\ST\STM32F4xx\Include ».

– Copier le fichier « stm32f4xx.h » situé dans « c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Drivers\CMSIS\Device\ST\STM32F4xx\Include ».

– Copier le fichier « system_stm32f4xx.h » situé dans « c:\STM32F4\STM32Cube_FW_F4_V1.3.0\Drivers\CMSIS\Device\ST\STM32F4xx\Include ».

 

Configuration de em::Blocks IDE

– Dans la fenêtre de Workspace, faire un clique droit sur le projet STM32F4-Discovery et sélectionner « Build options… »

– Dans l’onglet « Compiler settings », sélectionner le sous onglet « #define ».
Ajouter les deux constantes STM32F407xx et USE_HAL_DRIVER

– Dans l’onglet « Compiler settings », sélectionner le sous onglet « Other options ».
Ajouter l’option -Wno-unused-but-set-variable et valider avec le bouton « Ok » (pour supprimer le warning: variable ‘xxx’ set but not used).

– Editer le fichier source « Source/src/system_stm32f4xx.c » et à la ligne 156 changer la valeur de #define PLL_M à 8 (Le Quartz est à 8Mhz).

– Faire un clique droit sur la racine « STM32F4-Discovery » dans la fenêtre Workspace. Sélectionner « Remove files… » et valider les 2 boites de dialogue suivantes pour supprimer tous les fichiers de l’arborescence projet.

– Faire un clique droit sur la racine « STM32F4-Discovery » et sélectionner « Add files recursively… » pour re-créer la nouvelle structure du projet :

* valider la première boite de dialogue pour inclure le contenu du répertoire « STM32F4-Discovery ».

* dans la seconde boite de dialogue, aller en bas de la liste des fichiers et cocher les deux derniers fichiers « stm32f407vg_flash.ld » et « stm32f407vg_sram.ld ». Ensuite cliquer sur « Ok »

* cliquer sur « Ok » à la troisième boite de dialogue.

(si vous avez un répertoire « D sources » dans l’arborescence projet, due à une complation précédente importée, ouvrez le et faites un clique droit sur le répertoire « obj », sélectionner « remove « obj\* »)

– Editer le fichier « Headers/Firmware/STM32F4-Discovery/stm32f4_discovery_audio.h » et à la ligne 52 remplacer #include « ..\..\..\Middlewares\ST\STM32_Audio\Addons\PDM\pdm_filter.h »
par « #include « pdm_filter.h »

– Editer le fichier « Header/Firmware/FreeRTOS/FreeRTOSConfig.h » et déplacer la ligne 85 en dehors du bloc « #ifdef __ICCARM__ ».

On doit avoir :

 
 #ifdef __ICCARM__
 #include <stdint.h>
 #endif
 extern uint32_t SystemCoreClock;

– Editer le fichier « main.c » pour remplacer le contenu par :

/*
**
** Main.c
**
**
**********************************************************************/
#include "stm32f4xx.h"
#include "stm32f4_discovery.h"
#include "FreeRTOS.h"
#include "task.h"

#define TASK_PRIORITY	(tskIDLE_PRIORITY + 1)
#define STACK_SIZE      (configMINIMAL_STACK_SIZE + 100)


// Task prototypes
void LedTaskFunction( void *pvParameters );
void BtnTaskFunction( void *pvParameters );


int main(void)
{
    // Initialization
    HAL_Init();

    // create the task
    xTaskCreate( LedTaskFunction,   /* Pointer to the function that implements the task. */
                 "Flash Led",       /* Text name for the task. This is to facilitate debugging only. */
                 STACK_SIZE,        /* Stack depth */
                 NULL,              /* We are not using the task parameter. */
                 TASK_PRIORITY,     /* This task will run at priority 1. */
                 NULL );            /* We are not going to use the task handle. */

    // Create the BTN task
    xTaskCreate( BtnTaskFunction, "BTN Task", STACK_SIZE, NULL, TASK_PRIORITY, NULL );

    // Start the scheduler so the tasks start executing
    vTaskStartScheduler();

    while(1) ;
}

void LedTaskFunction( void *pvParameters )
{
    BSP_LED_Init(LED6);
    for (;;)
    {
        BSP_LED_Toggle(LED6);
        vTaskDelay(500);    // Delay 500 ms
    }
}

void BtnTaskFunction( void *pvParameters )
{
    BSP_LED_Init(LED3);
    BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_GPIO);
    for (;;)
    {
        if (BSP_PB_GetState(BUTTON_KEY))
            BSP_LED_On(LED3);
        else
            BSP_LED_Off(LED3);
    }
}

On peut maintenant compiler ce projet sans erreur.

Si on le lance, une première tâche fait cligotter la LED 6 avec une période de 1s et une seconde tâche recopie l’état du bouton utilisateur sur la LED 3.

Maintenant que le projet est prêt (et comme ça nous a pris pas mal de temps pour le construire 😉 ), il faut le sauver sous forme d’un template dans em::Blocks.

Utiliser le menu « File / Save Project as Template… »

 

Complément pour le STM32CubeF4 V1.9.0

– Se positionner dans le répertoire « c:\STM32F4\STM32F4-Discovery\cmsis ».

– Effacer son contenu

– Y recopier le contenu du réperoire « c:\STM32F4\STM32Cube_FW_F4_V1.9.0\Drivers\CMSIS\Include »

Utiliser em::Blocks avec la STM32F4-Discovery

Après avoir beaucoup essayé d’IDE pour programmer la carte STM32F4-Discovery, mon choix s’est porté sur em::Blocks.

C’est un environnement gratuit, sans limitation de taille de code (contrairement aux version Free des IDE payants). C’est un fork de code::Blocks destiné à la génération de code embarqué. Il reconnait nativement de nombreuse cartes d’évaluation, dont la STM32F4-Discovery.

Le logiciel peut être téléchargé sur le site de em::Blocks.

 

Prérequis

– em:Blocks téléchargé et installé  😉  La version utilisée dans cet article est la 2.30

– STM32F4 drivers installés : a télécharger sur la page du site de ST (http://www.st.com/web/en/search/partNumberKeyword) en cherchant la référence STSW-LINK (stsw-link008 pour les driver Windows 7).

– Firmware pour la carte STM32F4-Discovery : sur la même page de recherche que ci-dessus, chercher la référence STSW-STM32068 pour pouvoir télécharge le fichier stsw-stm32068.zip.

– Créer un répertoire de travail « C:\STM32F4 » et dézipper le fichier stsw-stm32068.zip dedans. Cela doit donner :
C:\STM32F4\STM32F4-Discovery_FW_V1.1.0

 

Création d’un nouveau projet

 

Génération du code de base

1) Lancer em::Blocks. Ouvrir le menu « File / New / Project… »
2014-12-31_1006092) Selectionner « STmicro-ARM »

 

2015-01-03_1716453) Entrer le nom du nouveau projet et le chemin pour ce projet

 

2014-12-31_1006224) Laisser les options par défaut

 

2014-12-31_100627

5) Choisir Cortex M4 (F3xx-F4xx)

 

2014-12-31_100632

6) Choisir STM32F4xx

 

2014-12-31_100659

7) Choisir le micro-contrôleur STM32F407VG.

 

2014-12-31_100713

8) Laisser la configuration par défaut

 

2015-01-03_170518

9) Sélectionner l’onglet « Target settings » et cocher la case « Run to main() ». Cela permet lors du lancement du mode debug de s’arrêter sur la première ligne du code plutôt que sur la première ligne du loader assembleur.

==> Le code est généré et est compilable.

 

Adaptation pour la STM32F4-Discovery

1) Recopier le firmware dans le répertoire du projet :

copier le répertoire

c:\STM32F4\STM32F4-Discovery_FW_V1.1.0\Utilities\STM32F4-Discovery

dans

c:\STM32F4\Test

 

2) Importer les modifications dans le projet

2014-12-31_102457

Faire un clique droit sur le nom du projet dans la fenêtre de gauche. Dans le menu choisir « Add files recusrsively ».

 

3) Sélectionner le nouveau répertoire rajouté au projet

2015-01-03_172641

 

4) Valider les 2 boites de dialogue qui listent les fichiers à importer

2015-01-03_173859 2014-12-31_101723

 

5) Pour éviter d’inclure d’autres dépendances, il faut supprimer les fichiers de gestion « audio »

2015-01-03_174657

 

Ouvrir le répertoire STM32F4-Discovery dans l’espace projet.

Faire un clique droit sur le fichier audio « stm32f4_discovery_audio_codec.c », puis choisir « Remove file from project ».

 

5) Prise en compte du quartz à 8Mhz

Dans le répertoire src, éditer le fichier system_stm32f4xx.c

C’est le fichier de configuration qui est automatiquement appelé au lancement du programme. Contrairement à ce qui est indiqué dans les commentaire en ligne 59, la fréquence du quartz est de 8 Mhz. Il faut onc chnager la valeur du PLL_M pour le passer à 8.

Editer la ligne 156 ou recherchez la constante PLL_M et forcer sa valeur à 8 :

#define PLL_M   8

 

6) Le projet maintenant prêt à être compilé.

Pour tester, je vous propose le code suivant pour main.c :

#include « stm32f4_discovery.h »

int main(void)
{
STM_EVAL_LEDInit(LED3);
STM_EVAL_LEDOn(LED3);
while(1) ;
}

En cas d’erreur lors de la compilation indiquant des erreurs sur le fichier audio, effacer le répertoire « c:\STM32F4\Test\obj\Debug » et relancer la compilation.

 

 Génération d’un template

Pour éviter de refaire tout ce travail lors chaque nouveau projet, il est possible de créer un template de projet.

En utilisant ce projet « Test » qui est configuré correctement, ouvrir le menu « File / Save project as template… » et choisir le nom du template.

 

Pour les nouveaux projets, il suffit de faire « File / New / From Template… » et de choisir votre template pour avoir automatiquement toute la configuration appliquée par défaut  🙂

Présentation de la STM32F4-Discovery

C’est une carte avec beaucoup de possibilitées et un un prix très abordable (environ 15€). Si on compare avec des cartes du type Ardruino, cette carte est beaucoup plus performante à prix égal.

M-05313

La STM32F4-Discovery comporte de base sur la carte :

  • un Microcontrôleur stm32f407vgt6 32-bit ARM Cortex-M4F, 1 MB de Flash, 192 KB de RAM
  • un connecteur ST-LINK/V2 ou la possibilité d’utiliser le conneteur USB d’allimentation pour la programmation et le bedug
  • un connecteur USB pour l’allimentation 5V
  • des sorties 3V et 5V pour les applications externes
  • un accéléromètre LIS302DL ou LIS3DSH ST MEMS 3-axis (sur les dernières versions c’est le LIS3DSH)
  • un micro MP45DT02 pour enregistrer des sons
  • un  audio DAC CS43L22, avec un un pilote de haut-parleur class D
  • 4 LEDs, LD3 (orange), LD4 (vert), LD5 (rouge) and LD6 (bleu)
  • 2 boutons poussoir (utilisateur et reset)
  • un connecteur USB OTG FS (micro-AB) pour s’interfacer avec des systèmes externes (clé USB, PC, …)
  • 2 connecteurs I/O pour se connecter avec des prototypes

Pour plus de détails, vous pouvez consulter le lien de l’éditeur : STM32F4-Discovery