浅谈CC1101驱动在STM32F103的移植

电子说

1.2w人已加入

描述

  本文主要是关于CC1101的相关介绍,并着重对CC1101驱动在STM32F103的移植进行了详尽的阐述。

  浅谈CC1101驱动在STM32F103的移植

  首先明确:CC1101是通过SPI与MCU进行通信的。根据从TI官方上获得CC1101驱动,直接先移植SPI部分,STM32F103提供了SPI1和SPI2两条SPI总线,可自行选择,对于SPI的移植,直接参考STM32开发板上关于通过SPI操作Flash示例代码,对于SPI的配置与TI提供的驱动代码里的SPI配置保持一致。SPI移植完成之后,接上CC1101射频模块,测试SPI是否能正常通信,主要通过向CC1101任意可读可写寄存器写一个任意值,然后再读出该寄存器里的值,通过串口打印出该值,通过以上操作判断SPI是否正常通信,SPI移植是否成功。当然,这里使用到了串口,所以需要同时将串口的代码实现,同样参考串口实例。

  CC1101

  其次,当STM32与CC1101的SPI通信完成后,果断开始CC1101后续驱动的移植。移植过程中,所有变量名、函数名与TI提供的驱动里的保持一致,当然CC1101寄存器配置也保持移植。对于移植初期,我并没有太多的关心CC1101的时序问题,只关心怎么去移植,这也是自己的一个不好的习惯,所以初期移植的时候,对着TI提供的驱动代码,TI代码里有什么函数,我也移植什么函数;函数里有CS管脚的操作,也对应在操作在STM32下定义的CS管脚;TI里延时多长,我也跟着在STM32下延时相应的时间。整个驱动移植下来,关于CC1101的驱动函数也大多了然在心了。

  最后,TI驱动里提供的是轮询的方式收发数据,对于初期来说,首先需要实现CC1101的工作,编译调试移植到STM32上的CC1101驱动代码,看见数据从接收端串口打印出的那瞬间,心情真心不错基于STM32F103的CC1101驱动移植。

  当然,轮询的方式并不适合我在实际中应用,改用中断方式接收数据,且使用FIFO小于64BYTE,对于中断接收,做如下总结:

  方法一:配置寄存器IOCFGx.GDOx_CFG=0x06(可查看CC1101数据手册通用引脚部分),以下降沿触发中断。

  方法二:配置寄存器IOCFGx.GDOx_CFG=0x01,以上升降沿触发中断。

  对于中断的试用,具体可根据对IOCFGx.GDOx_CFG的配置实现。

  本以为,这样之后就完成了CC1101的驱动移植,最后才知道,自己菜得不行,移植的代码只是纯粹的数据收发,当导师问道有无CCA、CS检测等等,我就茫然了,恰好又是期末了,大牛导师最后自己去重新移植了有CCA检测机制的驱动(主要参考TI官方提供的SimpliciTI代码),心里真心难受基于STM32F103的CC1101驱动移植,好失败,后期只对CC1101驱动进行了维护和改进。

  关于在后期维护和改进中,主要解决两个问题:

  1.通信距离

  测试参考SimpliciTI移植的CC1101驱动,其通信距离只有20几米,能穿透一堵墙,无法满足我们的需求,通过增加发射功率PA值,通信距离也不太明显。查阅资料,通信距离与应用环境、通信速率、PA等有关,与是准备将它通信速率(TI提供的是空中速率为250K的),修改为10K的速率,开始以为纯粹配置一下MDMCFG3 为10K就行,但最终是必须配置channel filter bandwidth 、frequency deviation等,这些配置均建议通过TI提供的SmartRF Studio 软件进行配置。速率改变也必须注意CCA监测过程中RSSI可用等待时间,RSSI可参考其TI提供的DN505文档。最后,通过降低传输速率,将PA值设为10db,测试通信距离在空旷场地下可达到200多米,可穿透三堵墙,已经满足项目需要。但测试期间,修改后的10K速率驱动,经常CCA检测失败,虽然通过DN505文档修改了RSSI等待的时间,但依旧这样,最终此问题纠结了我3天,最后突发奇想地去修改了调制解调方式为2-FSK后,CCA检测正常运行,至今还是没明白为什么会这样。

  2.关于GDO0的问题

  由于项目中是定时发送数据,接收端采用GDO0以中断方式接收数据,但在测试中发现,终端正常运行不定时间后,中断无法产生,调试为发现FIFO溢出等,通过去TI论坛上查找,发现有类似问题,但没有彻底的解决方法,目前主要通过设置定时阈值,超过阈值未接收到数据,就判定为GDO0中断出现问题,便执行FIFO刷新操作,然后终端又能继续正常运行,

  CC1101与STM32的低功耗

  1.stm32低功耗

  (1)进入stop模式

  由于项目需要在睡眠时也保留RAM的数据,顾考虑采用stop模式以减少STM32 的功耗,进入stop的方法很简单,直接调用库函数中的 PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); 此处,我选择了关闭电压转换器以进一步降低功耗,使用指令WFI进入,关于STOP进入方式的选择,可参考前文提供的博客。

  (2)STM32的唤醒

  由于,应用中采用发送完数据变进入休眠,并定时唤醒发送,且STOP模式下RTC正常工作,所以在本应用中采用了RTC闹钟周期中断唤醒,对于RTC的使用即配置可如下:

  void RTC_Configuration(void)

  {

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

  EXTI_InitTypeDef EXTI_InitStructure;

  EXTI_ClearITPendingBit(EXTI_Line17);

  EXTI_InitStructure.EXTI_Line = EXTI_Line17;

  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;

  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;

  EXTI_InitStructure.EXTI_LineCmd = ENABLE;

  EXTI_Init(&EXTI_InitStructure);

  PWR_BackupAccessCmd(ENABLE);

  BKP_DeInit();

  #ifdef RCC_LSE

  RCC_LSEConfig(RCC_LSE_ON);

  while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)

  {

  }

  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

  #else

  RCC_LSICmd(ENABLE);

  while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)

  {

  }

  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);

  #endif

  RCC_RTCCLKCmd(ENABLE);

  RTC_WaitForSynchro();

  RTC_SetPrescaler(32767);

  RTC_WaitForLastTask();

  RTC_ITConfig(RTC_IT_ALR, ENABLE);

  RTC_WaitForLastTask();

  RTC_Alarm_Interrupt(DISABLE);

  }

  以上,主要注意RTC时钟的选择,选择RCC_LSE ,时间比较精确,但会产生相对长一点的唤醒时延选择;RCC_LSI,时间则不那么准确,且功耗要多一点,但产生的唤醒时延较小,具体可查阅STM32使用手册关于低功耗部分的介绍。

  2.CC1101低功耗

  (1)进入掉电模式

  CC1101进入IDEL状态 一》 使用掉电模式(SPWD)即可。

  (2)唤醒

  直接操作拉低CS管脚即可。

  3.调试低功耗

  前期调试,只分别测试了STM32和CC1101在休眠功能上的实现,即是否能进入休眠以及是否能够成功进行唤醒,未对实际功耗进行测试(由于硬件的特殊性)。

  后期第一次测试STM32+CC1101整体模块低功耗模式下功耗为4点几mA,顿时就无语了关于STM32低功耗+CC1101低功耗;然后果断挑断模块上的所有LED灯,再次测试,功耗直接降到1mA左右,此时虽然有所下降,但离手册上的几uA真不是一个档次的,但对于菜鸟的我此时根本不知道怎么继续减少功耗了,好吧,我只有去茫茫网络中寻找低功耗的蛛丝马迹了,果然在http://www.openedv.com/posts/list/18372.htm#116532里找到了希望,真心感谢博主的分享,于是赶紧把用到的SPI管脚以及串口管脚安装博主提供的修改,并关闭所有不用的PIN,但最终测试功耗依然未降低,这就纳闷了,为啥还是每降低呢关于STM32低功耗+CC1101低功耗,突然想起了不久前看过的STM32L系列低功耗的芯片,同时在有个低功耗经验师兄的提醒下,果断参考了其官方提供的超低功耗代码关于STM32低功耗+CC1101低功耗,并在自己的项目中进行如下操作:

  在每次进入休眠前:

  #关闭所有时钟以及外设(如本项目中用到的串口、SPI、timer)

  #将所有I/O口改为GPIO_Mode_AIN状态

  void DisableGPIO(void)

  {

  GPIO_InitTypeDef GPIO_InitStructure

  ;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOC\

  |RCC_APB2Periph_GPIOE|RCC_APB2Periph_AFIO, ENABLE);

  //Configure all GPIO port pins in Analog Input mode (floating input trigger OFF)

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_Init(GPIOB, &GPIO_InitStructure);

  GPIO_Init(GPIOC, &GPIO_InitStructure);

  GPIO_Init(GPIOD, &GPIO_InitStructure);

  GPIO_Init(GPIOE, &GPIO_InitStructure);

  //GPIOs Periph clock disable

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC

  |RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE, DISABLE);

  }

  在每次唤醒后:

  #开启休眠前所关闭的对应时钟以及外设

  #初始化使用到的GPIO口

  添加了如上的处理后,再次测试低功耗,终于让我看见了uA级别的功耗关于STM32低功耗+CC1101低功耗,但功耗最低时在40uA左右,与根据芯片手册提供的低功耗数据相比,还是有很大的距离,不过至此,通过软件进一步实现低功耗,我已经无法再想到其他的方法,外设该关的都已经关掉,功耗在40uA左右,目前能想到的就是硬件上功耗降降低,

  结语

  关于CC1101的相关介绍就到这了,如有不足之处欢迎指正。

相关阅读推荐:基于STM32驱动CC1101的程序分析

相关阅读推荐:基于STM32F103RB和CC1101的无线数传模块设计

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
评论(0)
发评论
zaojiyong 2023-07-31
0 回复 举报
您好 能分享一下代码吗?我使用轮询的方法调通了 但更改为中断的时候出现了问题 收起回复

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分