基于stm32CubeMX控制LORA芯片SX1280 SPI通信

· 更新于

LORASPIstm32SX1280

1,资源

sx1280芯片官网:https://www.semtech.cn/products/wireless-rf/lora-connect/sx1280

官网C语言源码下载:https://semtech.my.salesforce.com/sfc/p/E0000000JelG/a/2R0000001NRT/MODO4Ha5BGMNCfkz4qk4WZV3_72TTgbbXqeOcuDog1A

下载后的压缩包名为:SX1280_DemoApp_V1_0.zip

解压后在:如下目录下找到SX1280_DemoApp\SMTC_Drivers\sx1280-driver-c

其中。radio.h是抽象头文件,里面都是函数指针,这里面的函数就是官方手册的实际调用函数。

sx1280-hal.c h是spi实现的读写函数,属于底层。(最要这里面修改我们自己的板子)

sx1280.c h是sx1280芯片的业务逻辑函数,不用动。

2,开始施工

1,stm32cbumx里面正常

我新建了比sx1280-hal还底层的文件mybase.c h,主要实现SpiInOut,SpiIn,GpioWrite,GpioRead

2,硬件驱动

mybase.c

`#include "mybase.h"  void SpiInit(void) { 	// RadioSpiHandle = hspi2; }  void GpioWrite( GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, uint32_t value ) {     HAL_GPIO_WritePin( GPIOx, GPIO_Pin , ( GPIO_PinState ) value ); }  uint32_t GpioRead( GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin ) {     return HAL_GPIO_ReadPin( GPIOx, GPIO_Pin ); } void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin ) {     // GpioLaunchIrqHandler( GPIO_Pin ); }  void SpiInOut( uint8_t *txBuffer, uint8_t *rxBuffer, uint16_t size ) { 	#ifdef STM32L4XX_FAMILY     	HAL_SPIEx_FlushRxFifo( &hspi2 ); // Comment For STM32L0XX and STM32L1XX Int間ration, uncomment for STM32L4XX Int間ration  	#endif     #ifdef USE_DMA         blockingDmaFlag = true;         HAL_SPI_TransmitReceive_DMA( &SpiHandle, txBuffer, rxBuffer, size );         WAIT_FOR_BLOCKING_FLAG     #else         HAL_SPI_TransmitReceive( &hspi2, txBuffer, rxBuffer, size, HAL_MAX_DELAY );     #endif }  void SpiIn( uint8_t *txBuffer, uint16_t size ) {     #ifdef USE_DMA         blockingDmaFlag = true;         HAL_SPI_Transmit_DMA( &SpiHandle, txBuffer, size );         WAIT_FOR_BLOCKING_FLAG     #else         HAL_SPI_Transmit( &hspi2, txBuffer, size, HAL_MAX_DELAY );     #endif }`

mybase.h

`#ifndef __MYBASE_H__ #define __MYBASE_H__  #include <stdint.h> #include <stdbool.h> #include <math.h>   #include "main.h" #include "gpio.h" #include "spi.h" #include "sx1280.h" /*****  * 说明:这个函数实现sx1280官方库的底层硬件函数  *  */  extern SPI_HandleTypeDef hspi2;    #define RADIO_nRESET_PORT    SX1280_RST_GPIO_Port #define RADIO_nRESET_PIN     SX1280_RST_Pin #define RADIO_NSS_PORT       SPI2_NSS_GPIO_Port #define RADIO_NSS_PIN        SPI2_NSS_Pin #define RADIO_DIO1_GPIO_Port SX1280_DIO1_GPIO_Port #define RADIO_DIO1_Pin       SX1280_DIO1_Pin #define RADIO_BUSY_PORT      SX1280_BUSY_GPIO_Port #define RADIO_BUSY_PIN       SX1280_BUSY_Pin   void GpioWrite( GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin,  uint32_t value ); uint32_t GpioRead( GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin );   void SpiInit( void ); void SpiInOut( uint8_t *txBuffer, uint8_t *rxBuffer, uint16_t size ); void SpiIn( uint8_t *txBuffer, uint16_t size );  #endif`

main.h

`#define SX1280_RST_Pin GPIO_PIN_7 #define SX1280_RST_GPIO_Port GPIOA #define SX1280_RXEN_Pin GPIO_PIN_4 #define SX1280_RXEN_GPIO_Port GPIOC #define SX1280_TXEN_Pin GPIO_PIN_5 #define SX1280_TXEN_GPIO_Port GPIOC #define SX1280_BUSY_Pin GPIO_PIN_2 #define SX1280_BUSY_GPIO_Port GPIOB #define SX1280_DIO1_Pin GPIO_PIN_10 #define SX1280_DIO1_GPIO_Port GPIOB`

3,上层APP

my1280app.c

