STM32F1筆記(十三)SPI

SPI:Serial Peripheral interface,串行外圍設備接口。

SPI接口一般使用4條線通信:

MISO主設備數據輸入,從設備數據輸出。

MOSI主設備數據輸出,從設備數據輸入。

SCLK時鐘信號,由主設備產生。

從圖中可以看出,主機和從機都有一個串行移位寄存器,主機通過向它的SPI串行寄存器寫入一個字節來發起一次傳輸。寄存器通過MOSI信號線將字節傳送給從機,從機也將自己的移位寄存器中的內容通過MISO信號線返回給主機。這樣,兩個移位寄存器中的內容就被交換。外設的寫操作和讀操作是同步完成的。如果只進行寫操作,主機只需忽略接收到的字節;反之,若主機要讀取從機的一個字節,就必須發送一個空字節來引發從機的傳輸,這個空字節通常稱為dummy_byte。

SPI總線四種工作方式是為了和不同外設進行數據交換,其輸出串行同步時鐘極性和相位可以進行配置。

時鐘極性CPOL=0,串行同步時鐘的空閑狀態為低電平;如果CPOL=1,串行同步時鐘的空閑狀態為高電平。

時鐘相位CPHA=0,在串行同步時鐘的第一個跳變沿(上升或下降)數據被采樣;如果CPHA=1,在串行同步時鐘的第二個跳變沿(上升或下降)數據被采樣。

SPI主從設備的時鐘相位和極性應該一致。

?

STM32F1的SPI時鐘最多可以到18Mhz。可用DMA。

SPI配置示例

void SPI2_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef SPI_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB, GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI2, &SPI_InitStructure);SPI_Cmd (SPI2, ENABLE);SPI2_ReadWriteByte(0xff); 
}  

SPI_Direction:選擇半雙工、全雙工。

SPI_Mode:選擇主機模式、從機模式。

SPI_DataSize:選擇8位還是16位幀格式傳輸。

SPI_CPOL:設置時鐘極性為高電平還是低電平。

SPI_CPHA:設置時鐘相位,選擇在時鐘的第幾個跳變沿數據被采樣。

SPI_NSS:設置NSS信號由硬件(NSS管腳)還是軟件控制。

SPI_BaudRatePrescaler:設置SPI波特率預分頻值。示例選擇256即本次SPI傳輸速度=36M/256=140.625KHz。

SPI_FirstBit:設置數據傳輸順序是MSB位在前還是LSB位在前。大部分應用是MSB在前。

SPI_CRCPolynomial:設置CRC校驗多項式,提高通信可靠性,大于1即可。

?

標準庫里SPI發送一個字節函數為

SPI_I2S_SendData(SPI2, data);

接受一個字節函數為

data =?SPI_I2S_ReceiveData(SPI2);

因此需要我們再封裝幾個函數,SPI寫任意字節,讀任意字節,讀寫任意字節。

?

SPI最常見的應用場景是讀寫FLASH。

正點原子戰艦板子上的FLASH為W25Q128。該款FLASH的容量為128Mb也就是16M字節。將16M的容量分為256個塊(Block),每個塊大小為64K字節,每個塊又分為16個扇區(Sector),每個扇區4K字節。W25Q128最小擦除單位為一個扇區,也就是每次必須擦除4K字節。這樣就需要開辟一個至少4K的緩存區,即單片機需要有4K以上的SRAM才能很好操作。W25Q128最大SPI時鐘能達80Mhz。

?

FLASH拿到手通常先測試能否到它的ID

從W25QXX datasheet ?里看到,主機給它發0x90,0x00,0x00,0x00,即可讀取16位ID

u16 W25QXX_ReadID(void)
{u16 Temp = 0;W25QXX_CS = 0;SPI2_ReadWriteByte(0x90);SPI2_ReadWriteByte(0x00);SPI2_ReadWriteByte(0x00);SPI2_ReadWriteByte(0x00);Temp |= SPI2_ReadWriteByte(0xFF) << 8;Temp |= SPI2_ReadWriteByte(0xFF);W25QXX_CS = 1;return Temp;
} 

