历史上的今天
返回首页

历史上的今天

今天是:2025年01月23日(星期四)

正在发生

2020年01月23日 | MSP430 SPI总线详解

2020-01-23 来源:eefocus

SPI总线系统是一种同步串行外设接口;是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。 许多的芯片都用这种协议通信:EEPROM、Flash、实时时钟、AD转换器、数字信号处理器等:MSP430的USART模块不仅能够实现异步模式(见:MSP430程序库<二>UART异步串口),而且支持同步串行通信(即SPI模式);其SPI支持3线、4线操作,支持主机模式和从机模式,字符长度可以7位或8位等。由于要用AD7708芯片完成AD采样,AD7708是通过SPI与其它设备通信的;本程序比较简化,只完成了主机模式的初始化。


硬件介绍:

SPI:SPI是Motorola首先在其MC68HCXX系列处理器上定义的,它是一种同步的高速串行通信协议,有关SPI协议的详细内容,参考:SPI_互动百科。


MSP430对SPI的支持:当msp430USART模块控制器UxCTL的位SYNC置位时,USART模块工作于同步模式,对于149即工作于SPI模式,若是169,USART0可以支持I2C,可以通过另一控制位I2C控制,I2C位0则工作于SPI。在SPI模式下,允许单片机以确定的速率发送和接收7位或8位数据。


同步通信与异步通信类似;同步通信和异步通信寄存器资源一致,具体寄存器的不同位之间的功能存在差异;具体寄存器内容参见TI提供的用户指南。


USART模块的SPI操作可以是3线和4线,其信号如下: 

SIMO:从进主出,主机模式下,数据输出;从机模式下,数据输入。 

SOMI:从出主进,主机模式下,数据输入;从机模式下,数据输出。 

UCLK:USART SPI模式时钟,信号有主机输出,从机输入。 

STE:从机模式发送接收允许控制脚,用于4线模式,控制多主从系统中多个从机,避免发生冲突。具体方式如下(图截自 用户指南):

image

四线主机模式:STE为高电平,SIMO和UCLK操作正常;STE为低电平,SIMO和UCLK被置为输入方向,主机控制权让出。 

四线从机模式:STE为高电平,从机的发送和接收无效,且把SOMI置为输入方向;STE为低电平,发送接收正常,SOMI也为正常输出。


USART模块串行时钟极性和相位设置:


USART的时钟UCLK的极性和相位由位于UxTCTL寄存器的CKPH和CKPL位控制,具体如下图:在程序中,我分别称之为,时钟模式0、时钟模式1、时钟模式2、时钟模式3。

image

USART的波特率产生,SPI不同于异步通信:异步通信由UxBR1UxBR0UxMCTL三个寄存器控制,以产生标准频率;而同步模式,主从设备用同一个时钟,不再需要产生标准时钟,故而不再用UxMCTL寄存器,设其值为0.


其他的,与异步通信基本一致,这里不再细说。具体参考用户指南。


程序实现:

程序和异步通信方式类似:首先是初始化函数,然后是读取数据、写入数据函数。此程序采用和我之前的UART程序库类似的结构,写入数据后进入低功耗等待中断,判断标志位进行写入数据和读取数据。


这里函数只实现430的主机模式,如需从机模式可以仿照我的程序,进行简化实现。


由于,我即将使用的SPI设备(AD7708)不是字符型设备,这里不再实现写入字符串函数,也不再移植printf和scanf函数,如若需要可以自己添加,printf和scanf的移植参考:MSP430程序库<四>printf和scanf函数移植


初始化函数:SpiMasterInit,实现主机模式的初始化工作,函数内容如下:


char SpiMasterInit(long baud,char dataBits,char mode,char clkMode)

