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; ihw->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 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);