1 つの記事で IIC プロトコルを徹底的に学ぶことができます
1. SPIの概要
SPIプロトコルは、モトローラ社が提案した通信プロトコル(Serial Peripheral Interface)、すなわち高速全二重通信バスであるSerial Peripheral Interfaceである。より高い通信速度が要求されるADC、LCDなどの機器とMCUの間で広く使用されています。ここでは、 IIC プロトコルを徹底的に学ぶために書いた別のブログと比較できます
。 1. 信号ライン: SPI には SCK、MOSI、MISO、CS ラインがあります (CLK、SDA のみの IIC とは異なります)。
2. アドレス指定モード: SPI は CS チップ選択信号を通じてスレーブ デバイスを選択します (IIC はアドレス指定を通じてスレーブ デバイスを見つけます)。
3. 通信速度: SPI 速度は高速 (最大 fPCLK/2) で、一般に高速デバイスに使用されます。相互通信(IICとは異なります)
2.SPI接続
2.1 1 つのマスターと 1 つのスレーブ
「1 マスター 1 スレーブ」SPI 相互接続モードでは、1 つの SPI マスター デバイスのみが 1 つの SPI スレーブ デバイスと通信します。この場合、マスターデバイスの SCK、MOSI、MISO とスレーブデバイスの SCK、MOSI、MISO を直接接続し、マスターデバイスの SS をハイレベルに設定し、マスターデバイスの SS をハイレベルに設定するだけで済みます。スレーブ デバイスをグランドに接続します (つまり、Ping を設定し、チップ選択が有効で、スレーブ デバイスを選択します)。
2.2 1 つのマスターと複数のスレーブ
「1 つのマスターと複数のスレーブ」SPI 相互接続モードでは、1 つの SPI マスター デバイスが複数の SPI スレーブ デバイスと通信できます。この場合、すべての SPI デバイス (マスターとスレーブを含む) はクロック ラインとデータ ライン、つまり SCK、MOSI、MISO 3 ラインを共有し、マスター側の複数の GPIO ピンを使用してデバイスから異なる SPI を選択します。
3. SPI通信処理
通信プロセスについて話す前に、極性と位相について話しましょう。その後のサンプリングプロセスは後でのみ理解できます。
3.1 CPOL (極性) と CPHA (位相)
CPHA (クロック位相) ビットは「0」にクリアされ、データは SCK クロックの奇数 (1 番目、3 番目、5 番目...) の遷移エッジでサンプリングされます。CPHA (クロック位相) ビットは「」に設定されます
。 1" であり、データは SCK クロックの偶数番号 (2 番目、4 番目、6 番目...) のジャンプ エッジ サンプリングでサンプリングされます。CPOL ビットが "0" の場合、アイドル時に SCK が 0 であることを意味します
。 CPOL ビットが「1」の場合、アイドル時に SCK が 1 であることを意味します。
したがって、CPOL は最初のエッジが立ち上がりエッジであるか立ち下がりエッジであるかを決定します。SCK idle が 0 の場合、最初のエッジは立ち上がりエッジです。アイドル時に SCK が 1 の場合、最初のエッジは立ち下がりエッジです。
したがって、一般に、CPHA と CPOL は、立ち上がりエッジでサンプリングするか立ち下がりエッジでサンプリングするかを決定します。
したがって、合計 4 つの組み合わせがあり、SPI に 4 つのモードがあることが決まります。一般的な表は次のとおりです。
3.2 SPI タイミング図
これはホストの通信シーケンスです。例としてSPI モード 0を取り上げます。NSS、SCK、および MOSI 信号はすべてホストによって制御されますが、MISO 信号は
スレーブによって生成され、ホストはこの信号ラインを通じてスレーブのデータを読み取ります。MOSI 信号と MISO 信号は
NSS が Low レベルの場合にのみ有効であり、MOSI 信号と MISO 信号は SCK の各クロック サイクルで 1 ビットのデータを送信します。
3.1 SPI スタート信号
NSS信号線がHighからLowに変化し、SPI通信の開始信号となります。NSS は各スレーブの専用信号線であり、スレーブは自身の NSS ライン上のスタート信号を検出すると、マスターに選択されたことを知り、マスターとの通信を開始します。
3.2 SPI 停止信号
NSS信号は、SPI通信の停止信号であるLowからHighに変化し、通信が終了しスレーブの選択状態が解除されたことを示します。
3.3 データの利用可能性
SPI は、MOSI および MISO 信号線を使用してデータを送信し、SCK 信号線を使用してデータ同期を行います。MOSI および MISO データ ラインは、SCK の各クロック サイクルで 1 ビットのデータを送信し、データの入力と出力は同時に実行されます。データ送信時、MSB ファーストか LSB ファーストかは厳密に規定されていませんが、2 台の SPI 通信デバイス間で同じプロトコルが使用されていることを確認する必要があり、MOSI と MISO のデータは SCK の立ち上がりエッジで変化し、その間に出力されます。 SCKの立ち下がりエッジがサンプリングされます。つまり、SCK の立ち下がりエッジで MOSI と MISO のデータが有効となり、ハイレベルの場合はデータ "1" を意味し、ローレベルの場合はデータ "0" を意味します。また、データが無効な場合もあり、MOSI と MISO は次のデータ表現の準備をします。各 SPI データ転送は 8 ビットまたは 16 ビット単位で行うことができ、転送ごとのユニット数は制限されません。
4. コード例
ここでは Flash との通信を例に挙げます。以下は初期化コードです。
void SPI_FLASH_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* 使能SPI时钟 */
RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE );
/* 使能SPI引脚相关的时钟
1.片选引脚 2.SCK时钟引脚 3.MISO引脚 4.MOSI引脚 */
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOA|
RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOA, ENABLE );
/* 配置SPI的 CS引脚,普通IO即可 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 配置SPI的 SCK引脚*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 配置SPI的 MISO引脚*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 配置SPI的 MOSI引脚*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 停止信号 FLASH: CS引脚高电平*/
GPIO_SetBits(GPIOA,GPIO_Pin_4);
/* SPI 模式配置 */
// FLASH芯片 支持SPI模式0及模式3,据此设置CPOL CPHA
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//全双工模式
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主机
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //8位
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_4; //速率4分频
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //高位先行
SPI_InitStructure.SPI_CRCPolynomial = 7; //数据校验 --一般不需要
SPI_Init(FLASH_SPIx , &SPI_InitStructure); //初始化结构体
/* 使能 SPI */
SPI_Cmd(SPI1 , ENABLE);
}