Atmel SAM4S

Atmel SAM4S sous Linux - TP n°4 : le bus TWI/I2C

L’objectif est de mettre en oeuvre le bus TWI/I2C de la carte Atmel SAM4S.

Remarque : Pour ce TP, vous aurez besoin de relier un adaptateur USB/RS232 sur le port série UART J7 et d’utiliser un logiciel d’émulation de terminal ($ picocom -b 115200 /dev/ttyUSB0 ou cutecom sous GNU/Linux ou TeraTerm sous Windows) sur le port série virtuel pour visualiser les messages de débuggage. On quitte picocom en utilisant la combinaison de touches Ctrl-A puis Ctrl-X.

Ressources

Introduction

I2C (Inter-Integrated Circuit) est un bus de données qui permet de relier facilement un microprocesseur et différents circuits électroniques. Conçu par Philips en 1982 pour les applications de domotique et d’électronique domestique, il a permis d’interconnecter les composants d’une télévision moderne : récepteur de la télécommande, réglages des amplificateurs basses fréquences, tuner, horloge, gestion de la prise péritel, etc.

Il existe maintenant d’innombrables périphériques exploitant ce bus, dont beaucoup de microcontrôleurs. Le poids de l’industrie de l’électronique grand public a permis des prix très bas grâce à ces nombreux composants.

Remarque : Ce bus porte parfois le nom de TWI (Two Wire Interface) chez certains constructeurs. C’est la cas ici avec Atmel.

I2C est un bus série synchrone bidirectionnel half-duplex. Le débit peut aller jusqu’à 400 Kbits/s (100 Kbits/s en mode standard).

Plusieurs équipements, soit maîtres, soit esclaves, peuvent être connectés au bus. Les échanges ont toujours lieu entre un seul maître et un (ou tous les) esclave(s), toujours à l’initiative du maître (jamais de maître à maître ou d’esclave à esclave). Cependant, rien n’empêche un composant de passer du statut de maître à esclave et réciproquement.

La connexion est réalisée par l’intermédiaire de deux lignes :

  • SDA (Serial Data Line) ou TWD : ligne de données bidirectionnelle,
  • SCL (Serial Clock Line) ou TWCK : ligne d’horloge de synchronisation unidirectionnelle (maître/esclaves) ou bidirectionnelle (multi-maîtres).

Remarque : Il ne faut également pas oublier la masse (GND) qui doit être commune aux équipements.

Le nombre maximal d’équipements est limité par le nombre d’adresses disponibles, 7 bits pour l’adresse et un bit pour définir si on écrit ou on lit (R/W), soit en théorie 128 périphériques. De nombreuses adresses sont déjà attribuées par les fabricants ce qui limite grandement le nombre d’équipements. Un mode d’adressage sur 10 bits existent mainteant.

Le bus TWI sur la carte Atmel

La carte Atmel SAM4S dispose de 2 bus TWI :

Remarque : le bus TWI0 n’est pas accessible sur la carte de développement SAM4S-EK puisque les lignes PA3 et PA4 sont câblés sur le QTouch Slider. Les lignes du bus TWI1 sont partagées avec l’interface JTAG.

On va donc utiliser le bus TWI1 avec les lignes PB4 et PB5 :

Remarque : les deux résistances de pull-up ne sont pas présentes sur la carte SAM4S-EK.

Le bus TWI de la carte peut être programmé en mode maître ou en mode esclave. Dans les manipulations, on l’utilisera en maître TWI.

Les définitions de base concernant les 2 bus TWI sont déjà réalisées dans le fichier /usr/local/asf/sam/utils/cmsis/sam4s/include/sam4s16c.h :

// Les ID
#define ID_TWI0   (19) /**< \brief Two Wire Interface 0 (TWI0) */
#define ID_TWI1   (20) /**< \brief Two Wire Interface 1 (TWI1) */

// Les adresses de base des registres
#define TWI0       ((Twi    *)0x40018000U) /**< \brief (TWI0      ) Base Address */
#define TWI1       ((Twi    *)0x4001C000U) /**< \brief (TWI1      ) Base Address */

// Les 2 gestionnaires d'interruptions
void TWI0_Handler       ( void );
void TWI1_Handler       ( void );

La structure Twi est déclarée dans /usr/local/asf/sam/utils/cmsis/sam4s/include/component/component_twi.h :

