STM32和CC2520的TinyOS移植与驱动分析

发布者:JoyfulSunflower最新更新时间:2012-12-11 来源: 电子设计工程 关键字:STM32  CC2520  TinyOS移植 手机看文章 扫描二维码
随时随地手机看文章
引言
    无线传感器网络(Wireless Sensor Network,WSN)是一种应用相关的网络。需要对某些操作系统进行移植。本文采用TinyOS作为软件平台,成功移植了Radio、Timer、USART、SPI和General I/O等5个底层模块。测试结果表明,移植的5个底层模块能够正常工作。

1 MCU和无线模块介绍
   
STM32系列按性能分成两个系列:STM32F103“增强型”系列和STM32F101“基本型”系列,时钟频率达到72 MHz,是同类产品中性能最高的产品。本项目采用芯片STM32F103RBT6。CC2520选用第二代ZigBee/IEEE 802.15.4无线电频率(RF)收发器。

2 TinyOS操作系统和NesC分析
2.1 NesC介绍
    NesC是专门为网络嵌入式系统设计的编程语言,是对C的扩展,它基于TinyOS的结构化概念和执行模型而设计。主要编程模式包括:事件驱动、弹性并发型和面向组件程序设计等。NesC编译器进行数据竞争检测(提高可靠性)、积极的函数内联(降低资源消耗)等整体程序分析,简化了应用程序的开发。
2.2 TinyOS分析
    TinyOS(Tiny Micro Threading Operating System)是由加州大学伯克利分校开发的开源的传感器网络操作系统,其本身是由NesC语言编写。TinyOS的组件模型体系结构如图1所示。上层组件对下层组件发命令,下层组件向上层组件发信号通知事件,最底层的硬件抽象组件直接和硬件打交道。

c.JPG


    TinyOS的硬件抽象层通常是3级抽象结构,称作HAA(Hardware Abstraction Architecture)。整个硬件抽象层分为硬件表示层(HPL)、硬件适配层(HAL)和硬件接口层(HIL)。
    硬件表示层(Hardware Presentation Layer,HPL)是对硬件平台的功能性描述,主要通过存储单元和I/O映射端口访问硬件和通过硬件中断来实现以下功能:能量管理、控制硬件、硬件中断开闭、提供硬件中断服务程序等。
    在HPL上的是硬件适配层(Hardware Adaptation Layer,HAL),该层是整个硬件抽象层的核心,利用HPL提供的原始接口建立硬件描述资源,并通过状态来反映硬件的使用情况以实现对硬件的仲裁控制,提高系统性能。
    硬件抽象层的最高层是硬件接口层(Hardware Interface Layer,HIL),该层把HAL层提供的接口转换成硬件独立的接口,隐藏了平台之间的差异,并向上层提供统一的硬件API接口。

3 基于STM32和CC2520平台的TinyOS实现
   
由上文所述,将TinyOS移植到STM32核处理器和CC2520上的关键问题是硬件抽象层组件的定制和编译器工具链的配置。基于TinyOS开源代码的约定,主要修改代码放置在/tos/chips/STM32和tos/platforms/STM32p103。
3. 1 修改芯片文件
   
每个芯片都通过多个接口或组件提供它所实现的功能,这些接口或组件组成芯片的驱动。将芯片的结构抽象文件放于tos/chips。如果芯片有子系统则建立子目录,如:tos/chips/STM32/timer。需要改写的TinyOS和MCU相关模块如下所述。
3.1.1 STM32核处理器
   
为了同其他外围设备的驱动分开,需要在MCU相关的文件中增加两个定义;原子操作的开始和结束,在头文件hardware.h中定义;低功耗工作模式,由组件MCUSleepC定义。具体可以参考其他MCU文件编写。
    TinyOS通过一些接口管理MCU的状态,决定MCU何时进入低功耗状态。MCUSleepC组件向上层提供McuSleep和McuPowerState接口。TinyOS调度器在原子操作中调用McuSleep.sleep(),保证在进入低功耗状态前处于开中断状态。在sleep状态,可以关闭一些高耗能的模块,比如:高频时钟、PLL等。[page]

3. 1.2 修改I/O、LED灯、Timer、USART、SPI组件
   