{

    long int brclk;                 //波特率发生器时钟频率

    

    UxCTL |= SWRST;                 //初始

    

    //反馈选择位,为1,发送的数被自己接收,用于测试,正常使用时注释掉

    //UxCTL |= LISTEN;

    

    UxCTL |= SYNC + MM;             //SPI 主机模式

    

    //时钟源设置

    UxTCTL &=~ (SSEL0+SSEL1);       //清除之前的时钟设置

    if(baud<=16364)                 //

    {

      UxTCTL |= SSEL0;              //ACLK,降低功耗

      brclk = 32768;                //波特率发生器时钟频率=ACLK(32768)

    }

    else

    {

      UxTCTL |= SSEL1;              //SMCLK,保证速度

      brclk = 1000000;              //波特率发生器时钟频率=SMCLK(1MHz)

    }

    

    //------------------------设置波特率-------------------------   

    if(baud < 300||baud > 115200)   //波特率超出范围

    {

        return 0;

    }

    //设置波特率寄存器

    int fen = brclk / baud;         //分频系数

    if(fen<2)return (0);            //分频系数必须大于2

    else

    {

        UxBR0 = fen / 256;

        UxBR1 = fen % 256;

    }

    

    //------------------------设置数据位-------------------------    

    switch(dataBits)

    {

        case 7:case'7': UxCTL &=~ CHAR; break;      //7位数据

        case 8:case'8': UxCTL |= CHAR;  break;      //8位数据

        default :       return(0);                  //参数错误

    } 

    //------------------------设置模式---------------------------    

    switch(mode)

    {

        case 3:case'3': UxTCTL |= STC;  USPI3ON;    break;  //三线模式

        case 4:case'4': UxTCTL &=~ STC; USPI4ON;    break;  //四线模式

        default :       return(0);                          //参数错误

    }

    

    //------------------------设置UCLK模式-----------------------  

    switch(clkMode)

    {

        case 0:case'0': UxTCTL &=~ CKPH; UxTCTL &=~ CKPL;   break;  //模式0

        case 1:case'1': UxTCTL &=~ CKPH; UxTCTL |= CKPL;    break;  //模式1

        case 2:case'2': UxTCTL |= CKPH;  UxTCTL &=~ CKPL;   break;  //模式2

        case 3:case'3': UxTCTL |= CKPH;  UxTCTL |= CKPL;    break;  //模式3

        default :       return(0);                                  //参数错误

    }

    

    UxME |= USPIEx;             //模块使能

    

    UCTL0 &= ~SWRST;            // Initialize USART state machine

    

    UxIE |= URXIEx + UTXIEx;    // Enable USART0 RX interrupt 

    

    return(1);                  //设置成功

}

程序注释已经比较详细,这里不再细说;如果要改为从机模式,把时钟设置和波特率设置去掉应该就可以了。


发送函数和接收函数:


void SpiWriteDat(char c)

    while (TxFlag==0) SpiLpm();  // 等待上一字节发完,并休眠

    TxFlag=0;                     //

    UxTXBUF=c;

}

 char SpiReadDat()

    while (RxFlag==0) SpiLpm(); // 收到一字节?

    RxFlag=0;

    return(UxRXBUF);

}

发送和接收函数和异步通信里面的几乎一样,如果标志位为0,则等待改变为1,然后写入或读出;标志位在中断函数里被更改;中断函数如下:


#pragma vector=USARTxRX_VECTOR

__interrupt void UartRx()

{

    RxFlag=1;

    __low_power_mode_off_on_exit();

}

 #pragma vector=USARTxTX_VECTOR

__interrupt void UartTx ()

{

    TxFlag=1;

    __low_power_mode_off_on_exit();

}

中断里面仅仅置标志位后,就退出低功耗;退出后即写入或者读取数据。


读取或写入函数调用的SpiLpm函数:


void SpiLpm()

{

    if(UxTCTL&SSEL0) LPM3;  //若以ACLK 作时钟,进入LPM3休眠(仅打开ACLK)

    else             LPM0;  //若以SMCLK作时钟,进入LPM0休眠(不关闭SMCLK)

}

根据不同情况进入低功耗,如果单片机其他地方不允许进入低功耗,可以更改这个函数。


程序部分就这么多了。需要的函数在头文件里面声明,方便使用。


使用示例:

程序使用方式和之前的程序库相同,加入c文件,包含h文件,调用初始化函数后即可掉用程序库中的函数。


#include "msp430x16x.h"   //430寄存器头文件

#include "Spi.h"         //串口通讯程序库头文件


void main()

{

    // Stop watchdog timer to prevent time out reset

    WDTCTL = WDTPW + WDTHOLD;

    

    ClkInit();

    // 主机模式,波特率25000,8位数据位,三线模式,时钟模式0(具体见spi.c)

    SpiMasterInit(25000,8,3,0);

    _EINT(); 

    

    

    while(1)                    //串口测试

    {

        SpiWriteDat(0X20);

        char a = SpiReadDat();

    }

}

这里只是一个简单的使用示例,详细的使用,将会在下一篇给出,下一篇:MSP430程序库<六>通过SPI操作AD7708;将会使用今天的程序库,完成SPI的通信部分。


注意事项:


SPI是全双工通信,每次写入(发送)8位/7位数据的同时,430的SPI主模块都会在发送后半个时钟周期读取采样的0/1信号,存入接收缓冲寄存器,所以,每次的写入,均有数据读取,但不一定是从设备发送回来的,这个地方在使用430主机模式的时候必须注意,很容易出错(我也是在调试AD7708的时候才注意到这个地方的);SPI的函数已经添加SpiWriteData函数,这个函数会在发送的同时返回发送完成半个时钟周期后的接收到的数据,方便使用;不建议使用前面的发送和读取函数,很容易出错;建议使用刚添加的这个函数,程序库已经更新,可以重新下载。函数SpiWriteData:


char SpiWriteData(char c)

{

    SpiWriteDat(c);

    return SpiReadDat();

}

发送后读取即可,程序比较简单。


新的示例程序:


void main()

{

    // Stop watchdog timer to prevent time out reset

    WDTCTL = WDTPW + WDTHOLD;

    

    ClkInit();

    // 主机模式,波特率25000,8位数据位,三线模式,时钟模式0(具体见spi.c)

    SpiMasterInit(25000,8,3,0);

    _EINT(); 

    

    

    while(1)                    //串口测试

    {

        SpiWriteData(0X20);     //只写入

        char a = SpiWriteData(0xff);    //只读取

    }

}


推荐阅读

史海拾趣

Dolphin Interconnect Solutions Asa公司的发展小趣事

Dolphin Interconnect Solutions ASA自创立之初,便以技术革新为核心驱动力。公司不断投入研发资源,开发出了基于PCI Express的I/O和clustering产品,这些产品在市场上取得了显著的成功。随着技术的不断进步,Dolphin又成功地将产品扩展到更广泛的领域,如云计算、大数据处理等,进一步巩固了其在电子行业的地位。

Hirose公司的发展小趣事

在全球化的背景下,Dolphin Interconnect Solutions ASA积极实施国际化战略。公司不仅在欧美等发达国家建立了完善的销售网络,还通过参加国际展会、举办技术研讨会等方式,提高了品牌知名度和市场影响力。同时,Dolphin还加强了与国际知名企业的合作,共同推动电子行业的发展。

Hama公司的发展小趣事

H&D Wireless始终将产品创新和客户服务放在首位。公司不断推出新的物联网解决方案,以满足不同行业客户的需求。同时,H&D Wireless还建立了完善的客户服务体系,为客户提供全方位的技术支持和解决方案咨询。这种以客户为中心的经营理念赢得了广大客户的信赖和支持,也为公司的持续发展奠定了坚实基础。

以上五个故事展示了H&D Wireless公司在电子行业中的发展历程和成就,体现了其在物联网领域的创新能力和市场竞争力。

Hewlett Packard Co公司的发展小趣事
合理布线以减少信号干扰和噪声影响,提高音质表现。
GSME Electronics公司的发展小趣事

随着公司业务的不断拓展和市场竞争的日益激烈,GSME Electronics开始实施国际化战略。公司积极参与国际市场竞争,加强与国外客户的合作与交流,不断提升产品的国际竞争力。同时,公司还注重品牌建设,通过提升产品质量和服务水平,树立了良好的品牌形象。如今,“桂微牌”产品已经在国内外市场上赢得了广泛的认可度和美誉度,为公司未来的发展奠定了坚实的基础。