typedef struct {
  __O  uint32_t TWI_CR;        /**< \brief (Twi Offset: 0x00) Control Register */
  __IO uint32_t TWI_MMR;       /**< \brief (Twi Offset: 0x04) Master Mode Register */
  __IO uint32_t TWI_SMR;       /**< \brief (Twi Offset: 0x08) Slave Mode Register */
  __IO uint32_t TWI_IADR;      /**< \brief (Twi Offset: 0x0C) Internal Address Register */
  __IO uint32_t TWI_CWGR;      /**< \brief (Twi Offset: 0x10) Clock Waveform Generator Register */
  __I  uint32_t Reserved1[3];
  __I  uint32_t TWI_SR;        /**< \brief (Twi Offset: 0x20) Status Register */
  __O  uint32_t TWI_IER;       /**< \brief (Twi Offset: 0x24) Interrupt Enable Register */
  __O  uint32_t TWI_IDR;       /**< \brief (Twi Offset: 0x28) Interrupt Disable Register */
  __I  uint32_t TWI_IMR;       /**< \brief (Twi Offset: 0x2C) Interrupt Mask Register */
  __I  uint32_t TWI_RHR;       /**< \brief (Twi Offset: 0x30) Receive Holding Register */
  __O  uint32_t TWI_THR;       /**< \brief (Twi Offset: 0x34) Transmit Holding Register */
  __I  uint32_t Reserved2[50];
  __IO uint32_t TWI_RPR;       /**< \brief (Twi Offset: 0x100) Receive Pointer Register */
  __IO uint32_t TWI_RCR;       /**< \brief (Twi Offset: 0x104) Receive Counter Register */
  __IO uint32_t TWI_TPR;       /**< \brief (Twi Offset: 0x108) Transmit Pointer Register */
  __IO uint32_t TWI_TCR;       /**< \brief (Twi Offset: 0x10C) Transmit Counter Register */
  __IO uint32_t TWI_RNPR;      /**< \brief (Twi Offset: 0x110) Receive Next Pointer Register */
  __IO uint32_t TWI_RNCR;      /**< \brief (Twi Offset: 0x114) Receive Next Counter Register */
  __IO uint32_t TWI_TNPR;      /**< \brief (Twi Offset: 0x118) Transmit Next Pointer Register */
  __IO uint32_t TWI_TNCR;      /**< \brief (Twi Offset: 0x11C) Transmit Next Counter Register */
  __O  uint32_t TWI_PTCR;      /**< \brief (Twi Offset: 0x120) Transfer Control Register */
  __I  uint32_t TWI_PTSR;      /**< \brief (Twi Offset: 0x124) Transfer Status Register */
} Twi;

Attention : il vous faudra inclure les fichiers d’en-têtes (header) twi.h et ajouter sam/drivers/twi/twi.c dans la liste des fichiers à compiler (variable CSRCS du fichier config.mk) puis sam/drivers/twi dans la liste des chemins des fichiers headers (variable INC_PATH du fichier config.mk).

Documentation : Chapitre 34 Two-wire Interface (TWI) page 719 du atmel-11100-32-bit-cortex-m4-microcontroller-sam4s_datasheet.pdf

Pour simplifier la programmation directe du TWI, la bibliothèque logicielle ASF fournit des fonctions de contrôle : http://asf.atmel.com/docs/latest/sam4s/html/group__twi__group.html. Certaines structures seront utilisées pour les échanges (cf. http://asf.atmel.com/docs/latest/sam4s/html/twi_8h.html).

Manipulations

Communiquer sur le bus TWI

On désire lire et/ou écrire une E/S numérique à partir d’un circuit I2C. On utilisera le circuit PCF8574 qui dispose de 8 E/S.

Documentation : PCF8574.pdf

Remarque : l’adresse de base du PCF8574 est 0x40 avec le bit R/W et 0x20 donc (0x40 >> 1) si le bit R/W (poids faible) n’intervient pas dans l’adresse du circuit I2C.

On crée un programme de test qui utilise les fonctions de la bibliothèque logicielle ASF :

$ vim main.c
// Communication TWI (carte Atmel SAM4S-EK)

#include <asf.h>
#include <twi.h>

/** TWI */
/** TWI Bus Clock 400kHz */
#define TWI_CLK     400000
//#define TWI_CLK     100000
#define ADR_BASE_8574        (0x40 >> 1)