(1)通用I/O接口
    HIL层组件通过3个接口描述MCU可以控制的通用输入输出引脚。General I/O接口描述输入输出引脚被清零或置位状态、设置为输入或输出模式。GpioInterrupt接口描述单个引脚触发的中断,可以对每一个引脚分别配置为上升沿触发或者下降沿触发中断。GpioCapture接口描述捕获单个引脚发生的事件,可以对每一个引脚分别配置为上升沿触发或者下降沿触发。
    (2)LED灯
    TinyOS最多可独立支持平台上3个LED灯。TinyOS通过PlatformLedsC组件直接访问3个LED灯,LedC和LedP组件再通过装配PlatformLedsC组件,向上层组件提供Led接口,相当于General I/O接口的使用。在PlatformLedsC组件中,可以对每种开发板指定相应的LED引脚。
    (3)Timer
    MCU时钟通常有3种常见的功能:控制、时钟/计数器、触发。将与MCU时钟相关的文件放到chips/STM32/timer。时钟的通用功能通过一系列的接口定义实现:
    d.JPG
    (4)USART
    节点可以通过USART与PC通信,将与USART相关文件放于chips/STM32/uart。本文只通过HplSTM32UartNoDmaP组件的STM32Uart1C配件实现了简单的USART功能。串口的初始化包括:波特率、字长、奇偶校验位、流控制、打开串口时钟和配置串口发送接收引脚等。
    (5)SPI
    由于CC2520通过SPI接口和MCU通信,所以必须实现SPI接口。SPI的初始化包括:时钟信号的相位和极性、NSS模式、数据帧格式、主从模式等。
3.2 CC2520驱动
   
在tos/chips/cc2520中,定义与CC2520芯片相关的组件,这里面的组件直接对芯片进行操作。在tos/platforms/cc2520文件夹中定义CC2520和MCU交互的接口。CC2520通过SPI接口与STM32完成设置和收发数据两方面的任务。
    CC2520工作流程如下:应用程序中使用SplitControl接口,该接口最终连接到CCDriverLayerP上,在SoftwareInit.init中对CC2520使用的和MCU相连的引脚进行初始配置。
    首先,复位CC2520,并且关闭电压调整器,根据Datasheet,延时1100 μs,延时通过接口BusyWait。延时完成后,开启电压调整器,并延时200μs后使能CC2520。完成后,申请SPI资源,该资源接口连接在CC2520DriverLayerP上,资源申请允许后,在CC25 20DriverLayerP中捕获到SpiResource.granted事件,然后开始通过SPI接口初始化CC2520,调用startOscillator。之后,调用initRadio对CC2520的寄存器进行相应配置。
    而在接收模式时,CC2520收到物理帧的SFD字段后,会在SFD引脚输出高电平,直到接收完该帧。如果启用了地址识别,在地址识别后,SFD引脚立即转为输出低电平。FIFO和FIFOP引脚标识FIFO缓存区的状态。如果接收FIFO缓存区有数据,FIFO引脚输出高电平;如果接收FIFO缓冲区为空,FIFO引脚输出低电平。TinyOS无线模块组织架构图如图2所示。

e.JPG


3.3 修改平台文件
   
在tos/platforms下放置平台相关文件,将物理驱动相关的组件连接起来组成具体平台。创建一个平台需要完成5个部分:
    ①“.platform”文件告知编译系统驱动文件的位置,由一系列的包含路径和NesC的参数组成。ncc将“.platform”文件当作perl脚本读出,并将参数传递到NesC预编译器。
    ②平台导入程序PlatformP/PlatformC,通过调用两个初始化接口platformC.Init和MainC.softwarelnit来激活MCU、传感器和射频等硬件模块及相关软件。platformC.Init通常完成时钟校准和引脚设置,保证硬件在可操作状态。
    ③与硬件具体功能相关的头文件“hardware.h”和将芯片与平台结合的具体代码。“hardware.h”包含了其他硬件子系统的头文件,并被主文件“MainC.nc”所包含。
    ④修改链接脚本文件,仿照其他平台文件在tos/platforms文件夹下建立tos.x文件,设置rom和ram的起始地址和大小。设置中断向量表、代码段、数据段、非初始化数据段和其他段的放置位置。
    ⑤定义中断向量表,在tos/platforms/STM32-p103/vectors文件夹下新建STM32-vector.c文件,用于放置中断向量表,按照STM32提供的中断配置中断向量表,并初始化默认中断处理函数,实际应用中这些中断处理函数可以在其他文件中重定义。比如时钟中断处理函数在McuSleepC.nc中重定义。

[page]

3.4 修改编译工具链
3.4.1 配置交叉开发工具链
   
STM32支持的编译器有很多,比如:ARM—NONE—EABI—GCC、KEIL、IAR等。本文采用ARM—NONE—EABI—GCC编译器。NesC程序的编译主要分两步,首先调用ncc编译器把NesC预编译成C文件(即预编译过程);然后通过一个脚本程序,将经过NesC预编译生成的TinyOS应用程序转换成可以下载到开发板的hex格式文件;最后送入J—Flash ARM下载器下载到硬件。修改后的编译工具链如图3所示。

