Le buffer circulaire est une structure de données à taille fixe doté d'un pointeur de lecture et d'un pointeur d'écriture. Ces pointeurs reviennent à zéro lorsque l'on atteint la fin du buffer. Un processus "producteur" va placer des données dans le buffer afin qu'elles soient consommées par un autre processus
Une visualisation d'un ring buffer de 16 octets. La chaîne "Ca va bien?" n'a pas encore été consommée par le processus consommateur.
Avant d'aller plus loin, nous allons écrire le code C d'un buffer circulaire. Voici à quoi devrai ressembler le fichier d'en-têtes :
#define RING_BUFFER_SIZE 32
struct ring_buffer {
// ...
};
// Initialise le buffer circulaire
void ring_buffer_init(struct ring_buffer *rb);
// Ajoute un octet dans le buffer circulaire
void ring_buffer_put(struct ring_buffer *rb, uint8_t data);
// Récupère un octet du buffer circulaire
uint8_t ring_buffer_get(struct ring_buffer *rb);
// Indique le nombre d'octets disponibles dans le buffer circulaire
uint8_t ring_buffer_available_bytes(struct ring_buffer *rb);
// Indique si le buffer circulaire est plein
uint8_t ring_buffer_is_full(struct ring_buffer *rb);
Testez le code du buffer circulaire en compilant sur votre ordinateur un programme de test. Pensez notamment à tester les cas limites (lecture dans un buffer vide, écriture dans un buffer plein).
Aidez vous de la section USART0 (de la page 143 à la page 165) de la datasheet de l'ATmega328P pour répondre aux questions ci-dessous:
Mettez désormais à jour le code de l'UART afin d'utiliser les interruptions pour l'envoi et la réception de données.
Commencez par écrire les fonctions suivante afin de gérer l'envoi de données :
// Initialise l'UART à la vitesse donnée
void uart_init(uint32_t baudrate);
// Envoie un octet sur l'UART
void uart_send_byte(uint8_t data);
// Envoie une chaîne de caractères sur l'UART
void uart_send_string(const char *str);
Puis les fonctions suivantes afin de gérer la réception de données :
// Indique si l'UART a au moins un octet disponible
uint8_t uart_available();
// Récupère un octet de l'UART
uint8_t uart_read_byte();
Reproduisez dans un firmware uart
le comportement du TD précédent avec votre
nouvelle implémentation de l'UART.
$ minicom -b 115200 -o -D /dev/ttyACM0
Entrez du texte: Hello World!
Vous avez saisi: Hello World!
À l'aide de la commande:
$ avr-size --mcu=atmega328p -C build/firmware.elf
Il est possible de connaître la taille du programme généré. Comparez la taille de la section "Program" si vous utilisez des buffers circulaires de 31, 32 et 33 octets.
Comment expliquez-vous cela ?
Vous pouvez vous aider de avr-objdump -d build/firmware.elf
dans ces cas pour comprendre ce qui se passe.