Communication sans fil avec STM32F103 et module LoRa

Connexion matérielle

Correspondance des broches

Broche STM32 Broche SX1278 Fonction
PA4 (NSS) NSS Sélection SPI
PA5 (SCK) SCK Horloge SPI
PA6 (MISO) MISO Données maître vers esclave
PA7 (MOSI) MOSI Données esclave vers maître
PB0 (RST) RESET Réinitialissation
PB1 (DIO0) DIO0 Interruption

Conception électronique

  • Filtrage d'alimentation : Condensateur 10μF + 0.1μF entre 3.3V et GND
  • Protection des signaux : Résistances 1kΩ en série sur les lignes SPI et DIO0
  • Adaptation d'antenne : Antenne 50Ω avec antenne hélicoïdale externe recommandée

Environnement logiciel

Outils de dévelopement

  • IDE : STM32CubeIDE
  • Version HAL : 1.8.3
  • Bibliothèque LoRa : Pilote Semtech SX127x v4.4.2

Configuration clé

// Configuration CubeMX :
SPI1 : Mode maître, fréquence 32MHz, format 8 bits
GPIO : PA4 en sortie (contrôle manuel NSS)
EXTI : PB1 en interruption sur front montant

Implémentation du pilote

Initialisation SPI

void Configurer_SPI1(void) {
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
  HAL_SPI_Init(&hspi1);
}

uint8_t Echanger_SPI(uint8_t *emission, uint8_t *reception, uint16_t taille) {
  HAL_SPI_TransmitReceive(&hspi1, emission, reception, taille, 1000);
  return HAL_SPI_GetState(&hspi1);
}

Configuraton LoRa

#define PIN_RESET  GPIO_PIN_0
#define PIN_DIO0   GPIO_PIN_1

void Reinitialiser_SX1278(void) {
  HAL_GPIO_WritePin(GPIOB, PIN_RESET, GPIO_PIN_RESET);
  HAL_Delay(10);
  HAL_GPIO_WritePin(GPIOB, PIN_RESET, GPIO_PIN_SET);
  HAL_Delay(100);
}

void Ecrire_Registre(uint8_t adresse, uint8_t valeur) {
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  Echanger_SPI(&adresse, NULL, 1);
  Echanger_SPI(&valeur, NULL, 1);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
}

uint8_t Lire_Registre(uint8_t adresse) {
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  Echanger_SPI(&adresse, NULL, 1);
  uint8_t donnee;
  Echanger_SPI(&donnee, NULL, 1);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
  return donnee;
}

void Initialiser_LoRa(void) {
  Reinitialiser_SX1278();
  Ecrire_Registre(0x06, 0x6C);  // Fréquence 433 MHz
  Ecrire_Registre(0x07, 0x80);
  Ecrire_Registre(0x08, 0x00);
  Ecrire_Registre(0x1E, 0x74);  // Facteur d'étalement SF12
  Ecrire_Registre(0x1D, 0x0A);  // Bande 125 kHz
  Ecrire_Registre(0x09, 0x81);  // Puissance 20 dBm
}

Transmission de données

Émission

void Emettre_Trame(uint8_t *donnees, uint8_t longueur) {
  Ecrire_Registre(0x01, 0x01);  // Mode veille
  Ecrire_Registre(0x0D, 0x00);  // Pointeur FIFO
  Ecrire_Registre(0x22, longueur);  // Longueur charge utile
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  Echanger_SPI(0x00, donnees, longueur);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
  Ecrire_Registre(0x01, 0x03);  // Mode émission
  while((Lire_Registre(0x12) & 0x08) == 0);  // Attente fin transmission
}

Réception par interruption

uint8_t bufferReception[256];
uint8_t compteurReception = 0;

void HAL_GPIO_EXTI_Callback(uint16_t broche) {
  if(broche == GPIO_PIN_1) {
    uint8_t flags = Lire_Registre(0x12);
    uint8_t longueur = Lire_Registre(0x22);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
    Echanger_SPI(0x00, bufferReception, longueur);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
    compteurReception = longueur;
    Ecrire_Registre(0x12, 0x04);  // Effacer drapeau
  }
}

Paramétrage avancé

Configuration dynamique

void Ajuster_Parametres(float distance) {
  if(distance > 5000) {
    Ecrire_Registre(0x1E, 0xC0);  // SF12, BW 62.5kHz
  } else if(distance > 2000) {
    Ecrire_Registre(0x1E, 0xA0);  // SF10, BW 125kHz
  }
}

Gestion des erreurs

uint8_t Verifier_CRC(uint8_t *donnees, uint8_t taille) {
  uint8_t crc = 0;
  for(uint8_t i = 0; i < taille; i++) {
    crc ^= donnees[i];
    for(uint8_t j = 0; j < 8; j++) {
      crc = (crc & 0x80) ? (crc << 1) ^ 0x31 : crc << 1;
    }
  }
  return crc;
}

Problèmes courants

Symptôme Solution
Échec de réception Vérifier la configuration DIO0
Perte de paquets Activer le CRC et retransmission
Portée réduite Ajuster le facteur d'étalement

Étiquettes: STM32F103 LoRA SX1278 SPI Communication sans fil

Publié le 20 juillet à 08h46