int main (void)
{
    twi_packet_t packet_rx;
    uint8_t data = 0;
    
    my_init();

    // Désactive le JTAG
    REG_CCFG_SYSIO |= CCFG_SYSIO_SYSIO4; // (1 << 4)
    REG_CCFG_SYSIO |= CCFG_SYSIO_SYSIO5; // (1 << 5)

    // Configure l'accès aux lignes SDA et SCL sur le PIOB
    gpio_configure_pin(TWI1_DATA_GPIO, TWI1_DATA_FLAGS);
    gpio_configure_pin(TWI1_CLK_GPIO, TWI1_CLK_FLAGS);
    
    puts("Start TWI/I2C\r");
    
    // Active l'horloge du périphérique TWI
    pmc_enable_periph_clk(ID_TWI1);

    // Initialise le bus TWI 1
    twi_options_t opt;
    opt.master_clk = sysclk_get_cpu_hz();
    opt.master_clk = sysclk_get_peripheral_bus_hz(TWI1);
    opt.speed      = TWI_CLK;
    opt.smbus      = 0;

    if (twi_master_init(TWI1, &opt) != TWI_SUCCESS) 
    {
        puts("-E-\tEchec initialisation TWI/I2C.\r");
    }
    else printf("Init :\tOK!\n\r");

    printf("Adresse 8574 : 0x%02X\r\n", ADR_BASE_8574);
    if (twi_probe(TWI1, ADR_BASE_8574) != TWI_SUCCESS) 
    {
        puts("-E-\tPas d'esclave TWI/I2C detecte.\r");
    }
    else printf("Probe :\tOK!\n\r");

    packet_rx.chip        = ADR_BASE_8574;
    packet_rx.addr[0]     = 0;
    packet_rx.addr_length = 0;
    packet_rx.buffer      = &data;
    packet_rx.length      = 1;
    if (twi_master_read(TWI1, &packet_rx) != TWI_SUCCESS) 
    {
        puts("-E-\tTWI master read packet failed.\r");
    }
    else
    {
        printf("Data lue : 0x%02X\r\n", data);
        mdelay(10);
    }

    mdelay(1000);

    // Reset du mode et du bus
    twi_disable_master_mode(TWI1);
    twi_reset(TWI1);
    printf("End.\n\r");

    // Réactive le JTAG
    REG_CCFG_SYSIO &= ~CCFG_SYSIO_SYSIO4; // (1 << 4)
    REG_CCFG_SYSIO &= ~CCFG_SYSIO_SYSIO5; // (1 << 5)

    return 0;
}

Code source : tp4-twi.zip

Test :

$ make
$ ./run.sh xxx_flash.elf 

Travail demandé

Relier les deux cartes entre elles.

  1. Fournir le schéma de cablage entre la carte PCF8574 et la carte Atmel SAM4S-EK.

  2. Tester le programme fourni.

  3. Écrire le programme de test qui permet de valider la commandes des sorties numériques (cf. la fonction twi_master_write()).

  1. Écrire le programme de test pour les circuits I2C à votre disposition (PCF8591, DS1621, etc …).

Sam-ba

Le programme de test fourni doit se terminer pour pouvoir réactiver l’interface JTAG à la fin de son exécution. Si votre programme de test “plante” en bouclant indéfinimment vous ne pourrez plus reflasher un nouveau programme car l’interface JTAG ne sera plus opérationnelle !

Dans ce cas, il vous faudra utiliser sam-ba et le port micro-USB de la carte. Ce port USB permettra de reprogrammer les mémoires de la carte Atmel SAM4S-EK.

Le logiciel SAM-BA est un ensemble d’outils pour la programmation des microcontrôleurs ARM (SAMA5, SAM3, SAM4, SAM7 et SAM9) fourni par Atmel.

Vous devez d’abord faire un effacement des mémoires :

  • débrancher l’alimentation
  • mettre un cavalier en JP3 ERASE
  • rebrancher l’alimentation
  • débrancher l’alimentation
  • retirer le cavalier en JP3 ERASE
  • rebrancher l’alimentation

Relier un câble USB entre la carte SAM4S-EK et le PC et on vérifie la détection du périphérique de programmation :