這里要注意讀ID時MOSI發送的是0xFF,這個就是DUMMY_BYTE,大多DUMMY_BYTE是0xFF,少部分設備會有特殊要求

FLASH讀取數據,先發0x03和讀取數據的地址起點,然后即可讀取。

代碼如下

void W25QXX_Read(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)   
{ u16 i;   			W25QXX_CS = 0;SPI2_ReadWriteByte(0x03);SPI2_ReadWriteByte((u8) ((ReadAddr) >> 16));SPI2_ReadWriteByte((u8) ((ReadAddr) >> 8)); SPI2_ReadWriteByte((u8) ReadAddr);for(i = 0; i < NumByteToRead; i++){ pBuffer[i] = SPI2_ReadWriteByte(0XFF);}W25QXX_CS = 1;  				    	      
} 

?

W25Q128寫使能,要給flash寫數據,必須先寫使能。

從W25QXX datasheet ?里看到,只要發0x06即可寫使能。

void W25QXX_Write_Enable(void)   
{W25QXX_CS=0;SPI2_ReadWriteByte(0x06);W25QXX_CS=1;  	      
} 

?

寫使能后還不能立即往FLASH里面寫數據,需要將寫入數據的FLASH地址擦除。

void W25QXX_Erase_Sector(u32 Dst_Addr)   
{  	  Dst_Addr *= 4096;W25QXX_Write_Enable();W25QXX_Wait_Busy();W25QXX_CS = 0;SPI2_ReadWriteByte(0x20);SPI2_ReadWriteByte((u8) ((Dst_Addr) >> 16)); SPI2_ReadWriteByte((u8) ((Dst_Addr) >> 8));   SPI2_ReadWriteByte((u8) Dst_Addr);W25QXX_CS = 1;W25QXX_Wait_Busy();
} 

?

FLASH寫數據需要考慮跨扇區寫入的問題,因為FLASH只提供了往一個頁page寫數據的命令0x02。

