1

TUTO XMEGA (ASF) : Connexion USB CDC avec votre XMEGA

La derniere version de ce tuto est disponible sur le WIKI

La classe CDC permet d’établir une communication série (RS232) via l’USB du microcontrôleur.
La liaison sera équivalente à une liaison UART avec les contrôles de flux en plus.

Créer un projet ASF et ajouter la librairie USB Device (service) dans le menu déroulant, sélectionner “cdc”

La première chose à faire est de configurer l’horloge. Pour fonctionner, le module USB a besoin d’une horloge de 12 ou 48Mhz. L’oscillateur interne de 32Mhz sera utilisé. En effet sa fréquence peut être réglée entre 30 et 55Mhz grâce à une PLL numérique. Nous allons donc le faire fonctionner à 48Mhz et nous utiliserons une prédiviseur /2 pour fournir une horloge de 24Mhz au CPU.

Editer le fichier conf_clock.h et supprimer toutes les lignes et mettez à la place :

#ifndef CONF_CLOCK_H_INCLUDED
#define CONF_CLOCK_H_INCLUDED

//Horloge USB
#define CONFIG_USBCLK_SOURCE     USBCLK_SRC_RCOSC		//Choix de l'horloge interne pour l'USB
#define CONFIG_OSC_RC32_CAL      48000000UL			//Calibration de l'horloge pour qu'elle fonctionne à 48Mhz
#define CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC  OSC_ID_USBSOF	//Utilisation d'une calibration automatique lors de la reception de la premiere trame USB	

//Horloge CPU qui doit être > à 12Mhz pour les applications USB
#define CONFIG_SYSCLK_SOURCE     SYSCLK_SRC_RC32MHZ		//Choix de l'horloge interne (qui fonctionne à 48Mhz)
#define CONFIG_SYSCLK_PSADIV     SYSCLK_PSADIV_2		//Prescaler A divise la fréquence par 2 = 24Mhz
#define CONFIG_SYSCLK_PSBCDIV    SYSCLK_PSBCDIV_1_1		//Prescaler B pas de division. Donc le CPU fonctionne à 24Mhz

#endif /* CONF_CLOCK_H_INCLUDED */

Ajouter au début du main, les lignes d’initialisation suivantes :

//Initialisation système
sysclk_init();
irq_initialize_vectors();
cpu_irq_enable();

board_init();

Nous allons maintenant nous occuper de la configuration USB. Informations qui seront transmises au controleur USB du PC afin de pouvoir identifier notre carte. Ouvrez le fichier conf_usb.f et indiquer les informations suivantes :

#define  USB_DEVICE_VENDOR_ID        USB_VID_ATMEL		//VID ATMEL
#define  USB_DEVICE_PRODUCT_ID            USB_PID_ATMEL_ASF_CDC		//PID CDC
#define  USB_DEVICE_MAJOR_VERSION         1				//Version du périphérique
#define  USB_DEVICE_MINOR_VERSION         0
#define  USB_DEVICE_POWER                 100				//Consommation de notre carte
#define  USB_DEVICE_ATTR                  USB_CONFIG_ATTR_BUS_POWERED	//La carte est alimentée par le bus USB

Chaque fabricant de périphérique achete auprès d’usb.org des plages identifiants uniques qui permettent à votre ordinateur de l’identifier et charger le driver adéquate. C’est identifiant est composé d’un VID vendor ID USB_DEVICE_VENDOR_ID (Numéro d’identification du fabricant) et d’un PID product ID USB_DEVICE_PRODUCT_ID (Numéro d’identification du produit). Si vous souhaitez avoir votre propre VID/PID, il vous en coutera environ 2000$.8-) En attendant, nous allons garder les VID/PID d’Atmel. ;-)

Si vous souhaitez faire des essais avec des VIP/PID différents, vous pouvez utiliser ceux de LUFA qui ont été donnés par ATMEL. Il est totalement interdit d’utiliser ces PID dans un autre cadre que le test. J’ai également lu que certains fabricants en fournissent à leurs clients sur demande (Microchip, FTDI)