f.JPG


    下面对这个过程进行详细的介绍。
    第一步:源组件文件(.nc源文件)的分析和转换,在这个阶段调用TinyOS自带的编译器ncc,对.nc源文件进行文法、语法分析,检测共享数据缓冲区等。再根据各个组件和接口对其使用的函数和变量进行名字扩展,使其具有全局唯一性。最后把所有的函数和变量都整合到一个主函数main()中,并生成相应的app.c文件。此时生成的已经是普通的C语言程序。以上这个替换过程是由ncc的核心程序nescl.exe完成的。
    第二步:在生成app.c文件后,ncc调用arm—none—eabi—gcc的交叉编译器工具对该C文件进行编译、链接生成可执行文件main.exe,然后通过arm—none—eabi—objcopy工具转换成main.hex,以便最后下载到STM32平台上运行调试。
3.4.2 定制编译环境
   
为使编译系统能够寻找到编译平台,在工程主文件夹下增加环境定制文件“setup.sh”,定制工程目录、编译工具、解释工具等路径。在/support/make目录增加“STM32-p103.target”文件。定制STM32的MAKE系统。在make文件中指定用arm—none—eabi—gcc为编译器,arm-none-eabi-objcopy为输出格式转换器。
    以一个简单的应用程序radioCountToLeds为例,在STM32平台上编译的结果如图4所示。

a.JPG


    可以通过TinyOS自带的工具生成各个组件的连线关系,只需要在make命令后面添加docs选项。

4 测试
    TinyOS自带的radioCountToLeds测试程序,需用通用I/O接口、Timer、Leds、SPI和无线模块(CC2520)驱动等组件。为了查看USART模块驱动,也为了便于跟踪程序执行流程,在源程序中加入了串口输出代码,结果如图5所示。

b.JPG


    本实验通过一个节点每一秒定时广播数据包,定时器中断触发时发送一个16位的数据,并把此数加1。其他节点接收此数据,并根据接收数据的低3位是否为1来分别控制3个Led灯闪烁。通过观察节点上Led灯的有规律闪烁,能够证明各模块成功移植。

结语
   
本文简单介绍了NesC语言的特点和TinyOS系统架构,重点介绍了TinyOS的编译机制,并在此基础上详细说明了将TinyOS内核程序移植到以STM32核处理器和CC2520无线模块芯片为核心的开发板上的具体方法。通过测试发现,各个模块能够正常稳定工作。但无线模块协议栈还不够完善,功能还不全面,仍需要进一步的研究。

关键字:STM32  CC2520  TinyOS移植 引用地址:STM32和CC2520的TinyOS移植与驱动分析

上一篇:基于ARM的家用智能垃圾桶设计
下一篇:基于DM9000AE的S3C2440嵌入式系统的以太网接口设计

推荐阅读最新更新时间:2024-03-16 13:14

stm32库函数学习篇通用定时器输入捕获功能
实现功能:PA8随意延时驱动led灯闪烁,并且将PA8用杜邦线连接到PA7口,PA7是通用定时器TIM3的2通道,在TIM3_CH2触发中断程序中取反连接到PD2口的led灯,指示中断程序运行,并且每次进入中断后改变触发捕获的极性。实现两个led灯会交替闪烁。 先有必要了解stm32定时器的输入触发模块,如下图: 需要注意的是,一眼望去一个定时器似乎有8个通道,左边四个,右边四个,但其实左边和右边是共用相同的IO引脚,所以名称标注是一模一样。也就是说,每个通用定时器都只有四个独立通道,当某一通道作为了输入触发功能那就不能再作为输出匹配功能。这一点我们也可以从其他地方找到印证。比如TIM_ITConfig()函数中如下
[单片机]
<font color='red'>stm32</font>库函数学习篇通用定时器输入捕获功能
STM32——多通道ADC的DMA方式采集方法
前言: 最近在调试STM32F205芯片ADC多通道DMA方式采集数据,总结下STM32多通道ADC的DMA方式采集的使用方法。 硬件平台:STM32F205 软件平台:keil v5 函数库:标准库 多通道ADC的配置 #define Channel_Num 9 //ADC的通道数,本例使用9个通道 #define Sample_Num 10 //采样次数,本例使用平均滤波,采样10次取均值 u16 ADC_ConvertedValue ;//ADC采集数据的缓存 uint16_t ADC_Value ={0};//9个ADC通道的采样值 下面为ADC及DMA的详细配置函数。 void ADC_DMA
[单片机]
stm32 usart在DMA模式下只能发送一次
  问题描述:使用STM32 cube生成usart2 DMA direct mode(不使用FIFO,normal模式,STM32f407)配置代码,usart2可以使用阻塞方式发送,使用DMA发送则只能发送第一次,复位后还只能发送一次。   单步调试发现DMA方式下的发送在发送第一次之后,husart- State 标志变为 HAL_USART_STATE_BUSY就再也不变了。比较直接的解决思路就是在DMA发送中断中给这个标志修改为HAL_USART_STATE_READY,修改之后还是不好用(我认为是可以通过修改多个相关寄存器解决的,但是个人倾向于不深入了解其寄存器,而是用封装度更高的HAL系列函数)。   读stm32f