void W25QXX_Write_Page(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{u16 i;W25QXX_Write_Enable();W25QXX_CS = 0;SPI2_ReadWriteByte(0x02);SPI2_ReadWriteByte((u8) ((WriteAddr) >> 16));SPI2_ReadWriteByte((u8) ((WriteAddr) >> 8));SPI2_ReadWriteByte((u8) WriteAddr);for(i = 0; i < NumByteToWrite; i++){SPI2_ReadWriteByte(pBuffer[i]);}W25QXX_CS = 1;W25QXX_Wait_Busy();
} void W25QXX_Write_NoCheck(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)   
{ 			 		 u16 pageremain;pageremain = 256 - WriteAddr % 256;if(NumByteToWrite <= pageremain){pageremain = NumByteToWrite;}while(1){W25QXX_Write_Page(pBuffer , WriteAddr, pageremain);if(NumByteToWrite == pageremain){    break;}else{pBuffer += pageremain;WriteAddr += pageremain;	NumByteToWrite -= pageremain;if(NumByteToWrite > 256){pageremain = 256;}else{pageremain = NumByteToWrite;}}};	    
} u8 W25QXX_BUFFER[4096];void W25QXX_Write(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)   
{u32 secpos;u16 secoff;u16 secremain;u16 i;u8 * W25QXX_BUF;W25QXX_BUF = W25QXX_BUFFER;	     secpos = WriteAddr / 4096;  secoff = WriteAddr % 4096;secremain = 4096 - secoff;  if(NumByteToWrite <= secremain){secremain = NumByteToWrite;}while(1) {	W25QXX_Read(W25QXX_BUF, secpos * 4096, 4096);for(i = 0; i < secremain; i++){if(W25QXX_BUF[secoff + i] != 0XFF){break;}}if(i < secremain){W25QXX_Erase_Sector(secpos);for(i = 0; i < secremain; i++){W25QXX_BUF[i + secoff] = pBuffer[i];	  }W25QXX_Write_NoCheck(W25QXX_BUF, secpos * 4096, 4096);}else{W25QXX_Write_NoCheck(pBuffer, WriteAddr, secremain);}if(NumByteToWrite == secremain){break;}else{secpos++;secoff = 0;pBuffer += secremain;WriteAddr += secremain;NumByteToWrite -= secremain;if(NumByteToWrite > 4096){secremain = 4096;}else{secremain = NumByteToWrite;}}	 }
}

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/374366.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/374366.shtml
英文地址,請注明出處:http://en.pswp.cn/news/374366.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

紅帽Openshift:入門–云中的Java EE6

現在有一段時間&#xff0c;我正在研究“云”。 研究它的功能&#xff0c;它可以做什么&#xff0c;為什么我們應該切換到“云”&#xff0c;進行討論&#xff0c;與RealDolmen的云專家maartenballiauw等人交談。 我已經在Google App Engine&#xff08;用于Java&#xff09;上…

python自定義函數參數_python自定義函數的參數之四種表現形式

&#xff08;1&#xff09;def a(x,y):print x,y 這是最常見的定義方式&#xff0c;調用該函數&#xff0c;a(1,2)則x取1&#xff0c;y取2&#xff0c;形參與實參相對應&#xff0c;如果a(1)或者a(1,2,3)則會報錯 &#xff08;2&#xff09;def a(x,y3):print x,y 提供了默認值…

osg添加紋理示例

轉自http://www.cnblogs.com/ylwn817/articles/1976851.html #include <osgDB/ReadFile>#include <osgViewer/Viewer> #include <osg/Node>#include <osg/Geode>#include <osg/Geometry>#include <osg/Group>#include <osg/Texture2D&g…

2.運算符

Swift 支持大部分標準 C 語言的運算符&#xff0c;分為一元、二元和三元運算符。 一元運算符對單一操作對象操作&#xff08;如 -a&#xff09;。一元運算符分前置運算符和后置運算符&#xff0c;前置運算符需緊跟在操作對象之前&#xff08;如 !b&#xff09;&#xff0c;后置…

C語言開發筆記(二)volatile

volatile常用于多線程共享資源和嵌入式軟件的中斷。 &#xff08;一&#xff09;嵌入式軟件中斷中volatile的應用 volatile unsigned short g_timer3_count 0;void TIM3_IRQHandler(void) {if (TIM_GetITStatus(TIM3, TIM_IT_Update) ! RESET){TIM_ClearITPendingBit(TIM3, T…

在WebLogic 12c上運行RichFaces 4.1.0.Final

您可能已經注意到&#xff0c;我只是喜歡JSF。 不僅是Mojarra的規范和參考實現&#xff0c;而且是市場上最具創意的組件套件。 這是我一直以來最喜歡的PrimeFaces &#xff0c;當然還有RichFaces 。 這就是為什么在這里找到“在xxx上運行xxx”帖子的原因:)今天是我的RichFaces和…

maven 私服的setting.xml配置

1 <?xml version"1.0" encoding"UTF-8"?>2 <settings xmlns"http://maven.apache.org/SETTINGS/1.0.0" 3 xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation"http://m…

python中的運算符_Python 中的神秘運算符

今天我們來講講 Python 里一個不為眾人所知的運算符。你可能會覺得疑惑&#xff1a;還有我不知道的運算符&#xff1f;別急著下結論&#xff0c;先往下看看再說。 在 Python3.5 中通過 PEP465https://www.python.org/dev/peps/pep-0465 加入了 運算符&#xff0c;也就是矩陣相乘…

input type:text輸入框點擊輸入,文字消失

<input name"Header1$txbsearch" type"text" value"18912345678" id"Header1_txbsearch" class"txbindex" οnfοcus"if (value 18912345678){value }" οnblur"if (value ){value18912345678}" sty…

C語言開發筆記(一)自動轉換和強制轉換

整型數據和實行數據之間可以進行運算&#xff0c;而且字符型數據可以和整型數據通用&#xff0c;所以整型、實型、字符型數據之間也是可以進行運算的&#xff0c;但在運算處理之前&#xff0c;不同類型的數據要事先轉換成同一種數據類型。轉換方法有兩種&#xff1a;自動轉換和…

Apache Shiro:簡化應用程序安全性

考慮到JAVA已有10多年的歷史了&#xff0c;對于需要在其應用程序中內置身份驗證和授權的應用程序開發人員來說&#xff0c;選擇的數量非常少。 在JAVA和J2EE中&#xff0c;JAAS規范是一種嘗試解決安全性的問題。 盡管JAAS用于身份驗證&#xff0c;但授權部分卻過于繁瑣而無法使…

Maven 導出依賴Jar,生成source.jar,javadoc.jar

下載最新版的Maven http://maven.apache.org/download.cgi 解壓到本地文件夾新建環境變量 MAVEN_HOME maven解壓目錄在path加入 %MAVEN_HOME%/bin;需要確保已經有Java環境變量 &#xff08;打開cmd java -version,javac -version兩個命令看正常不&#xff09;一、導出到默認目…

python提取包含特定字符串的行_python語言----txt中搜索特定字符串所在行

打開IDLE(python)&#xff0c;并新創建一個py文件&#xff0c;編輯內容為&#xff1a; 本示例演示如何在一個txt文件中搜索特定的字符串&#xff0c;并將其行顯示# 1. 打開文件# 2. 讀取行信息# 3. 判斷是否包含關鍵詞# 4. 不包含則循環操作&#xff0c;包含的話將行顯示并退出…

asp.net 分布式應用開發

Net Framework推出的許多新技術為上述任務的實現提供了相對簡單的解決方案。其中&#xff0c;基于SOAP的Web Service在處理分布式應用時具有比傳統的DCOM/CORBA明顯的優點&#xff0c;結合基于Web的ASP.NET頁面開發技術和SQL Server數據存儲技術&#xff08;或Xml文檔&#xff…

Spring Data JPA的持久層

1.概述 本文將重點介紹Spring 3.1&#xff0c;JPA和Spring Data的持久層的配置和實現。 有關使用基于Java的配置和項目的基本Maven pom設置Spring上下文的分步介紹&#xff0c;請參閱本文 。 持久性與春天 系列 &#xff1a; 第1部分 – 具有Spring 3.1和Hibernate的持久層 …

C語言開發筆記(三)自加和自減

看到一段代碼&#xff0c;被坑了。 #include <stdio.h>int main(void) {int a 7;printf("%d\n", a);printf("%d\n", a--);printf("%d\n", -a);printf("%d\n", -a--);printf("%d\n", a);return 0; } 結果為 -a的邏輯…

求解數獨回溯算法

實現的java代碼如下&#xff08;該算法只是將結果打印輸出&#xff0c;并沒有對原數組實現更改&#xff09;&#xff1a; //判斷a[i][j]取值val是否有效public boolean isValid(int[][] a, int i, int j, int val){//判斷是否跟同行沖突for(int j10;j1<9;j1){if(a[i][j1]val…

python語言屬于哪一種語言_Python與Java:你應該學習哪種語言,他們有什么區別?...

在企業招聘中&#xff0c; Python和Java經常是需求最大的編程語言。這兩種編程功能強大&#xff0c;靈活且面向對象的語言&#xff0c;通常在組織中和各種其他設置中使用。這可能會導致我們提出一個不可避免的問題&#xff1a;哪個更好&#xff1f; 這是一個復雜的問題&#xf…

關于手機端CSS Sprite圖標定位的一些領悟

今天在某個群里面閑逛&#xff0c;看見一個童鞋分享了一個攜程的移動端的頁面。地址這里我也分享下吧&#xff1a;http://m.ctrip.com/html5/在手機端我都很少用雪碧圖合并定位圖標&#xff0c;用的比較多就是用字體圖標來代替&#xff0c;有些圖標不多的時候就自己單個的切出來…

將Java向前推進? 一個定義。 一年回顧。

這篇文章是許多其他“年終”博客文章和評論之一。 但這并不是這樣。 我正在嘗試總結我在2011年所學到的有關Oracle和Java的知識&#xff0c;還試圖解釋“將Java向前推進”對我的意義以及我認為應該更好或更簡單地改變的東西。 感謝您全年關注我的博客&#xff0c;也感謝您在Twi…