`#include "my1280app.h"  const uint8_t PingMsg[] = "PING"; const uint8_t PongMsg[] = "PONG";  RadioCallbacks_t Callbacks = {     &OnTxDone,        // txDone     &OnRxDone,        // rxDone     NULL,             // syncWordDone     NULL,             // headerDone     &OnTxTimeout,     // txTimeout     &OnRxTimeout,     // rxTimeout     &OnRxError,       // rxError     NULL,             // rangingDone     &OnCadDone,       // cadDone };  uint8_t BufferSize = BUFFER_SIZE; uint8_t Buffer[BUFFER_SIZE]; uint16_t RxIrqMask = IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT; uint16_t TxIrqMask = IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT; AppStates_t AppState = APP_LOWPOWER;  PacketParams_t packetParams; PacketStatus_t packetStatus; ModulationParams_t modulationParams;  bool isMaster = true; // bool isMaster = false;  void LoRa_init() {     HAL_GPIO_WritePin(SX1280_RST_GPIO_Port, SX1280_RST_Pin, GPIO_PIN_RESET);     HAL_Delay(100);     HAL_GPIO_WritePin(SX1280_RST_GPIO_Port, SX1280_RST_Pin, GPIO_PIN_SET);     printf( "Radio firmware version 0x%x\r\n", SX1280GetFirmwareVersion() );     if(isMaster==true)     {         printf( "Master LORA mode\n\r" );     }     else     {         printf( "Slaver LORA mode\n\r" );     }      Radio.Init( &Callbacks );     Radio.SetRegulatorMode( USE_DCDC );      modulationParams.PacketType = PACKET_TYPE_LORA;     modulationParams.Params.LoRa.SpreadingFactor = LORA_SF12;     modulationParams.Params.LoRa.Bandwidth = LORA_BW_1600;     modulationParams.Params.LoRa.CodingRate = LORA_CR_LI_4_7;      packetParams.PacketType = PACKET_TYPE_LORA;     packetParams.Params.LoRa.PreambleLength = 12;     packetParams.Params.LoRa.HeaderType = LORA_PACKET_VARIABLE_LENGTH;     packetParams.Params.LoRa.PayloadLength = BUFFER_SIZE;     packetParams.Params.LoRa.CrcMode = LORA_CRC_ON;     packetParams.Params.LoRa.InvertIQ = LORA_IQ_NORMAL;      Radio.SetStandby( STDBY_RC );     switch(modulationParams.Params.LoRa.SpreadingFactor){         case LORA_SF5:         case LORA_SF6:             Radio.WriteRegister(0x0925,0x1E);             break;         case LORA_SF7:         case LORA_SF8:             Radio.WriteRegister(0x0925,0x37);             break;         case LORA_SF9:         case LORA_SF10:         case LORA_SF11:         case LORA_SF12:             Radio.WriteRegister(0x0925,0x32);             break;     }     Radio.SetPacketType( modulationParams.PacketType );     Radio.SetModulationParams( &modulationParams );     Radio.SetPacketParams( &packetParams );     Radio.SetRfFrequency( RF_FREQUENCY );     Radio.SetBufferBaseAddresses( 0x00, 0x00 );     Radio.SetTxParams( TX_OUTPUT_POWER, RADIO_RAMP_02_US );          //SX1280SetPollingMode( );     SX1281SetInterruptMode();      if(isMaster==true)     {         //发送         HAL_GPIO_WritePin(SX1280_TXEN_GPIO_Port,SX1280_TXEN_Pin,GPIO_PIN_SET);         Radio.SetDioIrqParams( TxIrqMask, TxIrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );         Radio.SendPayload((uint8_t*)"123456",6, ( TickTime_t ){ RX_TIMEOUT_TICK_SIZE, TX_TIMEOUT_VALUE });     }     else     {         HAL_GPIO_WritePin(SX1280_RXEN_GPIO_Port,SX1280_RXEN_Pin,GPIO_PIN_SET);         Radio.SetDioIrqParams( RxIrqMask, RxIrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );         //Radio.SetRx( ( TickTime_t ) { RX_TIMEOUT_TICK_SIZE, RX_TIMEOUT_VALUE } );         Radio.SetRx( ( TickTime_t ) { RX_TIMEOUT_TICK_SIZE, 0xFFFF } );//RX_TIMEOUT_VALUE     }     AppState = APP_LOWPOWER; }  void LoRa_process() {     SX1280ProcessIrqs( );     HAL_Delay(1000); }            void OnTxDone( void ) {     AppState = APP_TX;     printf( "<>>>>>>>>OnTxDone\n\r" );      Radio.SetDioIrqParams( TxIrqMask, TxIrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );     Radio.SendPayload((uint8_t*)"123456",6, ( TickTime_t ){ RX_TIMEOUT_TICK_SIZE, TX_TIMEOUT_VALUE }); }  void OnRxDone( void ) {     AppState = APP_RX;     printf( "<>>>>>>>>OnRxDone\n\r" );      BufferSize = 0;     Radio.GetPayload( Buffer, &BufferSize, BUFFER_SIZE );     Buffer[BufferSize+1] = 0;     printf("size = %d ,%s",BufferSize,Buffer);     // printf("OnRxDone\r\n",Buffer,BufferSize);     //Radio.SetRx( ( TickTime_t ) { RX_TIMEOUT_TICK_SIZE, RX_TIMEOUT_VALUE } ); }  void OnTxTimeout( void ) {     AppState = APP_TX_TIMEOUT;     printf( "<>>>>>>>>TXE\n\r" );      Radio.SetDioIrqParams( TxIrqMask, TxIrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );     Radio.SendPayload((uint8_t*)"12345",5, ( TickTime_t ){ RX_TIMEOUT_TICK_SIZE, TX_TIMEOUT_VALUE }); }  void OnRxTimeout( void ) {     AppState = APP_RX_TIMEOUT;     printf( "<>>>>>>>>OnRxTimeout\n\r" );      //Radio.SetRx( ( TickTime_t ) { RX_TIMEOUT_TICK_SIZE, RX_TIMEOUT_VALUE } );     Radio.SetRx( ( TickTime_t ) { RX_TIMEOUT_TICK_SIZE, 0xFFFF } ); }  void OnRxError(int error) {     AppState = APP_RX_ERROR;     printf( "RXE<>>>>>>>>error code=%d\n\r",error);      Radio.SetRx( ( TickTime_t ) { RX_TIMEOUT_TICK_SIZE, RX_TIMEOUT_VALUE } );  }   void OnCadDone( bool channelActivityDetected ) {     printf( "<>>OnCadDone  CAD code=%d\n\r",channelActivityDetected); }`

