1串行外設接口概述
1.1基本概念
SPI(串行外設接口)是一種高速、全雙工、同步的串行通信協議。串行外設接口一般是需要4根線來進行通信(NSS、MISO、MOSI、SCK),但是如果打算實現單向通信(最少3根線),就可以利用這種機制實現一對多或者一對一的通信。
1.2引腳定義
SPI總線采用的環形結構,利用的是主從模式(主機---->從機)進行數據的傳輸,由于是同步通信,所以在主機發送數據的同時也會收到從機發送的數據。
如果主機不打算和從機進行數據的傳輸,應該讓NSS引腳在空閑狀態下處于高電平(表示不通信),如果打算和某個從機進行單獨通信的話,則需要把從機對應的NSS引腳拉低。
片選引腳之間是“互斥”的,同一時刻只能有一個片選引腳為低電平。
主設備和從設備都有片選引腳NSS/CS,通過片選引腳來實現主設備和多個從設備之間的通信,NSS片選引腳可以由軟件控制,也可以由硬件控制。
1.3工作模式
由于SPI外設是全雙工同步通信,所以時鐘信號就由SCK引腳來生成,SCK引腳只能由主設備控制,從設備是無法控制的,所以SCK引腳輸出的脈沖信號的極性和相位就需要進行配置。
時鐘相位CPHA:置1? 第二個邊沿采集? 置0? ?第一個邊沿采集
時鐘極性CPHL:置1 上升沿采樣? ? ? ? ? ?置0? 下降沿采樣
這兩位可以得到四種不同的組合,就被作為SPI總線的工作模式(模式0~模式3),到底要選擇哪種模式,主機的工作模式必須根據從設備的數據手冊的說明進行設置。
1.4 數據格式
主機與從機在通信的過程中傳輸的數據時以bit為單位(串行傳輸),所以數據格式就十分重要,主機的數據格式必須要根據從機的數據格式進行設置(MSB或者LSB)。
1.5通信速率:
由圖可知:SPI1掛載在APB2上,而APB1總線頻率42MHZ,APB2總線頻率84MHZ,BR寄存器用000模式下最多可以使用42MHZ頻率,SPI2和SPI3也可以達到21Mbps,但是一些外圍器件的通信速率最高也就是10Mbps左右,極少數可以超過10Mbps(W25Q128芯片)。
2SPI配置
2.1使用流程
可以參考stm32f4xx_spi.c的開頭注釋以及ST公司提供的代碼例程,根據代碼思路進行設計
===================================================================
##### How to use this driver #####
===================================================================
[..]
(#) Enable peripheral clock using the following functions?
? ? ? ?RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE) for SPI1
1打開SPI外設的時鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE) for SPI2
RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI3, ENABLE) for SPI3
RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI3, ENABLE) for SPI4
RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI3, ENABLE) for SPI5
RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI3, ENABLE) for SPI6.
(#) Enable SCK, MOSI, MISO and NSS GPIO clocks using RCC_AHB1PeriphClockCmd()
function.2打開GPIO的外設時鐘
In I2S mode, if an external clock source is used then the I2S?
CKIN pin GPIO clock should also be enabled.
(#) Peripherals alternate function:?
(++) Connect the pin to the desired peripherals' Alternate Function (AF)?
using GPIO_PinAFConfig() function④引腳功能復用
(++) Configure the desired pin in alternate function by:?
GPIO_InitStruct->GPIO_Mode = GPIO_Mode_AF配置復用模式
(++) Select the type, pull-up/pull-down and output speed via GPIO_PuPd,?
GPIO_OType and GPIO_Speed members? ③初始化GPIO
(++) Call GPIO_Init() function In I2S mode, if an external clock source is?
used then the I2S CKIN pin should be also configured in Alternate?
function Push-pull pull-up mode.?
? ? ? ? ⑤配置SPI外設參數
(#) Program the Polarity, Phase, First Data, Baud Rate Prescaler, Slave?
Management, Peripheral Mode and CRC Polynomial values using the SPI_Init()
function.
In I2S mode, program the Mode, Standard, Data Format, MCLK Output, Audio?
frequency and Polarity using I2S_Init() function. For I2S mode, make sure?
that either:
(++) I2S PLL is configured using the functions?
RCC_I2SCLKConfig(RCC_I2S2CLKSource_PLLI2S), RCC_PLLI2SCmd(ENABLE) and?
RCC_GetFlagStatus(RCC_FLAG_PLLI2SRDY); or?
(++) External clock source is configured using the function?
RCC_I2SCLKConfig(RCC_I2S2CLKSource_Ext) and after setting correctly?
the define constant I2S_EXTERNAL_CLOCK_VAL in the stm32f4xx_conf.h file.?
(#) Enable the NVIC and the corresponding interrupt using the function?
SPI_ITConfig() if you need to use interrupt mode. 這個不用
(#) When using the DMA mode 這個不用
(++) Configure the DMA using DMA_Init() function
(++) Active the needed channel Request using SPI_I2S_DMACmd() function
(#) Enable the SPI using the SPI_Cmd() function or enable the I2S using
I2S_Cmd().⑥使能SPI
2.2代碼展示
#include "stm32f4xx.h"
#include "stm32f4xx_spi.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
void SPI1_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
SPI_InitTypeDef SPI_InitStruct;
? ? // 1. 使能時鐘
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
? ? // 2. 配置GPIO(復用功能)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; // SCK, MISO, MOSI
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; ?// 復用模式
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // 推挽輸出
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStruct);
? ? // 映射GPIO到SPI功能
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); // SCK
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); // MISO
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1); // MOSI
? ? // 3. 配置片選引腳(PA4,普通GPIO輸出)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_SetBits(GPIOA, GPIO_Pin_4); // 默認拉高(不選中)
? ? // 4. 配置SPI參數
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // 全雙工
SPI_InitStruct.SPI_Mode = SPI_Mode_Master; ? ? ? ? ? ? ? ? ? ? // 主模式
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; ? ? ? ? ? ? ? ? // 8位數據
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; ? ? ? ? ? ? ? ? ? ? ? ?// CPOL=0
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; ? ? ? ? ? ? ? ? ? ? ?// CPHA=0(模式0)
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; ? ? ? ? ? ? ? ? ? ? ? ? // 軟件控制NSS
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; // 時鐘分頻(APB2=84MHz時,SPI時鐘=10.5MHz)
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; ? ? ? ? ? ? ? ?// MSB優先
SPI_InitStruct.SPI_CRCPolynomial = 7; ? ? ? ? ? ? ? ? ? ? ? ? ?// CRC多項式(默認值)
SPI_Init(SPI1, &SPI_InitStruct);
? ? // 5. 使能SPI
SPI_Cmd(SPI1, ENABLE);
}
3應用:Flash閃存
3.1基本概念
開發板中板載的主控芯片是STM32F407ZET6,主控芯片內部搭載512K的Flash閃存,但是用戶程序是需要下載到Flash閃存空間的,所以留給用戶的操作空間并不大,就為了用戶的數據存儲,可以使用外部串行Flash閃存芯片,開發板上板載的外部Flash芯片的型號是W25Q128,具體的特點如下圖:
3.2內存分布
高電壓生成器:實現FLASH掉電不丟失,擊穿之后上電仍然記住擊穿的狀態
3.3基本模式
W25Q128芯片支持兩種SPI模式(模式0和模式3),主機可以選擇這兩種模式的一種進行通信即可。