您好,欢迎访问三七文档
SPI协议2/32目录概述协议结构实现扩展遗留问题总结3/32概述内部通讯底层传输单位为byte全双工的物理层中低速的传输(40kbits/s)以帧的形式传输提供可靠性保证协议的目的将底层细节隐藏起来,使AP实现者仅关心所需传输的数据,而不需要关心组帧、可靠性等问题4/32协议栈结构最高层为应用层,为用户自定义的数据第二层为传输层,负责用户数据以帧为单位发送和接收的确认控制第三层为数据链路层,负责按照帧格式封装用户数据、发送、接收以及解析收到的数据第四层为物理层,负责通过底层的物理资源进行数据发送和接收DatalinklayerApplicationlayerTransferlayerPhysicallayer(SPIorSCI)5/32物理层SPI,同步串行传输MasterSlave结构最快波特率40Kbit/s(200us/byte)考虑到使用的大多数MCU没有硬件的接收FIFO,传输一个byte的时间不能太短以便减轻CPU负担传输方式:利用中断的方式进行连续传递,MASTER一直发送CLOCK,有数据时发送数据,没有数据时发送空闲字符物理层提供全双工的比特通道6/32Datalinklayer—概述帧格式转义字节帧的封装帧接收检错7/32DataLinklayer—帧格式IDLESOFLENDATASUMEOFIDLEIDLE0xFF,无意义的填充字节SOF0x7ELEN帧中DATA的字节数DATA用户的数据,其长度可以是1字节到255字节SUM所有DATA的累加和的低8位,用于检错。EOF0x4E8/32DataLinklayer—转义字节为简化处理,防止出现数据中出现SOF和EOF导致接收错位的情况,我们对数据进行如下处理:将LEN,DATA,SUM字段中所有出现的0x7E都换为0x7D+0x5E,将所有的0x7d都换为0x7D+0x5D经过转义处理以后的数据才是真正在物理层上传输的数据同样的,对于EOF,我们将0x4E换为0x7D+0x2E对于IDLE,我们将0x0FF换为0x7D+0xDF9/32DataLinklayer—封装功能将用户数据按照帧格式成帧并做转义处理输入:用户数据首地址和长度输出:成帧后的数据首地址和长度10/32DataLinklayer—接收功能当接收到一帧数据后,可以将接收到的数据去掉协议开销后进行解转义处理根据接收到的长度,checksum等信息对接收到的数据进行检错11/32Transferlayer—可靠传输Stop&wait(ARQ)GobackNSlectretransmit对应于大多数的可靠性协议,使用带重传的肯定确认(positiveacknowledgementwithretransmission),要求接收方对接收到的数据进行确认,发送方在收到确认前不会发送下一帧。发送方还在发出一帧后启动一个定时器,如果在设定的时限内没有收到确认,重发数据包。传输层的协议可以根据实际需求做确认重发或者不做确认或者仅做确认,也可将可靠性问题交给更高层来处理目前我们的协议仅做简单的半双工通讯,仅需做回传确认。12/32Transferlayer—ACKNAK为此我们定义两种确认帧对传输的可靠性进行控制–ACK帧–NAK帧–当收到的数据是正确的帧格式后,回送ACK包,如果收到的数据格式错误,回送NAK包SOF10x06SUMEOFSOF10x15SUMEOF13/32协议栈实现架构Userdataunit:bytetransmittingconfirmcontrolSPIISRDriverwriteoperationSPIISRDriverreadoperationframeconfirmingDecodeUserdataunit:byteSPIparameter:startaddressofdatalengthofdatatimeoutAPPTransferlayerSPIdriverPhysicallayerTimeoutreportWriteoperationReceivingaframeeventparameter:startaddressofdatatimeoutreturn:timeoutordatalengthSpecialbytetransferred(SOFEOFIDLE)transmittingconfirmcontrolDatalinkStartaddressofdatalengthofdataReturnErrorstatusorfillthedatabufferEncodeSpecialbytetransferred(SOFEOFIDLE)14/32协议栈实现架构可以看到,从实现层面上SPI通讯协议主要分为以下五个层次:1、APP:由用户自己组织用户自定义的数据格式。2、Transferlayer:负责以Frame为单位进行数据的传输和传输确认控制。3、Datalinklayer:负责用户数据的打包,转义处理,发送和接收4、spidriver:负责通过spi硬件的资源将数据发送和接收,并负责接收的帧定界。5、physicallayer:spi硬件实体,在物理实体上将数据发送出去。15/32实现—物理层&Driver由于SPI的发送必须依赖于主机发送CLOCK,为了实现全双工的通讯,主机必须不停的发送数据,如果主机没有数据需要发送,那么填充无意义的Idle字节发送ISR:对应于SPI,发送和接收共用同一个中断,对于发送功能,Master和Slave如果有数据需要发送的时候就发送数据,没有的话就发送idle接收ISR:接收ISR负责进行帧的定界,通过判断接收到的数据中的SOF和EOF判断一帧是否接收完毕,如果接收完毕后,发送相应消息给高层16/32实现—物理层&DriverTXISRFlowchartTXISRStartLength=0?NoSendIdleRTIyesSenddataLength--Length=0?NoSendevent17/32实现—物理层&DriverRXISRFlowchartRXISRStartRxFlag=1?yesNoRxdata=SOF?Rxflag=1RXlength=0yesRTIRxdata=EOF?SendeventRxflag=0yesNoSavedatalength++Lengthsize?NoYesResetbufferRxflag=0Rxdata=SOF?NoyesResetRxbufferRxflag=118/32实现—物理层&Driver维护一个发送指针和发送长度,定义如下:INT16UwSpiTxLength;INT8U*pSpiTxBuf;在SPI中断中,通过判断wSpiTxLength是否为零来决定是否发送pSpiTxBuf指向的内容。维护了一个接收buffer来保存收到的数据INT8UbSpiRxBuf[cSpiMaxRxSize];INT16UwSpiRxLength;19/32实现—物理层&Driver接口voidsSpiStartClock(void)//启动spiclockvoidsSpiInit(INTOSprio)//初始化spi优先级voidsSpiWrite(INT8U*pdata,INT16Ulength)//发送数据INT8U*sbGetSpiRxData(void)//获得接收首地址INT16UswGetSpiRxLength(void)//获得接收数据长度#definecSpiMaxRxSize//用户指定接收缓存大小#defineeSpiTxComp1//发送完毕的消息#defineeSpiRxComp2//接收一帧数据的消息20/32实现—DataLink发送:将高层的数据进行转义处理后进行封装,再通过Driver的write接口进行发送,发送完毕后可以通过eSpiTxComp消息获得信息接收,当接收ISR接收到完整的一帧数据后,通过消息eSpiRxComp通知本层,通过get接口获得数据指针和长度后进行解转义和检错处理21/32实现—Datalink发送转义处理:INT8UsTranslateData(INT8Udata,INT8U*pdes)将原始数据data进行转义处理后,摆放在pdes起始的ram中,并返回转义后的长度,返回值只可能是1或者2成帧功能:本层维护一个发送buffer存放成帧后的数据INT8UbSpiTxBuf[cSpiMaxTxSize];编码函数定义如下:voidsSpiEncodePackage(INT8U*pdata,INT8Ulength)pdata为用户数据的首地址,length为用户数据的长度,本函数将这些数据进行转义处理后保存在bSpiTxBuf中,打包后的数据长度保存在变量wEncodeLength中22/32实现—Datalink发送通过编码功能,可以将用户数据组帧,然后再调用driver提供的接口函数进行发送:sSpiEncodePackage(pdata,length);sSpiWrite(bSpiTxBuf,wEncodeLength);23/32实现—Datalink接收解转义功能INT8UsRecoverData(INT8U*psrc,INT8U*pdes)psrc为解转义的数据地址,pdes为解转义后保存数据的地址如果pdes指向的内容为转义字节,而且下一个存储位置的内容大于0xDF时,说明数据有错误,该错误不做处理,留给高层去检查。返回处理的长度(1或2)解码功能对接收到的数据做解转义处理,解析出帧格式,根据帧格式中的length字段和checksum字段检查数据的正确性。如果数据正确,那么将数据复制到用户的buffer中,并返回数据长度,如果数据不正确,那么返回出错信息INT16UsSpiDecodePackge(INT8U*psrc,INT16Ulength,INT8U*pdes)在收到一帧数据后,调用driver的get接口获得数据后调用解码函数进行解码操作24/32实现—Datalink接口voidsSpiSendPackage(INT8U*pdata,INT8Ulength)发送一帧数据,用户数据首地址为pdata,长度为length,该函数调用了sSpiEncodePackage函数进行编码,然后调用sSpiWrite进行发送INT16UsSpiReceivePackage(INT8U*pdata)接收一帧数据,数据存放在起始地址为pdata的buffer中。该函数隐藏了datalink层和driver的接口信息,其形式如下sSpiDecodePackge(sbGetSpiRxData,swGetSpiRxLength,pdata);返回值如下:#definecFrameErr0x1000//帧长2#definecDataErr0x2000//最后一个字符是转义字符#definecLengthErr0x3000//收到的数据长度和帧中的长度不一致#definecChkSumErr0x4000//checksum错如果接收正常,返回数据的长度25/32实现—Transferlayer发送由于在物理层提供了全双工的通讯支持,那么将一帧数据交给spidriver后,该数据一定能够发送完毕,因此不存在发送超时的问题,调用函数sSpiSendpackage即可。收到eSpiTxComp后,等待接收方的回复。这时可能由于接收方没有收到数据,或者接收方接收错误的消息认为帧格式无法正确解析(可能是cFrameErr,cDataErr)而导致没有回复。因此存在回复超时的问题。26/32实现—Transferlayer发送FlowchartStarttimerSenddataWaiteventeSendCompWaiteventTimeoutcounter++Cntt
本文标题:SPI协议
链接地址:https://www.777doc.com/doc-3048816 .html