$ dmesg
[1588905.664962] usb 3-9.4.1: new full-speed USB device number 24 using xhci_hcd
[1588905.681465] usb 3-9.4.1: New USB device found, idVendor=03eb, idProduct=6124
[1588905.681468] usb 3-9.4.1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[1588905.681564] usb 3-9.4.1: ep 0x83 - rounding interval to 1024 microframes, ep desc says 2040 microframes
[1588905.682070] cdc_acm 3-9.4.1:1.0: This device cannot do calls on its own. It is not a modem.
[1588905.682082] cdc_acm 3-9.4.1:1.0: ttyACM0: USB ACM device
[1588911.084124] usb 3-9.4.1: USB disconnect, device number 24
[1588928.383005] usb 3-9.4.1: new full-speed USB device number 25 using xhci_hcd
[1588928.399682] usb 3-9.4.1: New USB device found, idVendor=03eb, idProduct=6124
[1588928.399685] usb 3-9.4.1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[1588928.399810] usb 3-9.4.1: ep 0x83 - rounding interval to 1024 microframes, ep desc says 2040 microframes
[1588928.400339] cdc_acm 3-9.4.1:1.0: This device cannot do calls on its own. It is not a modem.
[1588928.400353] cdc_acm 3-9.4.1:1.0: ttyACM0: USB ACM device

$ lsusb
Bus 003 Device 025: ID 03eb:6124 Atmel Corp. at91sam SAMBA bootloader

$ ls -l /dev/ttyACM0
crw-rw---- 1 root dialout 166, 0 juil.  2 16:46 /dev/ttyACM0

Attention : le périphérique /dev/ttyACM0 ne sera accessible en lecture/écriture que par l’utilisateur propriétaire root et les membres du groupe dialout. Tous les autres (other) utilisateurs auront aucun accès. Pour modifier cette situation, vous pouvez soit changer les droits manuellement ($ sudo chmod 666 /dev/ttyACM0) soit ajouter l’utilisateur (ici toto) dans le groupe dialout ($ sudo adduser toto dialout).

On installe maintenant sam-ba (www.atmel.com) :

$ sudo apt-get install tcl8.4 tclx8.4 tk8.4

$ cd /opt/

$ unzip sam-ba_2.15.zip 

$ rm -f sam-ba_2.15.zip

$ ls
sam-ba_cdc_linux  

$ ls sam-ba_cdc_linux 
applets  doc  sam-ba  sam-ba_64  tcl_lib  usr

// Manuellement
$ export PATH=$PATH:/opt/sam-ba_cdc_linux

$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:$HOME/bin:/opt/sam-ba_cdc_linux

// Automatiquement
$ vim ~/.bashrc
export PATH=$PATH:/opt/sam-ba_cdc_linux

$ source $HOME/.bashrc

Télécharger le programme de démo pour la carte Atmel SAM4S-EK sam4s_ek_demo_1.1_binary.zip :

$ wget -c http://www.atmel.com/images/sam4s_ek_demo_1.1_binary.zip

$ unzip sam4s_ek_demo_1.1_binary.zip

On démarre sam-ba et on transfère le programme sam4s-ek-demo.bin puis on exécute un Boot from Flash :

$ sam-ba_64

Bilan

Vous devez être capable de répondre aux questions suivantes :

  1. Définir un bus de communication série.

  2. Définir la notion d’acquittement dans un protocole de communication.

  3. Quel est le rôle du maître dans la communication ?

  4. À quoi sert le bit R/W ?

  5. Quelle est l’adresse du circuit PCF8591 ? DS1621 ? Commenter.

  6. Combien de circuits PCF8574 peut-on relier sur un même bus TWI/I2C ? Combien d’E/S peut-on alors disposer ?

  7. À quoi servent les résistances de pull-up sur le bus ?

  8. Quel est alors le nom donné à l’étage de sortie des lignes SDA et SCL ?

  9. En prenant le point de vue du programmeur, que trouve-t-on à l’intérieur d’un circuit I2C ?

Glossaire

Bus TWI/I2C (compléments)
Le codage utilisé sur le bus TWI/I2C est de type NRZ (non retour à 0) :

Le niveau (« HIGH » ou « LOW ») de la ligne SDA doit être maintenu stable pendant le niveau « HIGH » sur la ligne SCL pour la lecture du bit.

Il existe cinq vitesses de transmission :

  • « Standard mode » ≤ 100 kbit/s,
  • « Fast mode » ≤ 400 kbit/s,
  • « Fast plus mode » ≤ 1 Mbit/s,
  • « High-speed mode » ≤ 3,4 Mbit/s,
  • « Ultra-fast mode » ≤ 5 Mbit/s.

