新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > STM32的SPI問題。

STM32的SPI問題。

作者: 時間:2016-11-19 來源:網(wǎng)絡 收藏
問題描述:

之前一直使用的單片機是LPC2109,對其SPI很熟悉。基本就是原本拿來稍作修改就用。
由于某種原因需要使用STM32,然后設備的驅(qū)動是之前寫好的,只修改了一些硬件控制端口,由于硬件驅(qū)動使用到了SPI接口,而我是把SPI接口提供了出來,本來以為簡單修改SPI配置到對應單片機就行了。簡單看了STM3的SPI配置,輕車熟路改代碼,瞬間體現(xiàn)了良好的接口有哈。
編譯,生成目標文件,下載運行。
并沒有出現(xiàn)預想的結(jié)果。由于之前的設備驅(qū)動是能用的,所以排除設備驅(qū)動問題。
開始以為是由于對STM32端口配置的不熟悉導致的、看手冊,看別人代碼,沒發(fā)現(xiàn)問題。
debug........
問題定在SPI代碼上。查看配置,一樣啊。郁悶?。。?br />把自己配置考到別人能用的代碼中,可以使用。更加郁悶!?。?!
debug看寄存器。對比能運行代碼寄存器狀態(tài)。發(fā)現(xiàn)運行到一段代碼的時候寄存器不同
SPI_CR 0x0043
SPI_CR 0x2
看datasheet.OVR置位。問題應該就在這了。可是為什么呢??????

本文引用地址:http://m.butianyuan.cn/article/201611/318264.htm

搜此問題,此處出自這里

溢出錯誤(OVR)
 溢出錯誤表示連續(xù)傳輸多個數(shù)據(jù)時,后一個數(shù)據(jù)覆蓋了前一個數(shù)據(jù)而產(chǎn)生的錯誤。
 狀態(tài)標志SPIF表示的是數(shù)據(jù)傳輸正在進行中,它對數(shù)據(jù)的傳輸有較大的影響。主器件的SPIF有效由數(shù)據(jù)寄存器的空標志SPTE=0產(chǎn)生,而從器件的SPIF有效則只能由收到的第一個SCK的跳變產(chǎn)生,且又由于從器件的SPIF和主器件發(fā)出的SCK是異步的,因此從器件的傳輸標志SPIF從相對于主器件的傳輸標志SPIF主有一定的滯后。如圖4所示,在主器件連續(xù)發(fā)送兩個數(shù)據(jù)的時候?qū)⒂锌赡軐е聫钠骷膫鬏敇酥竞椭髌骷乱粋€數(shù)據(jù)的傳輸標志相重疊(圖4中虛線和陰影部分),第一個收到的數(shù)據(jù)必然被覆蓋,第二個數(shù)據(jù)的收/發(fā)也必然出錯,產(chǎn)生溢出錯誤

圖4溢出錯誤
  通過對從器件的波形分析發(fā)現(xiàn),counter=8后的第一個時鐘周期,數(shù)據(jù)最后一位的傳輸已經(jīng)完成。在數(shù)據(jù)已經(jīng)收/發(fā)完畢的情況下,counter=8狀態(tài)的長短對數(shù)據(jù)的正確性沒有影響,因此可以縮短counter=8的狀態(tài),以避免前一個SPIF和后一個SPIF相重疊。這樣,從硬件上避免了這一階段的溢出錯誤。
  但是,如果從器件工作速度不夠快或者軟件正在處理其他事情,在SPI接口接收到的數(shù)據(jù)尚未被讀取的情況下,又接收到一個新的數(shù)據(jù),溢出錯誤還是會發(fā)生的。此時,SPI接口保護前一個數(shù)據(jù)不被覆蓋,舍棄新收到的數(shù)據(jù),置溢出標志OVR=1;另外發(fā)出中斷信號(如果該中斷允許),通知從器件及時讀取數(shù)據(jù)。

23.4.7 錯誤標志位
I2S 單元有2個錯誤標志位。
下溢標志位(UDR)
在從發(fā)送模式下,如果數(shù)據(jù)傳輸?shù)牡谝粋€時鐘邊沿到達時,新的數(shù)據(jù)仍然沒有寫入SPI_DR寄存
器,該標志位會被置’1’ 。在寄存器SPI_I2SCFGR的I2SMOD 位置’1’ 后,該標志位才有效。如果
寄存器SPI_CR2的ERRIE位為’1’ ,就會產(chǎn)生中斷。
通過對寄存器SPI_SR進行讀操作來清除該標志位。
上溢標志位(OVR)
如果還沒有讀出前一個接收到的數(shù)據(jù)時,又接收到新的數(shù)據(jù),即產(chǎn)生上溢,該標志位置’1’ ,如
果寄存器SPI_CR2的ERRIE位為’1’ ,則產(chǎn)生中斷指示發(fā)生了錯誤。
這時,接收緩存的內(nèi)容,不會刷新為從發(fā)送設備送來的新數(shù)據(jù)。對寄存器SPI_DR的讀操作返回
最后一個正確接收到的數(shù)據(jù)。其他所有在上溢發(fā)生后由發(fā)送設備發(fā)出的16位數(shù)據(jù)都會丟失。
通過先讀寄存器SPI_SR再讀寄存器SPI_DR,來清除該標志位。

void SPI_write_byte(u8 data){S0SPDR = data;while ((S0SPSR & 0x80) == 0);}u8 SPI_read_byte(void){S0SPDR = 0xff;while((S0SPSR & 0x80) == 0);return (S0SPDR);}

整個工程修改的代碼如下(注釋代碼為不能正常工作的):

/**/// void SPI_write_byte(u8 data)// {// while (!(SPI1->SR & (1 << 1)));// SPI1->DR = data;// }// u8 SPI_read_byte(void)// {// while (!(SPI1->SR & 1));// return SPI1->DR;// }u8 spi_rw(u8 data){while (!(SPI1->SR & (1 << 1)));SPI1->DR = data;while (!(SPI1->SR & 1));return SPI1->DR;}/**/// SPI_write_byte(op  (address & ADDR_MASK));// SPI_write_byte(data);spi_rw(op  (address & ADDR_MASK));spi_rw(data);/**/// SPI_write_byte(RBM);spi_rw(RBM);// *data = SPI_read_byte();*data = spi_rw(0xff);/**/// SPI_write_byte(WBM);spi_rw(WBM);// SPI_write_byte(*data);spi_rw(*data);/**/

看完基本就明白問題所在了...

分析問題:

我是按照LPC的SPI配置的,而現(xiàn)在的是STM32,問題關鍵就在于STM32的接受緩沖空和發(fā)送緩沖非空的標志是不同的。而LPC單片機是相同的。仔細分析我寫的代碼,實際上每次執(zhí)行都缺少了對狀態(tài)的判斷,從而導致了數(shù)據(jù)的溢出。

解決問題:

修改代碼如下,問題解決。

u8 SPI_write_byte(u8 data){while (!(SPI1->SR & (1 << 1)));SPI1->DR = data;while (!(SPI1->SR & 1));return SPI1->DR;}u8 SPI_read_byte(void){while (!(SPI1->SR & (1 << 1)));SPI1->DR = 0xff;while (!(SPI1->SR & 1));return SPI1->DR;}


總結(jié):

問題出在思維的定勢,先入為主的思想導致了錯誤的思維,也體現(xiàn)了對問題的分析能力,以及編碼的隨意性。哎血的教訓啊。。。



關鍵詞: STM32SPI問

評論


技術專區(qū)

關閉