[单片机]
stm32专题二十一:LCD显示原理
显示器的基本参数: 1 像素 像素是组成图像的最基本单元要素,显示器的像素指它成像最小的点,即液晶原理中提到的一个显示单元。 2 分辨率 一些嵌入式设备的显示器常常以“行像素值 x 列像素值”表示屏幕的分辨率。如分辨率 800x480 表示该显示器的每一行有 800 个像素点,每一列有 480 个像素点,也可理解为有 800 列,480 行。 3 色彩深度 色彩深度指显示器的每个像素点能表示多少种颜色,一般用“位”(bit)来表示。如单色屏的每个像素点能表示亮或灭两种状态(即实际上能显示 2 种颜色),用 1 个数据位就可以表示像素点的所有状态,所以它的色彩深度为 1bit,其它常见的显示屏色深为16bit和 24bi
[单片机]
<font color='red'>stm32</font>专题二十一:LCD显示原理
一图搞懂单片机STM32的5个时钟源知识!
众所周知STM32有5个时钟源HSI、HSE、LSI、LSE、PLL,其实他只有四个,因为从上图中可以看到PLL都是由HSI或HSE提供的。 其中,高速时钟(HSE和HSI)提供给芯片主体的主时钟.低速时钟(LSE和LSI)只是提供给芯片中的RTC(实时时钟)及独立看门狗使用,图中可以看出高速时钟也可以提供给RTC。 内部时钟是在芯片内部RC振荡器产生的,起振较快,所以时钟在芯片刚上电的时候,默认使用内部高速时钟。而外部时钟信号是由外部的晶振输入的,在精度和稳定性上都有很大优势,所以上电之后我们再通过软件配置,转而采用外部时钟信号. 高速外部时钟(HSE):以外部晶振作时钟源,晶振频率可取范围为4~16MHz,我们
[单片机]
stm32时钟设置函数
这里涉及到一个很重要的寄存器,时钟配置寄存器:RCC_CFGR 1 #if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL) 2 /* #define SYSCLK_FREQ_HSE HSE_VALUE */ 3 #define SYSCLK_FREQ_24MHz 24000000 4 #else 5 /* #define SYSCLK_FREQ_HSE HSE_VALUE */ 6 /* #define SYSCLK_FREQ_24MHz 24000000 */ 7 /* #define SY
[单片机]
sw笨笨的STM32笔记之十:工作工作,PWM输出
a) 目的:基础PWM输出,以及中断配合应用。输出选用PB1,配置为TIM3_CH4,是目标板的LED6控制脚。 b) 对于简单的PWM输出应用,暂时无需考虑TIM1的高级功能之区别。 c) 初始化函数定义: void TIM_Configuration(void); //定义TIM初始化函数 d) 初始化函数调用: TIM_Configuration(); //TIM初始化函数调用 e) 初始化函数,不同于前面模块,TIM的初始化分为两部分 基本初始化和通道初始化: void TIM_Configuration(void)//TIM初始化函数 { TIM_TimeBaseI
[单片机]
STM32的端口复用和重映射
什么是端口复用? STM32有很多的内置外设,这些外设的外部引脚都是与GPIO复用的。也就是说,一个GPIO如果可以复用为内置外设的功能引脚,那么当这个GPIO作为内置外设使用的时候,就叫做复用。 例如: 串口1的发送接收引脚是PA9,PA10,当我们把PA9,PA10不用作GPIO,而用做复用功能串口1的发送接收引脚的时候,叫端口复用。 复用功能的配置: 以下端口复用配置过程以PA9,PA10配置为串口1为例GPIO端口时钟使能。 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); 复用外设时钟使能。比如你要将端口PA9,PA10复用为串口,所以要使能串口时钟
[单片机]
<font color='red'>STM32</font>的端口复用和重映射
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved