diff --git a/Readme.md b/Readme.md
index 89c3ed8..ee9181b 100644
--- a/Readme.md
+++ b/Readme.md
@@ -6,6 +6,8 @@ Le but est de présenter un code assurant toutes les fonctions de déplacement d
 
 Ce code est conçu pour s'exécuter sur un Raspberry Pi Pico.
 
+Nous en profitons pour proposer également les fonctions bas niveau développée pour le Raspberry Pi Pico.
+
 ![Architecture du programme](doc/ProgrammeHolonome2023.png)
 
 Voici un bref paragraphe explicatif pour chaque bloc fonctionnel.
@@ -63,4 +65,16 @@ Cette fonction permet de parcourir une trajectoire en tenant compte des contrain
 2. Calcul de l'avancement sur la trajectoire. 
 3. Obtention de la nouvelle consigne de position.
 
-Pour se déplacer sur une trajectoire, cette fonction utilise les outils de gestion des trajectoires définis dans les fichiers `trajectoire*`.
\ No newline at end of file
+Pour se déplacer sur une trajectoire, cette fonction utilise les outils de gestion des trajectoires définis dans les fichiers `trajectoire*`.
+
+Fonctions bas niveau
+===================
+
+I2C Maître, non bloquant
+------------------------
+
+Le fichier [i2c_maitre.c](i2c_maitre.c) propose une implémentation non-bloquante de l'i2c. L'utilisation s'effectue ainsi :
+- La fonction *i2c_gestion* doit être appelée régulièrement.
+- La fonction *i2c_transmission* (ou une fonction englobant celle-ci, telle que *i2c_lire_registre_nb*) doit être appelée jusqu'à ce qu'elle renvoie I2C_SUCCES. 
+
+Pour un exemple concret lisant une valeur dans une mémoire i2c, voir *test_i2c_lecture_pico_annex_nb2* de [test.c](test.c)
\ No newline at end of file
diff --git a/Test.c b/Test.c
index ace90d0..78a34db 100644
--- a/Test.c
+++ b/Test.c
@@ -45,6 +45,7 @@ int test_i2c_bus(void);
 void affiche_localisation(void);
 int test_i2c_lecture_pico_annex();
 int test_i2c_lecture_pico_annex_nb();
+int test_i2c_lecture_pico_annex_nb2();
 
 
 // Mode test : renvoie 0 pour quitter le mode test