Le bus étant synchrone, c’est le maître qui impose l’horloge via la ligne SCL.

Échange maître/esclave
Le message peut être décomposé en deux parties :
  • Le maître est l’émetteur, l’esclave est le récepteur :
    • émission d’une condition de START par le maître (« S »),
    • émission de l’octet d’adresse par le maître pour désigner un esclave, avec le bit R/W à 0,
    • réponse de l’esclave par un bit d’acquittement ACK (ou de non-acquittement NACK),
    • émission d’un octet de commande par le maître pour l’esclave,
    • réponse de l’esclave par un bit d’acquittement ACK (ou de non-acquittement NACK),
    • émission d’une condition de RESTART par le maître (« RS »),
    • émission de l’octet ou des octets d’adresse par le maître pour désigner le même esclave, avec le bit R/W à 1.
  • Le maître devient récepteur, l’esclave devient émetteur :
    • émission d’un octet de données par l’esclave pour le maître,
    • réponse du maître par un bit d’acquittement ACK (ou de non-acquittement NACK),
    • (émission d’autres octets de données par l’esclave avec acquittement du maître),
    • pour le dernier octet de données attendu par le maître, il répond par un NACK pour mettre fin au dialogue,
    • émission d’une condition de STOP par le maître (« P »).

La condition de START est une transgression de la règle de codage des bits qui est utilisée par le maître pour signifier le début d’une trame. Cette condition est caractérisée par le passage de la ligne SDA du niveau « HIGH » au niveau « LOW » pendant que la ligne « SCL » est maintenue au niveau « HIGH ».

La condition de STOP est une transgression de la règle de codage des bits qui est utilisée par le maître pour signifier la fin d’une trame. Cette condition est caractérisée par le passage de la ligne SDA du niveau « LOW » au niveau « HIGH » pendant que la ligne SCL est maintenue au niveau « HIGH ».

Le récepteur positionne le bit d’acquittement à :

  • « ACK », en forçant la ligne SDA au niveau « LOW », pour signaler la bonne réception de l’octet, équivalent à un bit à 0,
  • « NACK », en laissant la ligne SDA au niveau « HIGH », pour signaler un défaut dans la réception de l’octet, équivalent à un bit à 1.
Adressage I2C
L’octet d’adressage peut être scindé en deux parties :
  • les sept premiers bits correspondent à l’adresse proprement dite,
  • le dernier bit est nommé R/W :
    • s’il est à 0, le maître signale qu’il va envoyer des octets, et donc que l’esclave doit les lire,
    • s’il est à 1, le maître indique qu’il veut recevoir des octets, et donc que l’esclave doit les fournir.

On peut également considérer que l’adresse est codée sur les 8 bits, chaque esclave a alors deux adresses, l’adresse paire qui sert à lui envoyer des données, l’adresse impaire pour lui demander d’en envoyer.

Généralement, les fabricants des circuits I2C fixent une partie de l’adresse pour permettre d’identifier le type de circuit et laissent une partie libre permettant de relier plusieurs circuits du même type sur le bus.

Par exemple, le circuit I2C de 8 bits E/S (I/O) est déclinée en deux versions donnant deux adresses de base :

  • PCF8574 dont les 7 bits d’adresses sont : 0100 A2A1A0 -> 0x4.
  • PCF8574A dont les 7 bits d’adresses sont : 0111 A2A1A0 -> 0x7.

Le fabricant a laissé libre les 3 bits d’adresses de poids faible (A2 A1 A0) ce qui permettra de relier 2^3 = 8 circuits sur un même bus.

TOR
Signal à deux états stables représentant l’état d’une E/S ou d’un organe (capteur/actionneur), par exemple : vanne ouverte ou fermée, capteur fin de course activée ou non …
USB

USB (Universal Serial Bus) est une norme relative à un bus informatique en transmission série qui sert à connecter des périphériques informatiques à un ordinateur. Le bus USB permet de connecter des périphériques à chaud (quand l’ordinateur est en marche) et en bénéficiant du Plug and Play (le système reconnaît automatiquement le périphérique). Il peut alimenter les périphériques peu gourmands en énergie.

