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 变量来选择主机发送还是从机接收