@@ -153,7 +154,7 @@ int mode_test(){
 
     case 'X':
     case 'x':
-        while(test_i2c_lecture_pico_annex_nb());
+        while(test_i2c_lecture_pico_annex_nb2());
         break;
 
     case PICO_ERROR_TIMEOUT:
@@ -322,6 +323,44 @@ int test_i2c_lecture_pico_annex_nb(){
     return test_continue_test();
 }
 
+int test_i2c_lecture_pico_annex_nb2(){
+    i2c_maitre_init();
+
+    uint8_t tampon[10];
+    uint8_t registre=0;
+    uint8_t adresse = 0x17;
+    uint32_t time_i2c[5];
+    const uint8_t T_MAX_I2C = 10;
+    enum i2c_resultat_t retour_i2c = I2C_EN_COURS;
+
+    time_i2c[0] = time_us_32();
+    time_i2c[2] = 0;
+
+    while(retour_i2c == I2C_EN_COURS){
+        time_i2c[1] = time_us_32(); // Pour mesurer le temps d'execution
+        i2c_gestion(i2c0);
+        retour_i2c = i2c_lire_registre_nb(adresse, registre, tampon, T_MAX_I2C);
+        time_i2c[2] += time_us_32() - time_i2c[1]; // Pour mesurer le temps d'execution
+        sleep_us(100); // Attente, ou le reste du code
+    }
+    time_i2c[3] = time_us_32() - time_i2c[0];
+
+    // Affichage
+    for(int i=0; i<T_MAX_I2C; i++){
+        printf("%c", tampon[i]);
+    }
+    printf("\n");
+
+    for(int i=0; i<T_MAX_I2C; i++){
+        printf("%2x ", tampon[i]);
+    }
+    printf("\n");
+
+    printf("Temps lecture : %u microsecondes, temps specifique i2c : %u microsecondes.\n", time_i2c[3], time_i2c[2]);
+
+    return test_continue_test();
+}
+
 int test_i2c_bus(){
     // Adresse I2C : 0b0100 000 R/W
     // Lecture des broches sur les registres 0 et 1
diff --git a/i2c_maitre.c b/i2c_maitre.c
index 7011836..b7fff17 100644
--- a/i2c_maitre.c
+++ b/i2c_maitre.c
@@ -7,8 +7,30 @@
 #define I2C_SDA_PIN 16
 #define I2C_SCL_PIN 17
 
+#define I2C_NB_MAX_TAMPON 20
+
+enum i2c_statu_t{
+    I2C_STATU_LIBRE,
+    I2C_STATU_OCCUPE
+} i2c_statu_i2c0;
+
+uint16_t I2C_tampon_envoi[I2C_NB_MAX_TAMPON];
+uint8_t I2C_tampon_reception[I2C_NB_MAX_TAMPON];
+uint16_t I2C_nb_a_envoyer, I2C_nb_a_recevoir;
+uint8_t adresse_7_bits;
+uint32_t i2c_error_code; // value of i2c->hw->tx_abrt_source if anything wrong happen, 0 if everything was fine.
+
+enum transaction_statu_t{
+    TRANSACTION_EN_COURS,
+    TRANSACTION_TERMINEE
+} statu_emission, statu_reception;
+
+void i2d_set_adresse_esclave(uint8_t _adresse_7bits);
+void i2c_charger_tampon_envoi(uint8_t* emission, uint16_t nb_envoi, uint16_t nb_reception);
+enum i2c_resultat_t i2c_transmission(uint8_t _adresse_7bits, uint8_t* emission, uint16_t nb_envoi, uint16_t nb_reception);
+
 void i2c_maitre_init(void){
-    stdio_init_all();
+    //stdio_init_all();
     i2c_init(i2c0, 100 * 1000);
 
     printf("Initialisation des broches\n");
@@ -22,9 +44,187 @@ void i2c_maitre_init(void){
     printf("%d et %d en I2C\n", I2C_SDA_PIN, I2C_SCL_PIN);
     gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);
     gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);
+
+    i2c_statu_i2c0 = I2C_STATU_LIBRE;
 }
 
-/// @brief Pour l'instant bloquant, mais devrait passer en non bloquant bientôt
+/// @brief Fonction à appeler régulièrement ou en interruption.
+/// @param i2c 
+void i2c_gestion(i2c_inst_t *i2c){
+    // on veut gérer l'i2c avec cette fonction.
+    // 2 cas :
+    // - Soit écriture simple (plusieurs octets (W))
+    // - Soit écriture + lecture (Adresse (W), registre (W), données (R))
+    // Pour écrire 1 octet, i2c->hw->data_cmd = xxx, (avec CMD:8 à 0, ) 
+    // Pour lire 1 octet, i2c->hw->data_cmd = xxx (avec CMD:8 à 1)
+    // Il faut mettre CMD:9 à 1 pour le dernier octet.
+
+    // Envoi des données (ou des demandes de lecture)
+    static uint16_t index_envoi=0, index_reception=0;
+
+    // Acquitement des erreurs, pas 100% fonctionnel ! TODO !
+    if(i2c->hw->tx_abrt_source !=0){
+        i2c_error_code = i2c->hw->tx_abrt_source;
+        printf("Erreur I2C tx_abrt_source : %#x\n", i2c_error_code);
+        // on efface l'erreur en lisant le registre clr_tx_abrt
+        index_envoi = i2c->hw->clr_tx_abrt;
+        I2C_nb_a_envoyer = 0;
+        index_reception = 0;
+        I2C_nb_a_recevoir = 0;
+        statu_emission = TRANSACTION_TERMINEE;
+        statu_reception = TRANSACTION_TERMINEE;
+        i2c_statu_i2c0 = I2C_STATU_LIBRE;
+        printf("Erreur acquitee\n");
+    }
+
+    while( (index_envoi < I2C_nb_a_envoyer) && (i2c_get_write_available(i2c)) ){
+        bool restart = false;
+        bool last = false;
+
+        if (index_envoi == 0){
+            // Début de l'envoi, assurons nous d'avoir la bonne adresse de l'esclave
+            i2c->hw->enable = 0;
+            i2c->hw->tar = adresse_7_bits;
+            i2c->hw->enable = 1;
+        }else{
+            // Passage de l'écriture à la lecture, on envoie un bit de restart.
+            if( !(I2C_tampon_envoi[index_envoi-1] & I2C_IC_DATA_CMD_CMD_BITS) && 
+                    (I2C_tampon_envoi[index_envoi] & I2C_IC_DATA_CMD_CMD_BITS)){
+                restart = true;
+            }
+        }
+
+        if(index_envoi + 1 == I2C_nb_a_envoyer){
+            // Fin de la trame, nous devons envoyer un bit de stop.
+            last = true;
+        }
+
+        i2c->hw->data_cmd =
+                I2C_tampon_envoi[index_envoi] |
+                bool_to_bit(restart) << I2C_IC_DATA_CMD_RESTART_LSB |
+                bool_to_bit(last) << I2C_IC_DATA_CMD_STOP_LSB;
+
+        if(last){
+            statu_emission = TRANSACTION_TERMINEE;
+            index_envoi = 0;
+            I2C_nb_a_envoyer = 0;
+            //printf("I2C emission terminee\n");
+        }else{
+            index_envoi++;
+        }
+        
+    }
+
+    // Réception des données - Lecture des données présentes dans le tampon
+    while( (index_reception < I2C_nb_a_recevoir) && (i2c_get_read_available(i2c)) ){
+        I2C_tampon_reception[index_reception] = (uint8_t) i2c->hw->data_cmd;
+        index_reception++;
+    }
+    if(index_reception == I2C_nb_a_recevoir && I2C_nb_a_recevoir > 0 ){
+        statu_reception = TRANSACTION_TERMINEE;
+        index_reception = 0;
+        I2C_nb_a_recevoir = 0;
+    }
+
+    if(statu_reception == TRANSACTION_TERMINEE && statu_emission == TRANSACTION_TERMINEE){
+        i2c_statu_i2c0 = I2C_STATU_LIBRE;
+    }
+
+}
+
+/// @brief Charge le tampon d'émission pour pré-mâcher le travail à la fonction i2c_gestion
+/// @param emission 
+/// @param nb_envoi 
+/// @param nb_reception 
+void i2c_charger_tampon_envoi(uint8_t* emission, uint16_t nb_envoi, uint16_t nb_reception){
+    // Données à envoyer
+    for(unsigned int index=0; index<nb_envoi; index++){
+        I2C_tampon_envoi[index] = (uint16_t) emission[index];
+    }
+    // Données à lire
+    for(unsigned int index=0; index<nb_reception; index++){
+        I2C_tampon_envoi[nb_envoi + index] = (uint16_t) 0x0100;
+    }
+}
+
+/// @brief Stock l'adresse de l'esclave avec lequel communiquer
+/// @param _adresse_7bits 
+void i2d_set_adresse_esclave(uint8_t _adresse_7bits){
+    adresse_7_bits =_adresse_7bits;
+}
+
+/// @brief Initialise la transmission I2, sur l'i2c0. Une transmission se compose de 2 trames I2C, une pour écrire (Adresse + données), une pour lire
+/// Si nb_reception = 0, alors la trame pour lire ne sera pas envoyée.
+/// @param emission : données à envoyer
+/// @param nb_envoi : nombre de données à envoyer
+/// @param nb_reception : nombre de données à recevoir
+/// @return 1 en cas d'échec, 0 en cas de succès
+enum i2c_resultat_t i2c_transmission(uint8_t _adresse_7bits, uint8_t* emission, uint16_t nb_envoi, uint16_t nb_reception){
+    static enum m_statu_t{
+        I2C_STATU_INIT,
+        I2C_STATU_EN_COURS,
+    }m_statu = I2C_STATU_INIT;
+
+    switch(m_statu){
+        case I2C_STATU_INIT:
+            // I2C libre ?
+            if(i2c_statu_i2c0 == I2C_STATU_OCCUPE){
+                return I2C_EN_COURS;
+            }
+            // Alors il est à nous !
+            i2c_statu_i2c0 = I2C_STATU_OCCUPE;
+            statu_emission = TRANSACTION_EN_COURS;
+            statu_reception = TRANSACTION_EN_COURS;
+            i2c_error_code = 0;
+
+            i2d_set_adresse_esclave(_adresse_7bits);
+
+            i2c_charger_tampon_envoi(emission, nb_envoi, nb_reception);
+            // Nous devons envoyer aussi une commande pour chaque octet à recevoir.
+            I2C_nb_a_envoyer = nb_envoi + nb_reception;
+            I2C_nb_a_recevoir = nb_reception;
+            
+            // On appelle le fonction gestion pour gagner du temps.
+            i2c_gestion(i2c0);
+            m_statu = I2C_STATU_EN_COURS;
+            break;
+
+        case I2C_STATU_EN_COURS:
+            if(i2c_statu_i2c0 == I2C_STATU_LIBRE){
+                m_statu = I2C_STATU_INIT;
+                if(i2c_error_code){
+                    return I2C_ECHEC;
+                }else{
+                    return I2C_SUCCES;
+                }
+                
+            }
+            break;
+    }
+    return I2C_EN_COURS;
+}
+
+/// @brief 
+enum i2c_resultat_t i2c_lire_registre_nb(uint8_t adresse_7_bits, uint8_t registre, uint8_t * reception, uint8_t len){
+    uint8_t emission[1];
+    emission[0] = registre;
+    enum i2c_resultat_t i2c_resultat;
+    i2c_resultat = i2c_transmission(adresse_7_bits, emission, 1, len);
+    if(i2c_resultat == I2C_SUCCES){
+        for(uint32_t i = 0; i < len; i++){
+            reception[i] = I2C_tampon_reception[i];
+        }
+        return I2C_SUCCES;
+    }else if(i2c_resultat == I2C_ECHEC){
+        return I2C_ECHEC;
+    }
+    return I2C_EN_COURS;
+    
+}
+
+
+
+/// @brief Pour l'instant bloquant, mais devrait passer en non bloquant bientôt => Non, voir i2c_lire_registre_nb
 /// @param adresse_7_bits 
 /// @param  
 /// @return 0: en cours, 
diff --git a/i2c_maitre.h b/i2c_maitre.h
index a1ad172..a153a44 100644
--- a/i2c_maitre.h
+++ b/i2c_maitre.h
@@ -1,9 +1,14 @@
-#define I2C_EN_COURS 0
-#define I2C_SUCCES 1
-#define I2C_ECHEC -1
-
+#include "pico/stdlib.h"
+#include "hardware/i2c.h"
 
+enum i2c_resultat_t {
+    I2C_EN_COURS,
+    I2C_SUCCES,
+    I2C_ECHEC
+};
 
 void i2c_maitre_init(void);
+void i2c_gestion(i2c_inst_t *i2c);
+enum i2c_resultat_t i2c_lire_registre_nb(uint8_t adresse_7_bits, uint8_t registre, uint8_t * reception, uint8_t len);
 int i2c_ecrire_registre(char adresse_7_bits, char registre, char valeur_registre);
-int i2c_lire_registre(char adresse_7_bits, char registre, char * reception, char len);
\ No newline at end of file
+int i2c_lire_registre(char adresse_7_bits, char registre, char * reception, char len);