my1280app.h

`#ifndef __MY1280APP_H #define __MY1280APP_H  #include "sx1280-hal.h" #include "sx1280.h" #include "radio.h"  /*!  * Select mode of operation for the Ping Ping application  */ //#define MODE_BLE #define MODE_LORA //#define MODE_GFSK //#define MODE_FLRC   #define RF_BL_ADV_CHANNEL_38             			2426000000 // Hz #define RF_BL_ADV_CHANNEL_0                     	2404000000 // Hz  /*!  * \brief Defines the nominal frequency  */ #define RF_FREQUENCY                                RF_BL_ADV_CHANNEL_0 // Hz  /*!  * \brief Defines the output power in dBm  *  * \remark The range of the output power is [-18..+13] dBm  */ #define TX_OUTPUT_POWER                             13  /*!  * \brief Defines the buffer size, i.e. the payload size  */ #define BUFFER_SIZE                                 6  /*!  * \brief Number of tick size steps for tx timeout  */ #define TX_TIMEOUT_VALUE                            10000 // ms  /*!  * \brief Number of tick size steps for rx timeout  */ #define RX_TIMEOUT_VALUE                            1000 // ms  /*!  * \brief Size of ticks (used for Tx and Rx timeout)  */ #define RX_TIMEOUT_TICK_SIZE                        RADIO_TICK_SIZE_1000_US  /*!  * \brief Defines the size of the token defining message type in the payload  */ #define PINGPONGSIZE                                4   /*!  * \brief Defines the states of the application  */ typedef enum {     APP_LOWPOWER,     APP_RX,     APP_RX_TIMEOUT,     APP_RX_ERROR,     APP_TX,     APP_TX_TIMEOUT, }AppStates_t;   /*!  * \brief Function to be executed on Radio Tx Done event  */ void OnTxDone( void );  /*!  * \brief Function to be executed on Radio Rx Done event  */ void OnRxDone( void );  /*!  * \brief Function executed on Radio Tx Timeout event  */ void OnTxTimeout( void );  /*!  * \brief Function executed on Radio Rx Timeout event  */ void OnRxTimeout( void );  /*!  * \brief Function executed on Radio Rx Error event  */ void OnRxError(int error); void OnCadDone( bool channelActivityDetected );  void LoRa_init(void); void LoRa_process(void);  #endif`

3,控制逻辑梳理

1,上电要手动RST复位sx1280芯片,否则不正常(低电平有效)

2,TXEN和RXEN,在使用前要打开(高电平有效)(只开一个)

3,每次接收和每次发送,都要新设置SetDioIrqParams中断源

4,控制:

可以循环读取寄存器SX1280GetIrqStatus判断收发数据

可以使用EXTI GPIO中断读取

5,在app文件里面,使用 isMaster 变量来选择主机发送还是从机接收。