/* / _____) _ | | ( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| (C)2013 Semtech Description: SX1276 driver specific target board functions implementation License: Revised BSD License, see LICENSE.TXT file include in the project Maintainer: Miguel Luis and Gregory Cristian */ #include "radio.h" #include "sx1276.h" #include "sx1276-board.h" #include "delay.h" #include "stdio.h" //复位脚 #define SX1278_RST_PIN_INDEX GPIO_Pin_11 #define SX1278_RST_PIN_GROUP GPIOB //SPI引脚 #define SX1278_CS_PIN_INDEX GPIO_Pin_12 #define SX1278_CS_PIN_GROUP GPIOB #define SX1278_SCK_PIN_INDEX GPIO_Pin_13 #define SX1278_SCK_PIN_GROUP GPIOB #define SX1278_MISO_PIN_INDEX GPIO_Pin_14 #define SX1278_MISO_PIN_GROUP GPIOB #define SX1278_MOSI_PIN_INDEX GPIO_Pin_15 #define SX1278_MOSI_PIN_GROUP GPIOB //DIO0引脚(这里修改了需要手动修改中断初始化和中断函数) #define SX1278_DIO0_PIN_INDEX GPIO_Pin_6 #define SX1278_DIO0_PIN_GROUP GPIOG //DIO1引脚(这里修改了需要手动修改中断初始化和中断函数) //#define SX1278_DIO1_PIN_INDEX GPIO_Pin_1 //#define SX1278_DIO1_PIN_GROUP GPIOB /*! * Radio driver structure initialization */ const struct Radio_s Radio = { SX1276Init, SX1276GetStatus, SX1276SetModem, SX1276SetChannel, SX1276IsChannelFree, SX1276Random, SX1276SetRxConfig, SX1276SetTxConfig, SX1276CheckRfFrequency, SX1276GetTimeOnAir, SX1276Send, SX1276SetSleep, SX1276SetStby, SX1276SetRx, SX1276StartCad, SX1276ReadRssi, SX1276Write, SX1276Read, SX1276WriteBuffer, SX1276ReadBuffer, SX1276SetMaxPayloadLength }; /*! * Antenna switch GPIO pins objects */ /* 我们的RA-01/02模组的天线切换开关由硬件自动控制,不需要软件控制 Gpio_t AntSwitchLf; Gpio_t AntSwitchHf;*/ /*! * Tx and Rx timers */ /*TimerEvent_t TxTimeoutTimer; TimerEvent_t RxTimeoutTimer; TimerEvent_t RxTimeoutSyncWord;*/ //实现ms级延时 //delayMs:延时的ms数 void SX1276DelayMs(uint32_t delayMs){ delay_ms(delayMs); } //定时器初始化(RX,TX,SyncWord定时完成后都需要调用 SX1276OnTimeoutIrq() 函数) void SX1276TimerInit(void){ } void TIM2_Int_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能 TIM2->CR1 |= TIM_CR1_URS; //如果不设置这个会导致定时器启动的时候立即进入中断 //定时器TIM3初始化 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位 TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断 //中断优先级NVIC设置 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM3中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级3级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器 TIM_ClearITPendingBit(TIM2, TIM_IT_Update); TIM_Cmd(TIM2, ENABLE); //启动TIM } void TIM3_Int_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能 TIM3->CR1 |= TIM_CR1_URS; //如果不设置这个会导致定时器启动的时候立即进入中断 //定时器TIM3初始化 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断 //中断优先级NVIC设置 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器 TIM_ClearITPendingBit(TIM3, TIM_IT_Update); TIM_Cmd(TIM3, ENABLE); //启动TIM } void TIM4_Int_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //时钟使能 TIM4->CR1 |= TIM_CR1_URS; //如果不设置这个会导致定时器启动的时候立即进入中断 //定时器TIM3初始化 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位 TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断 //中断优先级NVIC设置 NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //TIM3中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级3级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器 TIM_ClearITPendingBit(TIM4, TIM_IT_Update); TIM_Cmd(TIM4, ENABLE); //启动TIM } //定时器3中断服务程序 void TIM3_IRQHandler(void) //TIM3中断 { if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否 { TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志 TIM_Cmd(TIM3, DISABLE); //失能TIMx SX1276OnTimeoutIrq(); //发生中断后需要调用 SX1276OnTimeoutIrq 函数 //printf("\r\ntimer irq\r\n"); } } //开启 tx 超时定时器,定时timeoutMs 毫秒 void SX1276TxTimeoutTimerStart( uint32_t timeoutMs ){ //这里简化使用了一个定时器,实际工程中最好使用独立的3个定时器,或者使用软件定时器 TIM3_Int_Init((timeoutMs * 10) -1,(12000-1));//10Khz的计数频率,计数到10次为1ms } //关闭 tx 超时定时器 void SX1276TxTimeoutTimerStop(void){ ///这里简化使用了一个定时器,实际工程中最好使用独立的3个定时器,或者使用软件定时器 TIM_Cmd(TIM3, DISABLE); //失能TIMx } //开启 RX 超时定时器,定时timeoutMs 毫秒 void SX1276RxTimeoutTimerStart( uint32_t timeoutMs ){ //这里简化使用了一个定时器,实际工程中最好使用独立的3个定时器,或者使用软件定时器 TIM3_Int_Init((timeoutMs * 10) -1,7199);//10Khz的计数频率,计数到10次为1ms } //关闭 RX 超时定时器 void SX1276RxTimeoutTimerStop(void){ ///这里简化使用了一个定时器,实际工程中最好使用独立的3个定时器,或者使用软件定时器 TIM_Cmd(TIM3, DISABLE); //失能TIMx } //开启 SyncWord 超时定时器,定时timeoutMs 毫秒 void SX1276SyncWordTimeoutTimerStart( uint32_t timeoutMs ){ //这里简化使用了一个定时器,实际工程中最好使用独立的3个定时器,或者使用软件定时器 TIM3_Int_Init((timeoutMs * 10) -1,7199);//10Khz的计数频率,计数到10次为1ms } //关闭 SyncWord 超时定时器 void SX1276SyncWordTimeoutTimerStop(void){ ///这里简化使用了一个定时器,实际工程中最好使用独立的3个定时器,或者使用软件定时器 TIM_Cmd(TIM3, DISABLE); //失能TIMx } //初始化SPI(cs低使能,极性SPI_CPOL_High,相位SPI_CPHA_2Edge,SPI_FirstBit_MSB)和Rst脚 void SX1276IoInit( void ) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; //初始化一个gpio用来控制spi1的cs RCC_APB2PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz,这里不用传参,直接写死用最大速度50MHZ GPIO_InitStructure.GPIO_Pin = SX1278_CS_PIN_INDEX; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //设置为推挽输出 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_Init(SX1278_CS_PIN_GROUP, &GPIO_InitStructure); //初始化GPIO //SPI的初始化 RCC_APB2PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);//SPI时钟使能 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //设置为推挽输出 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Pin = SX1278_SCK_PIN_INDEX|SX1278_MISO_PIN_INDEX|SX1278_MOSI_PIN_INDEX; GPIO_Init(SX1278_SCK_PIN_GROUP, &GPIO_InitStructure); //初始化GPIO //配置SPI SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构 SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //设置时钟极性(串行同步时钟的空闲状态为高电平还是低电平) SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //设置相位(串行同步时钟的第几个跳变沿(上升或下降)数据被采样) SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:设置为软件控制(SSI控制) SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; //定义波特率预分频的值:波特率预分频值为256(256是最低,可以设置完成之后调整速度,如果速度过快导致通信失败再调小) SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式(CRC校验相关) SPI_Init(SPI1,&SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器 SPI_Cmd(SPI1,ENABLE); //使能SPI外设 } DioIrqHandler **g_irqHandlers; //初始化DIO(上升沿)中断,将 DIO0~5 的GPIO中断函数调用 irqHandlers[0]~irqHandlers[5] void SX1276IoIrqInit( DioIrqHandler **irqHandlers ) { EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; g_irqHandlers=irqHandlers; //初始化DIO0 // 使能外部IO时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz,这里不用传参,直接写死用最大速度50MHZ GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN; GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN; GPIO_InitStructure.GPIO_Pin = SX1278_DIO0_PIN_INDEX; GPIO_Init(SX1278_DIO0_PIN_GROUP, &GPIO_InitStructure); //初始化GPIO //配置中断 SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOG,EXTI_PinSource6);//设置映射线关系(这里的 GPIO_PortSourceGPIOX 刚好是0-5,所以直接用pinName/16表示,GPIO_PinSourceXX刚好是0-15,所以用pinName%16表示了) EXTI_InitStructure.EXTI_Line=EXTI_Line6; //中断线u8_pinNum EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//外部中断 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//上升降沿触发 EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能中断 EXTI_Init(&EXTI_InitStructure);//配置中断 //配置中断优先级 NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //外部中断XX //stm32f103c8例子中这个优先级对应抢占优先级2子优先级3 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02; //抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; //子优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断 NVIC_Init(&NVIC_InitStructure); //配置优先级 EXTI_ClearITPendingBit(EXTI_Line6);//清除中断标志位 } #if 0 //外部中断线0中断处理函数,这里需要回调对应的函数 void EXTI0_IRQHandler(void){ g_irqHandlers[0](); EXTI_ClearITPendingBit(EXTI_Line0);//清除中断标志位 } //外部中断线1中断处理函数,这里需要回调对应的函数 void EXTI1_IRQHandler(void){ g_irqHandlers[1](); EXTI_ClearITPendingBit(EXTI_Line1);//清除中断标志位 } #endif //处理DIO tx中断或者Rx中断数据 void EXTI6_IRQHandler(void) { g_irqHandlers[0](); EXTI_ClearITPendingBit(EXTI_Line6);//清除中断标志位 } //将SPI、DIO0~5和Rst脚的中断去初始化 void SX1276IoDeInit( void ) { //这里省略去初始化的功能了 } //判断频率是否合法 //如果不限制频率可以直接return true bool SX1276CheckRfFrequency( uint32_t frequency ) { // Implement check. Currently all frequencies are supported return true; } /** * 硬复位 * 将rst引脚拉低1ms,然后将复位脚设置为无上下拉的输入模式 */ void SX1276Reset( void ) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //使能指定端口时钟(这里是为了方便ABC全开了) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz,这里不用传参,直接写死用最大速度50MHZ GPIO_InitStructure.GPIO_Pin = SX1278_RST_PIN_INDEX; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //设置为推挽输出 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_Init(SX1278_RST_PIN_GROUP, &GPIO_InitStructure); //初始化GPIO GPIO_ResetBits(SX1278_RST_PIN_GROUP,SX1278_RST_PIN_INDEX); //输出低电平 delay_ms(1); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN;//浮空输入 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL; GPIO_Init(SX1278_RST_PIN_GROUP, &GPIO_InitStructure); //初始化GPIO delay_ms(6); } /** * 设置SPI的片选脚的电平(低电平使能,高电平取消) * lev:true的时候高电平,false的时候低电平 */ void Sx1276SetNSS(bool lev ) { if(lev){ GPIO_SetBits(SX1278_CS_PIN_GROUP,SX1278_CS_PIN_INDEX); //输出高电平 }else{ GPIO_ResetBits(SX1278_CS_PIN_GROUP,SX1278_CS_PIN_INDEX); //输出低电平 } } /** * SPI读写函数,data是发送的数据,返回值是接收到的数据 */ uint8_t Sx1276SpiInOut(uint16_t data ) { //完成SPI的读写功能 uint16_t retry=0; while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){//检查指定的SPI标志位设置与否:发送缓存空标志位(缓冲区空了就可以拷贝数据了) if((retry++)>2000){ //超时了 return 0xff; } } SPI_I2S_SendData(SPI1, data); //通过外设SPIx发送一个数据 retry=0; while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){ //检查指定的SPI标志位设置与否:接受缓存非空标志位(非空了就表示接收数据完成了) if((retry++)>2000){ //超时了 return 0xff; } } return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据 }