1. Introduction
L'objectif était de développer un protocole de communication entre le microcontrôleur nrf52832 et deux capteurs de force à semi-pont chinois.
La tâche s'est avérée difficile, car j'ai été confronté à un manque d'informations claires. Plus probablement, « la racine du mal » se trouve dans le SDK de Nordic Semiconductor lui-même - les mises à jour constantes des versions, une certaine redondance et la confusion fonctionnelle. J'ai dû tout écrire à partir de zéro.
Je pense que ce sujet est assez pertinent, étant donné que cette puce dispose d'une pile BLE et d'un ensemble complet de « fonctionnalités intéressantes » en mode économiseur d'énergie. Mais je ne vais pas entrer trop dans les détails techniques, car de nombreux articles ont déjà été écrits à ce sujet.
2. Description du projet

Matériel :
- Adafruit Feather nRF52 Bluefruit LE (ce qui était à portée de main)
- ADC HX711
- Capteurs de force chinois 2 pcs. (50x2 kg)
- Programmateur ST-LINK V2
Logiciel :
- IDE VSCODE
- NRF SDK 16
- OpenOCD
- Programmateur ST-LINK V2
Tout se trouve dans un seul projet, il suffira de modifier le Makefile (pour indiquer l'emplacement de votre SDK).
3. Description du code
Nous allons utiliser le module GPIOTE pour travailler avec les périphériques en fonction de l'association de tâches et d'événements, ainsi que le module PPI pour le transfert de données d'un périphérique à un autre sans l'intervention du processeur.
ret_code_t err_code;
err_code = nrf_drv_gpiote_out_init(PD_SCK, &config); //configuration en sortie
nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false); // nous allons basculer la broche pour une impulsion
err_code = nrf_drv_gpiote_out_init(PD_SCK, &config); //configuration en sortie
Nous configurons la ligne de synchronisation PD_SCL en sortie pour générer des impulsions d'une durée de 10 µs.
nrf_drv_gpiote_in_config_t gpiote_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(false); // transition de niveau de haut en bas
nrf_gpio_cfg_input(DOUT, NRF_GPIO_PIN_NOPULL); // en entrée sans résistance de tirage
err_code = nrf_drv_gpiote_in_init(DOUT, &gpiote_config, gpiote_evt_handler); static void gpiote_evt_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
nrf_drv_gpiote_in_event_disable(DOUT); // désactiver l'interruption
nrf_drv_timer_enable(&m_timer0); // activer le minuteur
}
Nous configurons la ligne de données DOUT pour lire l'état de disponibilité du HX711, lorsqu'un niveau bas est détecté, le gestionnaire est déclenché, où nous désactivons l'interruption et lançons un minuteur pour générer des impulsions de synchronisation à la sortie PD_SCL.
err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel1);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_assign(m_ppi_channel1, nrf_drv_timer_event_address_get(&m_timer0, NRF_TIMER_EVENT_COMPARE0), nrf_drv_gpiote_out_task_addr_get(PD_SCK)); // nous connectons le timer à la sortie
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_enable(m_ppi_channel1); // nous activons le canal
APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_out_task_enable(PD_SCK); // включаем gpiote
Ensuite, nous initialisons le module PPI et connectons notre timer à la sortie PD_SCL, pour générer des impulsions d'une durée de 10µs lors de l'événement de comparaison, et activons également le module GPIOTE.
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG; // par défaut
timer_cfg.frequency = NRF_TIMER_FREQ_1MHz; // émettons à une fréquence de 1MHz
ret_code_t err_code = nrf_drv_timer_init(&m_timer0, &timer_cfg, timer0_event_handler);
APP_ERROR_CHECK(err_code);
nrf_drv_timer_extended_compare(&m_timer0,
NRF_TIMER_CC_CHANNEL0,
nrf_drv_timer_us_to_ticks(&m_timer0,
10),
NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
true); // s'active lors de la comparaisonNous initialisons le timer zéro et son gestionnaire.
if(m_counter%2 != 0 && m_counter<=48){
buffer <<= 1; // variable des données lues
c_counter++; // compteur des impulsions positives
if(nrf_gpio_pin_read(DOUT)) buffer++; // lecture de l'état de l'entrée
}
Les choses intéressantes se passent dans le gestionnaire de timer. La période des impulsions est de 20µs. Nous sommes intéressés par les impulsions impaires (sur le front montant) et à condition qu'elles soient au nombre de 24, et les événements — 48. À chaque événement impair, nous lisons DOUT.
D'après la fiche technique, le nombre d'impulsions doit être d'au moins 25, ce qui correspond à un coefficient d'amplification de 128 (dans le code, j'ai utilisé 25 impulsions), ce qui équivaut à 50 événements du timer, indiquant la fin du cadre de données.
++m_counter; // compteur des événements
if(m_counter==50){
nrf_drv_timer_disable(&m_timer0); // désactivation du timer
m_simple_timer_state = SIMPLE_TIMER_STATE_STOPPED; //
buffer = buffer ^ 0x800000;
hx711_stop(); // déconnexion de hx711
}
Après cela, nous désactivons le timer et traitons les données (selon la fiche technique) et plaçons le HX711 en mode basse consommation.
static void repeated_timer_handler(void * p_context)
{
nrf_drv_gpiote_out_toggle(LED_2);
if(m_simple_timer_state == SIMPLE_TIMER_STATE_STOPPED){
hx711_start(); // Démarrer hx711
nrf_drv_gpiote_out_toggle(LED_1);
m_simple_timer_state = SIMPLE_TIMER_STATE_STARTED;
}
}
/**@brief Créer des minuteurs.
*\/
static void create_timers()
{
ret_code_t err_code;
// Créer des minuteurs
err_code = app_timer_create(&m_repeated_timer_id,
APP_TIMER_MODE_REPEATED,
repeated_timer_handler);
APP_ERROR_CHECK(err_code);
}
Nous attendons un événement du minuteur RTC avec un intervalle de 10 s (cela reste à votre appréciation) dans le gestionnaire, nous démarrons HX711 en appelant une interruption sur la ligne DOUT.
Il y a un autre point, les logs sont affichés via UART (débit 115200, TX — pin 6, RX — pin 8) tous les réglages se trouvent dans sdk_config.h

Conclusions
Merci à tous pour votre attention, j'espère que cet article sera utile et vous fera gagner un temps précieux dans la recherche de solutions pour les développeurs. Je tiens à dire que l'approche technique utilisée par Nordic dans ses plateformes est assez intéressante en termes d'efficacité énergétique.
P.S.
Le projet est encore en cours de développement, donc si ce sujet vous intéresse, dans un prochain article je m'efforcerai de décrire l'algorithme de calibration des capteurs de poids, ainsi que la connexion de la pile BLE.
Matériaux
Source : habr.com