AMRI Enterprise Co Ltd公司的发展小趣事

品质是AMRI Enterprise Co Ltd的生命线。公司始终坚持品质至上的原则,通过严格的质量管理体系和持续改进的工艺流程,确保产品的稳定性和可靠性。同时,AMRI还注重品牌建设,通过提升品牌形象和塑造企业文化,增强客户对公司的信任度和忠诚度。这些努力使得AMRI的产品在市场上赢得了良好的口碑和广泛的认可。

问答坊 | AI 解惑

到了新单位,接手一个新项目,让我认识到了开发板的重要性

从刚毕业时候买的单片机到FPGA再到ARM,可以说我每样都买了一块学习板,但一直以来都是拿它做为学习之用,根本没有用到实际工作中去,这次到了新单位,接手一个项目是对他们原来的一个产品进行性能和可靠性进行提高,原来的产品是用51做的,这次我 ...…

查看全部问答>

飞凌S3C2440开发板路由实验代码

PS:本文转自 飞凌嵌入式技术交流群 这个是由群里一些工程师朋友做的小实验,可以作为参考。 嵌入式Linux简单路由实验     本实验所用硬件平台为飞凌(www.witech.com.cn)TE2440V2型开发板;该开发板上有两个网卡芯片,分别为C ...…

查看全部问答>

如何选择直流输入电压?需要用到12v,6v,3.3v三档电压

整个模块有几个是12v供电的,有几个是6v的, 单片机和液晶屏是3.3v 6v的是一个小电机,12v是一个磁力锁 现在想选用4节7号电池通过升压到12v, 6v转3.3v的有没有啥dcdc的模块 这样设计是否合理,还有,有没有交流220v直接转成6v的变压器,就是 ...…

查看全部问答>

关于WINCE6.0 VS2005 “go to definition ”功能 无法定位相关内容

关于WINCE6.0 VS2005 “go to definition ”功能 无法定位相关内容 大家好!向大家请教一个问题: 我现在装了VS2005 打开mini2440的BSP包(缺省内核工程),可以编译内核通过。 我想用go to definition 功能跟踪一下程序,比如定位一个函数或 ...…

查看全部问答>

请教一个电路

    各位大大,我有一块GR47模块,想做一个最简单的外围电路,只要SIM卡槽和一些必要电路。用串口和PC连,可以发彩信。。。哪位可以告诉我这个电路可以怎么做啊?…

查看全部问答>

在手机上,如何实现自己的软件中嵌入摄像头功能,

请问大家-有没有从事过在自己的软件中嵌入摄像头功能,就是自己的软件能够同过手机的摄像头照相,并且存储,而不是用手机自带的照相机。 有这方面的书也可以,大家介绍下吧,急用。 …

查看全部问答>

大侠帮忙

现在小弟我手上有款ARM开发板、是周立功出的。型号是easyarm2104 但是所有相关的资料全丢了。有哪位大侠有的,能共享下吗?不胜感激。…

查看全部问答>

EVC3.0+PPC202程序编译出错,关于StdAfx.sbr

Compiling resources... Compiling... Error spawning clarm.exe Creating browse info file... BSCMAKE: error BK1506 : cannot open file \'.\\ARMRel\\StdAfx.sbr\': No such file or directory Error executing bscmake.exe. Main.exe - ...…

查看全部问答>

请教一个编译出错的问题

大家新年好! 我是在一个原工程的基础上做修改的,添加了一些库文件和两个源文件,然后编译时出现了问题:could not open source file \\"os\\\\osif.h\\",其实这个头文件好像是在库里面的,为什么会出现这样的问题啊? 望各位不吝赐教!先 ...…

查看全部问答>

个人觉得写得很好的关于TC35的文章

 自己在进行TC35调试过程中觉得这两篇文章对调试还是有很大的帮助的,分享给大家…

查看全部问答>