Lors de la connexion du périphérique à l’hôte, ce dernier détecte l’ajout du nouvel élément grâce au changement de la tension entre les fils D+ et D-. À ce moment, l’ordinateur envoie un signal d’initialisation au périphérique puis à lui fournir une adresse définitive et à obtenir sa description : c’est la procédure d’énumération.

En effet, après avoir reçu son adresse, le périphérique transmet à l’hôte une liste de caractéristiques qui permettent à ce dernier de l’identifier (type, constructeur, nom, version). L’hôte, disposant de toutes les caractéristiques nécessaires est alors en mesure de charger le pilote approprié.

Les périphériques sont regroupés en types ou classes dans la terminologie USB. Tous les dispositifs d’une classe donnée reconnaissent le même protocole normalisé. Il existe par exemple une classe pour les périphériques de stockage de masse (mass storage class), implémentée par la quasi-totalité des clés USB, disques durs externes, appareils photo et par certains baladeurs. La plupart des systèmes d’exploitation possèdent des pilotes génériques, pour chaque type de périphérique. Ces pilotes génériques donnent accès aux fonctions de base, mais des fonctions avancées peuvent manquer.

Le bus USB ne permet pas de relier entre eux deux périphériques ou deux hôtes : le seul schéma de connexion autorisé est un périphérique sur un hôte. Pour éviter des branchements incorrects, la norme spécifie deux types de connecteurs : le type A, destiné à être situé sur l’hôte, et le type B, destiné à être situé sur le périphérique. Une mise à jour de la norme USB 2 introduit une version miniature du connecteur B : le mini-B. Elle est fonctionnellement équivalente au connecteur B, mais de dimensions nettement réduites.

Annexe : les fonctions my_init() et mdelay()

La fonction my_init() fournie permet d’initialiser la carte (board_init()), le système d’horloge (sysclk_init()) et le port série UART (configure_uart()). Une fonction mdelay() fournit un moyen de réaliser des temporisations d’attente en millisecondes.

#define STRING_EOL    "\r"
#define STRING_HEADER \
        "-- Exemple LED Bleue - "BOARD_NAME" --\r\n" \
        "-- "__DATE__" "__TIME__" --"STRING_EOL

/** UART Interface */
#define CONF_UART            CONSOLE_UART
#define CONF_UART_BAUDRATE   115200
#define CONF_UART_PARITY     UART_MR_PAR_NO
#define CONF_UART_CHAR_LENGTH  US_MR_CHRL_8_BIT
#define CONF_UART_STOP_BITS    US_MR_NBSTOP_1_BIT

volatile uint32_t g_ul_ms_ticks = 0;

static void my_init(void);
static void configure_uart(void);
static void mdelay(uint32_t ul_dly_ticks);

/**
 *  Initialise
 */
static void my_init(void)
{
    board_init();
    sysclk_init();

    /* Initialise le port uart */
    configure_uart();

    /* Envoie une chaîne de caractères */
    puts(STRING_HEADER);
    
    /* Configure les tics à 1 ms */
    if (SysTick_Config(sysclk_get_cpu_hz() / 1000)) 
    {
        puts("Erreur systick configuration\r");
        while (1);
    }
}

/**
 *  \brief Gestionnaire d'évènement pour les tics d'interruptions système
 *
 *  Incremente le compteur g_ul_ms_ticks
 *  
 */
void SysTick_Handler(void)
{
    g_ul_ms_ticks++;
}

/**
 * \brief Temporisation d'attente en millisecondes (basée sur les tics systèmes du microcontrôleur)
 *
 * \param ul_dly_ticks  temps d'attente en millisecondes
 */
static void mdelay(uint32_t ul_dly_ticks)
{
    uint32_t ul_cur_ticks;

    ul_cur_ticks = g_ul_ms_ticks;
    while ((g_ul_ms_ticks - ul_cur_ticks) < ul_dly_ticks);
}

/**
 *  Configure UART.
 */
static void configure_uart(void)
{
    const usart_serial_options_t uart_serial_options = 
    {
        .baudrate = CONF_UART_BAUDRATE,
        .charlength = CONF_UART_CHAR_LENGTH,
        .paritytype = CONF_UART_PARITY,
        .stopbits = CONF_UART_STOP_BITS,
    };

    sysclk_enable_peripheral_clock(CONSOLE_UART_ID);
    stdio_serial_init(CONF_UART, &uart_serial_options);
}

Retour au sommaire