La ligne suivante indique quelle version USB utiliser 1,2 etc …

USB_DEVICE_POWER sera la valeur de consommation de courant max de notre carte. Cette information sera transmise au PC afin qu’il adapte sa gestion de courant.

USB_DEVICE_ATTR indique au contrôleur si le périphérique s’alimente via le port USB ou s’il dispose d’une alimentation indépendante. Dans notre cas, il sera alimenté par le port USB.

Puis ajouter la ligne ci dessous dans votre fichier main.c pour démarrer la pile USB

udc_start();

A ce stade, votre PC doit déjà pouvoir détecter votre carte et installer les drivers.

Nous allons voir maintenant comment envoyer et recevoir des données via cette connexion. Aller dans le fichier conf_usb.f et modifier les lignes suivantes :

//! Interface callback definition
#define  UDI_CDC_ENABLE_EXT(port)	callback_cdc_enable()
extern bool callback_cdc_enable(void);
#define  UDI_CDC_DISABLE_EXT(port)	callback_cdc_disable()
extern void callback_cdc_disable(void);

Les fonctions callback_cdc_enable et callback_cdc_disable seront appelés dès que la connexion sera établie ou rompue.

Vérifier également les lignes suivantes qui definissent le débit de la liaison :

//! Define it when the transfer CDC Device to Host is a low rate (<512000 bauds)
//! to reduce CDC buffers size
#define  UDI_CDC_LOW_RATE

//! Default configuration of communication port
#define  UDI_CDC_DEFAULT_RATE             115200
#define  UDI_CDC_DEFAULT_STOPBITS         CDC_STOP_BITS_1
#define  UDI_CDC_DEFAULT_PARITY           CDC_PAR_NONE
#define  UDI_CDC_DEFAULT_DATABITS         8

Vous pouvez augmenter le baudrate jusqu’à 512 200 bauds. Au delà, il vous suffit de commenter la ligne #define UDI_CDC_LOW_RATE pour aller plus haut. Il faut savoir sur le debit est limité par la vitesse du CPU et par les fonctions utilisés. Atmel fournit un document montrant les limites de fonctionnement. On peut voir figure 6-4 qu’en utilisant les fonctions ReadBuf et WriteBuf qu’il est possible de monter jusqu’à environ 900Kbauds/s.

Dans votre fichier main.c ajouter les deux callback et le petit bout de code suivant qui renvoi “ok 1” dès que vous taper “1” et “error” si vous envoyé n’importe quoi d’autre.

#include <asf.h>

static bool flag_autorize_cdc_transfert = false; //Flag d'autorisation de transfert envoyé par l'hote.
char ch;										//Caractère reçu

//Lors de l'établissement de la connexion
bool callback_cdc_enable(void)
{
	flag_autorize_cdc_transfert = true;

	return true;
}
//Lors de la deconnexion
void callback_cdc_disable(void)
{
	flag_autorize_cdc_transfert = false;
}

int main (void)
{
	//Initialisation système
	sysclk_init();
	irq_initialize_vectors();
	cpu_irq_enable();

	board_init();

	//Démarrage de l'USB
	udc_start(); 

	while(1)
	{
		if (udi_cdc_is_rx_ready() && flag_autorize_cdc_transfert) //Si la transmission est autorisé et si nous avons reçu quelque chose
		{
			ch = udi_cdc_getc();
			switch(ch)
			{
				case '1':
					udi_cdc_write_buf("ok 1\r\n", 6);
				break;
				default :
					udi_cdc_write_buf("error\r\n", 7);
				break;
			};

		}
	}
}

Brancher, Compiler, programmer démarrer votre terminal préféré (Hyperterminal, putty, etc …). Indiquer le port COM de votre carte et le débit (115200) :

et taper 1 ou autre chose

admin

Un commentaire

  1. j’ai suivi les memes instructions mais ça ne marche pas
    j’ai aucun message de retour sur l’hyperteminal et quand je debug ch=0 toujours

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.