STM32的SPI問題。


問題描述

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

搜此問題,此處出自這里

溢出錯誤(OVR)
 溢出錯誤表示連續傳輸多個數據時,后一個數據覆蓋了前一個數據而產生的錯誤。
 狀態標志SPIF表示的是數據傳輸正在進行中,它對數據的傳輸有較大的影響。主器件的SPIF有效由數據寄存器的空標志SPTE=0產生,而從器件的SPIF有效則只能由收到的第一個SCK的跳變產生,且又由於從器件的SPIF和主器件發出的SCK是異步的,因此從器件的傳輸標志SPIF從相對於主器件的傳輸標志SPIF主有一定的滯后。如圖4所示,在主器件連續發送兩個數據的時候將有可能導致從器件的傳輸標志和主器件下一個數據的傳輸標志相重疊(圖4中虛線和陰影部分),第一個收到的數據必然被覆蓋,第二個數據的收/發也必然出錯,產生溢出錯誤

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

 

23.4.7 錯誤標志位
I2S 單元有2個錯誤標志位。
下溢標志位(UDR)
在從發送模式下,如果數據傳輸的第一個時鍾邊沿到達時,新的數據仍然沒有寫入SPI_DR寄存
器,該標志位會被置’1’ 。在寄存器SPI_I2SCFGR的I2SMOD 位置’1’ 后,該標志位才有效。如果
寄存器SPI_CR2的ERRIE位為’1’ ,就會產生中斷。
通過對寄存器SPI_SR進行讀操作來清除該標志位。
上溢標志位(OVR)
如果還沒有讀出前一個接收到的數據時,又接收到新的數據,即產生上溢,該標志位置’1’ ,如
果寄存器SPI_CR2的ERRIE位為’1’ ,則產生中斷指示發生了錯誤。
這時,接收緩存的內容,不會刷新為從發送設備送來的新數據。對寄存器SPI_DR的讀操作返回
最后一個正確接收到的數據。其他所有在上溢發生后由發送設備發出的16位數據都會丟失。
通過先讀寄存器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配置的,而現在的是STM32,問題關鍵就在於STM32的接受緩沖空和發送緩沖非空的標志是不同的。而LPC單片機是相同的。仔細分析我寫的代碼,實際上每次執行都缺少了對狀態的判斷,從而導致了數據的溢出。

解決問題:

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

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; }

 


總結:

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM