踏踏實實搞清 stm32 SPI匯流排 基礎和程式設計
SPI應用是相當的廣了,同步序列匯流排,同步同步當然需要時鐘訊號來統一了,這樣通訊雙方通訊時就比較默契沒那麼延遲(呆呆)了。應用於中低速場合。
學起來從哪些地方入手呢?如下:
SPI概念與特點 關鍵的時序接受 程式設計時重點 STM32內部的SPI使用(介紹、功能、中斷)
SPI概念與特點:不多說,序列,需要同步訊號 主從結構的 CS(片選) SCK SDI SDO
全雙工 一主控多從 8或16位資料通訊
其它特點:8個主模式波特率預分頻係數 fpcll/2
主模式和從模式下快速通行 並支援切換
程式設計MSB 或LSB在前
專用傳送和接受標誌可促發中斷
有SPI忙標誌位
支援硬體CRC校驗,傳送模式下crc值作為最後一個位元組被髮送,接受模式下最後一位元組自動CRC校驗
支援錯誤中斷標誌,支援DMA功能的1位元組傳送和接受緩衝器:產生髮送和接受請求。
SPI匯流排時序介紹:
看下下圖應該就會了
使用stm32 spi需要以下的步驟
1.管腳因為複用的,故先配置好管腳、並開啟spi時鐘
2.設定spi的工作模式
通過 SPI1_CR1 來設定,設定SPI1主機模式,設定資料格式8位,然後通過 CPOL 和 CPHA 位來設定 SCK時鐘極性及取樣方式。並設定 SPI1 的時鐘頻率(最大18Mhz),以及資料的格式(MSB 在前還是 LSB在前)。
3.使能SPI.
SPI韌體庫函式
下面是初始化,必須得結構體原型
typedef struct
{
uint16_t SPI_Direction;//設定方向 (2線全雙工、2線只接受、一線傳送、一線接受)
uint16_tSPI_Mode; //模式 (從或主裝置)
uint16_t SPI_DataSize; //寬度 (8或16位)
uint16_tSPI_CPOL; //時鐘極性 (低或高)
uint16_tSPI_CPHA; //時鐘相位 (第一個或第二個跳變沿)
uint16_tSPI_NSS; //片選方式 (硬體或軟體方式)
uint16_t SPI_BaudRatePrescaler; //波特率預分頻 (從2---256分頻)
uint16_tSPI_FirstBit; //最先發送的位 (最低位,還是最高位在先)
uint16_tSPI_CRCPolynomial; //設定crc多項式 (數字)如7
}SPI_InitTypeDef;
下面是例項,對SPI2進行的初始化
void SPI2_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//配置SPI2管腳
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 |GPIO_Pin_14| GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //複用推輓輸出
GPIO_Init(GPIOB, &GPIO_InitStructure);
//SPI2配置選項
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2 ,ENABLE);
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_16;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStructure);
//使能SPI2
SPI_Cmd(SPI2, ENABLE);
}
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
以上是,初始化的一些函式,發現韌體庫還有很多函式沒用上,下面就要談到應用了
STM32的SPI序列外圍匯流排介面,本程式,是將STM32的SPI配置為全雙工模式,且NSS使用的軟體模式。在使用SPI前,下面的這個過程我們必須理解,即STM32作為主機發送一個位元組資料時,必然能接收到一個數據,至於資料是否處理,由程式操作。
● 全雙工模式(BIDIMODE=0並且RXONLY=0)
─ 當寫入資料到SPI_DR暫存器(傳送緩衝器)後,傳輸開始;
─ 在傳送第一位資料的同時,資料被並行地從傳送緩衝器傳送到8位的移位暫存器中,
然後按順序被序列地移位送到MOSI引腳上;
─ 與此同時,在MISO引腳上接收到的資料,按順序被序列地移位進入8位的移位暫存器
中,然後被並行地傳送到SPI_DR暫存器(接收緩衝器)中。
注意:也就是說,在主機模式下,傳送和接收是同時進行的,所以我們傳送了一個數據,也就能接收到一個數據。而STM32內部硬體是這個過程的支撐!
讀一個位元組,往裡面傳送0,外設就返回一個數據了,傳送的0外設不處理(需要先寫入命令生效)
#define SPI_ReadByte(SPIx) SPI_WriteByte(SPIx,0)
寫一個位元組就直接傳送相應的位元組,外設就返回一個數據了
u8 SPI_WriteByte(SPI_TypeDef* SPIx,u8byte);
//spi 寫一個位元組...................................................................
u8 SPI_WriteByte(SPI_TypeDef* SPIx,u8 Byte)
{
while((SPIx->SR&SPI_I2S_FLAG_TXE)==RESET); //等待發送區空
SPIx->DR=Byte; //傳送一個byte
while((SPIx->SR&SPI_I2S_FLAG_RXNE)==RESET);//等待接收完一個byte
returnSPIx->DR; //返回收到的資料
}
void M25P16_Write_Enable(void)
{
Select_Flash();
SPI_Flash_Write(WRITE_ENABLE);
NotSelect_Flash();
}
void M25P16_Read_Id(u8 * id)
{
u8 i;
Select_Flash();
SPI_Flash_Write(READ_ID);
for(i=0;i<20;i++)
{
id[i] = SPI_Flash_Read();
}
NotSelect_Flash();
}
void M25P16_Write_Status_Reg(u8 reg)
{
Select_Flash();
SPI_Flash_Write(WRITE_STAUS_REG);
SPI_Flash_Write(reg);
NotSelect_Flash();
}
void M25P16_Read_Data(u32 addr,u32 len,u8*buf)
{
u32 i;
Select_Flash();
SPI_Flash_Write(READ_DATA);
SPI_Flash_Write((addr>>16) & 0xff);
SPI_Flash_Write((addr>>8) & 0xff);
SPI_Flash_Write(addr & 0xff);
for(i=0;i<len;i++)
{
buf[i]=SPI_Flash_Read();
}
NotSelect_Flash();
}
//頁程式設計函式,頁程式設計前一定要進行頁擦除!!!
void M25P16_Page_Program(u32 addr,u16 len,u8 *buf)
{
u32 i;
M25P16_Write_Enable();
Select_Flash();
SPI_Flash_Write(PAGE_PROGRAM);
SPI_Flash_Write((addr>>16) & 0xff);
SPI_Flash_Write((addr>>8) & 0xff);
SPI_Flash_Write(addr & 0xff);
for(i=0;i<len;i++)
SPI_Flash_Write(buf[i]);
NotSelect_Flash();
while(M25P16_Read_Status_Reg()&0x01);
}
以上函式搞懂了,特別市紅色部分標註的為重點,對於spi也就基本清楚了,這些也算是最底層的函數了,提供基本的API供以後檔案系統或其它地方使用。
----------------------------------------------------------------------------------------------
最後補上一些檔案框架的說明
首先我們把最底層的SPI初始化寫上,函式如下:
可見有晶片自帶SPI模組 有給mp3晶片的,有給flash的,還有給無線網路的,還有給軟體模擬spi時序供給觸控式螢幕的控制器的,然後我們把這個.c檔案配套的.h檔案給下面具體的函式包含,就能正確的選取和使用了,當這些具體功能的函式寫好了後,對應得.h函式就又繼續給更高級別的應用層使用。
今天先就介紹下spi_flash模組了,等天補上其它3個模組的講解,畢竟現在是基礎哦。