1. SPI協(xié)議概述
關(guān)于SPI協(xié)議不做贅述,見詳解。
https://blog.csdn.net/XieWinter/article/details/94738361
2. STM32 SPI特性及架構(gòu)
STM32芯片也集成了專門用于SPI協(xié)議通訊的外設(shè)。
2.1 SPI外設(shè)簡(jiǎn)介
STM32的SPI外設(shè)可用作通訊的主機(jī)及從機(jī),支持最高的SCK時(shí)鐘頻率為fpclk/2 (STM32F429型號(hào)的芯片默認(rèn)fpclk1為90MHz,fpclk2為45MHz),完全支持SPI協(xié)議的4種模式,數(shù)據(jù)幀長(zhǎng)度可設(shè)置為8位或16位,可設(shè)置數(shù)據(jù)MSB先行或LSB先行。
雙線雙工模式: 通常使用
雙線單向模式:MOSI/MISO數(shù)據(jù)線向一個(gè)方向傳輸數(shù)據(jù),可以加快一倍的速度
單線模式:半雙工
● 基于三條線的全雙工同步傳輸
● 基于雙線的單工同步傳輸,其中一條可作為雙向數(shù)據(jù)線
● 8 位或 16 位傳輸幀格式選擇
● 主模式或從模式操作
● 多主模式功能
● 8 個(gè)主模式波特率預(yù)分頻器(最大值為 fPCLK/2)
● 從模式頻率(最大值為 fPCLK/2)
● 對(duì)于主模式和從模式都可實(shí)現(xiàn)更快的通信
● 對(duì)于主模式和從模式都可通過硬件或軟件進(jìn)行 NSS 管理:動(dòng)態(tài)切換主/從操作
● 可編程的時(shí)鐘極性和相位
● 可編程的數(shù)據(jù)順序,最先移位 MSB 或 LSB
● 可觸發(fā)中斷的專用發(fā)送和接收標(biāo)志
● SPI 總線忙狀態(tài)標(biāo)志
● SPI TI 模式
● 用于確??煽客ㄐ诺挠布?CRC 功能:
— 在發(fā)送模式下可將 CRC 值作為最后一個(gè)字節(jié)發(fā)送
— 根據(jù)收到的最后一個(gè)字節(jié)自動(dòng)進(jìn)行 CRC 錯(cuò)誤校驗(yàn)
● 可觸發(fā)中斷的主模式故障、上溢和 CRC 錯(cuò)誤標(biāo)志
● 具有 DMA 功能的 1 字節(jié)發(fā)送和接收緩沖器:發(fā)送和接收請(qǐng)求
2.2 STM32的SPI架構(gòu)剖析
2.2.1 通訊引腳
SPI的所有硬件架構(gòu)都從圖 中左側(cè)MOSI、MISO、SCK及NSS線展開的。
處于不同外設(shè)總線上的SPI,最高通信速率有所差異。其中SPI1、SPI4、SPI5、SPI6是APB2上的設(shè)備,最高通信速率達(dá)45Mbtis/s,SPI2、SPI3是APB1上的設(shè)備,最高通信速率為22.5Mbits/s。
2.2.2 時(shí)鐘控制邏輯
SCK線的時(shí)鐘信號(hào),由波特率發(fā)生器根據(jù)“控制寄存器CR1”中的BR[0:2]位控制,該位是對(duì)fpclk時(shí)鐘的分頻因子,對(duì)fpclk的分頻結(jié)果就是SCK引腳的輸出時(shí)鐘頻率。
2.2.3 數(shù)據(jù)控制邏輯
SPI的MOSI及MISO都連接到數(shù)據(jù)移位寄存器上,數(shù)據(jù)移位寄存器的數(shù)據(jù)來源及目標(biāo)接收、發(fā)送緩沖區(qū)以及MISO、MOSI線。
通過寫SPI的“數(shù)據(jù)寄存器DR”把數(shù)據(jù)填充到發(fā)送緩沖區(qū)中,通訊讀“數(shù)據(jù)寄存器DR”,可以獲取接收緩沖區(qū)中的內(nèi)容。
其中數(shù)據(jù)幀長(zhǎng)度,可以通過“控制寄存器CR1”的“DFF位”配置成8位及16位模式;配置“LSBFIRST位”可選擇MSB先行還是LSB先行。
3. 通信過程
主模式收發(fā)流程及事件說明如下:
(1) 控制NSS信號(hào)線,產(chǎn)生起始信號(hào)(圖中沒有畫出);
(2) 把要發(fā)送的數(shù)據(jù)寫入到“數(shù)據(jù)寄存器DR”中,該數(shù)據(jù)會(huì)被存儲(chǔ)到發(fā)送緩沖區(qū);
(3) 通訊開始,SCK時(shí)鐘開始運(yùn)行。MOSI把發(fā)送緩沖區(qū)中的數(shù)據(jù)一位一位地傳輸出去;MISO則把數(shù)據(jù)一位一位地存儲(chǔ)進(jìn)接收緩沖區(qū)中;
(4) 當(dāng)發(fā)送完一幀數(shù)據(jù)的時(shí)候,“狀態(tài)寄存器SR”中的“TXE標(biāo)志位”會(huì)被置1,表示傳輸完一幀,發(fā)送緩沖區(qū)已空;類似地,當(dāng)接收完一幀數(shù)據(jù)的時(shí)候,“RXNE標(biāo)志位”會(huì)被置1,表示傳輸完一幀,接收緩沖區(qū)非空;
(5) 等待到“TXE標(biāo)志位”為1時(shí),若還要繼續(xù)發(fā)送數(shù)據(jù),則再次往“數(shù)據(jù)寄存器DR”寫入數(shù)據(jù)即可;等待到“RXNE標(biāo)志位”為1時(shí),通過讀取“數(shù)據(jù)寄存器DR”可以獲取接收緩沖區(qū)中的內(nèi)容。
4. 硬件設(shè)計(jì)
FLASH芯片中還有WP和HOLD引腳。WP引腳可控制寫保護(hù)功能,當(dāng)該引腳為低電平時(shí),禁止寫入數(shù)據(jù)。我們直接接電源,不使用寫保護(hù)功能。HOLD引腳可用于暫停通訊,該引腳為低電平時(shí),通訊暫停,數(shù)據(jù)輸出引腳輸出高阻抗?fàn)顟B(tài),時(shí)鐘和數(shù)據(jù)輸入引腳無效 。詳情見芯片數(shù)據(jù)手冊(cè)
“dummy”指該處可為任意數(shù)據(jù),
5. 軟件設(shè)計(jì)
注意:根據(jù)SPI協(xié)議可知,時(shí)鐘是由主機(jī)提供的,因此,讀字節(jié)的時(shí)候,發(fā)送數(shù)據(jù)使主機(jī)產(chǎn)生時(shí)鐘,從而是主從的移位寄存器按位移動(dòng)數(shù)據(jù),從而使得從機(jī)的數(shù)據(jù),轉(zhuǎn)移到主機(jī)的數(shù)據(jù)寄存器,從而獲取從機(jī)的相應(yīng)數(shù)據(jù)。
#ifndef __SPI_FLASH_H__
#define __SPI_FLASH_H__
#include "stm32f4xx.h"
#include /* Private typedef -----------------------------------------------------------*/ //#define sFLASH_ID 0xEF3015 //W25X16 //#define sFLASH_ID 0xEF4015 //W25Q16 //#define sFLASH_ID 0XEF4017 //W25Q64 #define sFLASH_ID 0XEF4018 //W25Q128 //#define SPI_FLASH_PageSize 4096 #define SPI_FLASH_PageSize 256 #define SPI_FLASH_PerWritePageSize 256 /* Private define ------------------------------------------------------------*/ /*命令定義-開頭*******************************/ #define W25X_WriteEnable 0x06 #define W25X_WriteDisable 0x04 #define W25X_ReadStatusReg 0x05 #define W25X_WriteStatusReg 0x01 #define W25X_ReadData 0x03 #define W25X_FastReadData 0x0B #define W25X_FastReadDual 0x3B #define W25X_PageProgram 0x02 #define W25X_BlockErase 0xD8 #define W25X_SectorErase 0x20 #define W25X_ChipErase 0xC7 #define W25X_PowerDown 0xB9 #define W25X_ReleasePowerDown 0xAB #define W25X_DeviceID 0xAB #define W25X_ManufactDeviceID 0x90 #define W25X_JedecDeviceID 0x9F #define WIP_Flag 0x01 /* Write In Progress (WIP) flag */ #define Dummy_Byte 0xFF /*命令定義-結(jié)尾*******************************/ /*SPI接口定義-開頭****************************/ //SPI號(hào) #define FLASH_SPI SPI3 #define FLASH_SPI_CLK RCC_APB1Periph_SPI3 #define FLASH_SPI_CLK_INIT RCC_APB1PeriphClockCmd //SCK引腳 #define FLASH_SPI_SCK_PIN GPIO_Pin_3 #define FLASH_SPI_SCK_GPIO_PORT GPIOB #define FLASH_SPI_SCK_GPIO_CLK RCC_AHB1Periph_GPIOB #define FLASH_SPI_SCK_PINSOURCE GPIO_PinSource3 #define FLASH_SPI_SCK_AF GPIO_AF_SPI3 //MISO引腳 #define FLASH_SPI_MISO_PIN GPIO_Pin_4 #define FLASH_SPI_MISO_GPIO_PORT GPIOB #define FLASH_SPI_MISO_GPIO_CLK RCC_AHB1Periph_GPIOB #define FLASH_SPI_MISO_PINSOURCE GPIO_PinSource4 #define FLASH_SPI_MISO_AF GPIO_AF_SPI3 //MOSI引腳 #define FLASH_SPI_MOSI_PIN GPIO_Pin_5 #define FLASH_SPI_MOSI_GPIO_PORT GPIOB #define FLASH_SPI_MOSI_GPIO_CLK RCC_AHB1Periph_GPIOB #define FLASH_SPI_MOSI_PINSOURCE GPIO_PinSource5 #define FLASH_SPI_MOSI_AF GPIO_AF_SPI3 //CS(NSS)引腳 #define FLASH_CS_PIN GPIO_Pin_8 #define FLASH_CS_GPIO_PORT GPIOI #define FLASH_CS_GPIO_CLK RCC_AHB1Periph_GPIOI //控制CS(NSS)引腳輸出低電平 #define SPI_FLASH_CS_LOW() {FLASH_CS_GPIO_PORT->BSRRH=FLASH_CS_PIN;} //控制CS(NSS)引腳輸出高電平 #define SPI_FLASH_CS_HIGH() {FLASH_CS_GPIO_PORT->BSRRL=FLASH_CS_PIN;} /*SPI接口定義-結(jié)尾****************************/ /*等待超時(shí)時(shí)間*/ #define SPIT_FLAG_TIMEOUT ((uint32_t)0x1000) #define SPIT_LONG_TIMEOUT ((uint32_t)(10 * SPIT_FLAG_TIMEOUT)) /*信息輸出*/ #define FLASH_DEBUG_ON 0 #define FLASH_INFO(fmt,arg...) printf("<<-FLASH-INFO->> "fmt"n",##arg) #define FLASH_ERROR(fmt,arg...) printf("<<-FLASH-ERROR->> "fmt"n",##arg) #define FLASH_DEBUG(fmt,arg...) do{ if(FLASH_DEBUG_ON) printf("<<-FLASH-DEBUG->> [%d]"fmt"n",__LINE__, ##arg); }while(0) void SPI_FLASH_Init(void); void SPI_FLASH_SectorErase(uint32_t SectorAddr); void SPI_FLASH_BulkErase(void); void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite); void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite); void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead); uint32_t SPI_FLASH_ReadID(void); uint32_t SPI_FLASH_ReadDeviceID(void); void SPI_FLASH_StartReadSequence(uint32_t ReadAddr); void SPI_Flash_PowerDown(void); void SPI_Flash_WAKEUP(void); uint8_t SPI_FLASH_ReadByte(void); uint8_t SPI_FLASH_SendByte(uint8_t byte); uint16_t SPI_FLASH_SendHalfWord(uint16_t HalfWord); void SPI_FLASH_WriteEnable(void); void SPI_FLASH_WaitForWriteEnd(void); #endif /* __SPI_FLASH_H__ */ /** ****************************************************************************** * @file bsp_spi_flash.c * @version V1.0 * @date 2015-xx-xx * @brief spi flash 底層應(yīng)用函數(shù)bsp ****************************************************************************** */ #include "bsp_spi_flash.h" static __IO uint32_t SPITimeout = SPIT_LONG_TIMEOUT; static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode); /** * @brief SPI_FLASH初始化 * @param 無 * @retval 無 */ void SPI_FLASH_Init(void) { SPI_InitTypeDef SPI_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; /* 使能 FLASH_SPI 及GPIO 時(shí)鐘 */ /*!< SPI_FLASH_SPI_CS_GPIO, SPI_FLASH_SPI_MOSI_GPIO,
上一篇:STM32 SPI發(fā)送與接收用一個(gè)函數(shù)實(shí)現(xiàn)的問題
下一篇:關(guān)于STM32f103 SPI時(shí)鐘速度的問題
推薦閱讀
史海拾趣
設(shè)計(jì)資源 培訓(xùn) 開發(fā)板 精華推薦
- 神經(jīng)形態(tài)芯片可能是革新機(jī)器人實(shí)時(shí)電機(jī)控制的未來
- 從三個(gè)方面理解ARM嵌入式系統(tǒng)
- 自動(dòng)報(bào)警 基于MCU的家庭防盜報(bào)警系統(tǒng)的設(shè)計(jì)
- 存儲(chǔ)控制器及其訪問外設(shè)的原理
- 基于51系列單片機(jī)的智能照明控制系統(tǒng)設(shè)計(jì)方案
- 基于STM32的四旋翼飛行器控制系統(tǒng)
- 單片機(jī)應(yīng)用編程技巧解析
- 基于89C52的教室智能節(jié)能照明系統(tǒng)設(shè)計(jì)
- 一種新型的雨量光照傳感器的設(shè)計(jì)
- 陽光電源與葛洲壩裝備公司大力發(fā)展光伏、儲(chǔ)能、氫能產(chǎn)業(yè)
- 上半年凈利同比或降48%-62%,精研科技暴跌超14%
- 南京疫情復(fù)燃 臺(tái)積電南京廠運(yùn)營(yíng)沒受影響
- 納芯微推全新集成電流路徑霍爾傳感器:NSM201X系列
- 臺(tái)積電:今年全球晶圓制造產(chǎn)值將漲20%
- 華為Mate 40系列EMUI 11更新:優(yōu)化了系統(tǒng)穩(wěn)定性
- 三星Galaxy Buds Pro定價(jià)比Buds+高
- 一加33W充電器獲得認(rèn)證,暗示中端機(jī)將至
- AirPods Max“傷錢包” 這對(duì)耳機(jī)能“治病”?
- 上市半月賣2000多臺(tái) 格力5G手機(jī)一個(gè)認(rèn)真笑話?
- 社區(qū)問題“已解決”功能添加
- 歡迎大家自費(fèi)買板參加金鋼狼活動(dòng),我的已經(jīng)到貨啦
- #以拆會(huì)友??氨茹y磚的Vi Brick 拆解
- 一分錢逼到英雄漢,發(fā)帖清貨.................!!!!!!!!!!
- 招聘風(fēng)向:重女輕男 拒收研究生
- 垃圾問題:Rabbit是什么?
- 急!急!有中斷傳輸和塊傳輸,怎么寫固件?
- 一起哇:基于國(guó)產(chǎn)芯、便攜烙鐵系統(tǒng)IronOS(FreeRTOS)的智能烙鐵
- 怎么把代碼加入ardunio ide中
- RF技術(shù)與無線實(shí)時(shí)倉(cāng)儲(chǔ)管理系統(tǒng)