# SPI驱动 # 这一节我们详细讲解TI CC13x0/CC26x0 SDK开发平台 基于TI-RTOS的SPI驱动实现,主要了解SPI驱动的分层实现、驱动接口,以及结合开发板板载SPIFlash调试通过驱动。 ## 概述 ## SPI(Serial Perripheral Interface),串行外设接口,是Motorala公司推出的一种同步串行接口技术,它能够使MCU以全双工(数据能够同时进行双向传输)的同步串行方式与各种外围设备进行高速数据通信。它主要用在EEPROM、Flash、实时时钟(RTC)、数模转换器(ADC)、数字信号处理器(DSP)以及数字信号解码器之间,他只占用芯片的4根管脚来实现控制和数据传输,现在很多芯片上都集成了SPI技术。SPI有时也称为SSI(同步串行接口)。SPI的控制方式采用主-从模式(Master-Slave)。 SPI驱动程序能够驱动芯片与外围设备在SPI总线上进行数据的传输和接收。SPI驱动程序接口是典型的RTOS应用程序调用接口,它们被重定向到`SPI_FxnTalble`中的指针指定的特定驱动程序实现,增强了程序的移植性。 ## SPI驱动的分层实现 ## 虽然我们在应用层直接调用几个驱动接口就可以在SPI总线上发送数据,但是在驱动程序内部从接口函数到底层硬件操作是通过了多层封装的。如图1所示是SPI驱动程序的分层实现图: ![](http://www.leconiot.com/md_res/cc2640r2f/peripheral_driver/spi/images/qudongfencengtu.png) 图1 SPI驱动程序的分层实现 由图1我们可以看到,应用程序开发者只需要直接调用中间件层的驱动接口(例如:SPI_init,SPI_open等等)就可以实现SPI的驱动功能,这里的中间件层就是我们程序中的SPI.c和SPI.h所在层。这一层规范统一了应用程序的调用接口,也就是说对于TI不同类型的芯片平台它们在这一层给出的接口都是一样的。应用层都是调用相同的接口来实现SPI功能,这样做的好处在于增强了程序的可移植性,不管你的平台怎么换,我的应用程序都是不变的,因为驱动的接口相同。 中间件层往下就是业务逻辑层,从业务逻辑层开始往下根据不同的芯片平台其接口封装实现就不尽相同了。这里我们以CC26XX芯片平台为例,业务逻辑层就位于SPICC26XXDMA.c和SPICC26XXDMA.h所在的层。这里采用DMA的数据传输方式,所以这一层主要在操控DMA以进行数据传输以及调用驱动库中的一些函数实现相应功能。需要注意的是这一层封装的驱动接口函数被全部放在一个函数指针结构体中,如List1所示,中间件层不直接调用这些驱动接口,而是通过一个配置文件(CC2640R2_LAUNCHXL.c)将装有驱动接口指针的结构体指针注册到SPI_config中,如List2所示,这样中间件层通过调用SPI_config中的结构体指针就可以指定使用业务逻辑层的驱动接口了。 List1:业务逻辑层驱动接口指针结构体 ```C const SPI_FxnTable SPICC26XXDMA_fxnTable = { SPICC26XXDMA_close, SPICC26XXDMA_control, SPICC26XXDMA_init, SPICC26XXDMA_open, SPICC26XXDMA_transfer, SPICC26XXDMA_transferCancel }; ``` List2:SPI_config中的驱动接口结构体指针注册 ```C const SPI_Config SPI_config[CC2640R2_LAUNCHXL_SPICOUNT] = { { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC2640R2_LAUNCHXL_SPI0], .hwAttrs = &spiCC26XXDMAHWAttrs[CC2640R2_LAUNCHXL_SPI0] }, { .fxnTablePtr = &SPICC26XXDMA_fxnTable, .object = &spiCC26XXDMAObjects[CC2640R2_LAUNCHXL_SPI1], .hwAttrs = &spiCC26XXDMAHWAttrs[CC2640R2_LAUNCHXL_SPI1] }, }; ``` 业务逻辑层再往下就是驱动库层(driver library),业务逻辑层会直接调用这一层的接口函数来来进行相应逻辑操作的。驱动库层位于ssi.c和ssi.h所在的层,这一层就开始与硬件接触,进行相应寄存器操作来实现SPI驱动了。 ## SPI的驱动配置 ## 在上文中我们已经提到SPI的配置数组SPI_config[],它位于相应芯片平台的配置文件中,这里我们以CC26XX芯片平台为例,其配置文件为CC2640R2_LAUNCHXL.c。如List3所示,是CC2640R2_LAUNCHXL.c中关于SPI的配置代码段。 List3:UART的配置代码段 ```C /* * =============================== SPI DMA =============================== */ #include #include SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2640R2_LAUNCHXL_SPICOUNT]; const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2640R2_LAUNCHXL_SPICOUNT] = { { .baseAddr = SSI0_BASE, .intNum = INT_SSI0_COMB, .intPriority = ~0, .swiPriority = 0, .powerMngrId = PowerCC26XX_PERIPH_SSI0, .defaultTxBufValue = 0, .rxChannelBitMask = 1<Download->Download Active Application**如图4所示,将程序下载到调试板中。 7. 打开串口调试助手,连接上对应的端口,在[CC13X0/CC26X0 Evaluation Board](https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w5003-16843957259.1.4e9ffef7qpJP8Z&id=554782561045&scene=taobao_shop)上按下复位键,你可以看到Manufacturer/Device ID被打印到串口调试工具上如图10所示。 ![](http://www.leconiot.com/md_res/cc2640r2f/peripheral_driver/spi/images/chuankoudisplay.png) 8. 如图11所示,将逻辑分析仪的各个通道分别连接[CC13X0/CC26X0 Evaluation Board](https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w5003-16843957259.1.4e9ffef7qpJP8Z&id=554782561045&scene=taobao_shop)上对应的SPI四个端口**SS/CS**(DIO20)、**SCK**(DIO10)、**SDO/MOSI**(DIO9)、**SDI/MISO**(DIO8),对于具体是哪几个IO口,你也可以在文档[CC13X0CC26X0EvaluationBoard](http://docs.leconiot.com/doku.php?id=cc2640r2f:leconiot:cc13x0_cc26x0_evaluation_board:cc13x0_cc26x0_evaluation_board)中查看。 ![](http://www.leconiot.com/md_res/cc2640r2f/peripheral_driver/spi/images/logicAnalyzerlink.jpg) 9. 打开逻辑分析仪(Saleae Logic 1.1.15),首先配置好SPI接口,这在软件右侧**Analyzers**下的SPI选项下配置,如图12所示。 ![](http://www.leconiot.com/md_res/cc2640r2f/peripheral_driver/spi/images/editlogicanlyzer.png) 10. 选择之后你可以看到如图13所示的配置界面,将各个端口对应的通道配置好,点击**Save**保存。 ![](http://www.leconiot.com/md_res/cc2640r2f/peripheral_driver/spi/images/edititem.png) 11. 点击界面上方的**Start**按钮如图14所示,会弹出如图15所示的界面 ![](http://www.leconiot.com/md_res/cc2640r2f/peripheral_driver/spi/images/logicanlyzerstart.png) ![](http://www.leconiot.com/md_res/cc2640r2f/peripheral_driver/spi/images/startgetdata.png) 12. 在[CC13X0/CC26X0 Evaluation Board](https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w5003-16843957259.1.4e9ffef7qpJP8Z&id=554782561045&scene=taobao_shop)上按下复位键,点击图15所示界面的**stop**按钮。 13. 这样我们就可以看到我们向Flash输入数据,读出数据的时序图,如图16所示。我们可以看到,我们输入的指令与我们程序是完全符合的,读出Manufacturer/Device ID与我们串口打印出来的是完全符合的。 ![](http://www.leconiot.com/md_res/cc2640r2f/peripheral_driver/spi/images/logicanlyzer.png) ## 加入我们 ## 文章所有代码、工具、文档开源。加入我们[**QQ群 591679055**](http://shang.qq.com/wpa/qunwpa?idkey=d94f12d37c3b37892af4b757c6dc34bea140f3f3128a8d68e556a3d728148e85)获取更多支持,共同研究CC2640R2F&BLE5.0。

CC2640R2F&BLE5.0-乐控畅联 © Copyright 2017, 成都乐控畅联科技有限公司.