分享到plurk 分享到twitter 分享到facebook

版本 96e2520af216775e877ad7680b930767c7f01733

SPI

Overview

SPI 為資料傳輸協定,有著以下幾點特色:

.. benfit is what?

  • 同步式
  • 全雙工
    • 可以半雙工或單工
  • 主從式
    • dynamic change of master/ slave
    • 多個 master
  • 8 master baud rate prescalers
  • slave mode frequency
  • SPI TI / motorola mode
  • MSB-first or LSB-first
  • Hardware CRC
  • DMA capability .. BIDI mode / RXONLY (p. 801) .. I2S feature

Device overview

.. image:: /embedded/SPI/STM32F40x block diagram.png STM32F40x block diagram [#]_

.. [#] DS8626: ARM Cortex-M4 32b MCU+FPU, 210DMIPS, up to 1MB Flash/192+4KB RAM, USB OTG HS/FS, Ethernet, 17 TIMs, 3 ADCs, 15 comm. interfaces & camera <http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/DM00037051.pdf>_ p.18

  • 3 SPI
    • SPI1: 37.5 Mbits/s
    • SPI2 & SPI3: 21 Mbits/s

.. Datasheet: p.32

SPI functional description

general

.. 介紹 pin

.. image:: /embedded/SPI/SPI block diagram.png SPI block diagram [#]_

.. [#] STM32F405xx, STM32F407xx , STM32F415xx and ... <http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/REFERENCE_MANUAL/DM00031020.pdf>_ p.793

  • MISO: Master In / Slave Out data
  • MISO: Master Out / Slave In data
  • SCK: Serial Clock ( Master -> Slave )
  • NSS: (optional) select slave, low-driven

.. image:: /embedded/SPI/single master _ single slave application.png SPI single master/single slave application [#]_

.. [#] STM32F405xx, STM32F407xx , STM32F415xx and ... <http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/REFERENCE_MANUAL/DM00031020.pdf>_ p.794

.. baud rate ref menual p.834

.. Slave select(NSS) pin management ’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’

Clock phase and clock polarity ’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’

.. image:: /embedded/SPI/SPI Dota clock timing diagram.png Data clock timing diagram[#]_

.. [#] STM32F405xx, STM32F407xx , STM32F415xx and ... <http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/REFERENCE_MANUAL/DM00031020.pdf>_ p.796

SPI_PR1 中有兩個 bits CPOL 和 CPHA 控制取值的時間關係,

  • CPOL(clock polarity) 決定閒置時 clock 的電位,CPOL = 0 表閒置時為低電位。
  • CPHA(clock phase) 決定在 clock 的哪個 edge 取值, CPHA = 0 表示在第一個 edge (到不同電位時)取值。

Data format ’’’’’’’’’’’

  • LSB-first or MSB first
  • 一次傳送的資料量為 8-bit 或 16-bit

confiurataion in master mode

confiurataion in slave mode

half-duplex communication

  • BIDMODE 判斷是否為全雙工
  • RXONLY 判斷半雙工時為傳送端或接收端。

SPI 可以只做半雙工,在半雙工時,沒用到的另一隻 pin 可作為一般的 GPIO 使用。

.. RXONLY 在 BIDMODE 時有作用否?

.. data transmission and reception procedures —————————————— Start sequence in master mode - In full-duplex (BIDIMODE=0 and RXONLY=0):: begins when data are written into the SPI_DR register (Tx buffer) - In unidirectional receive-only mode (BIDIMODE=0 and RXONLY=1):: begins as soon as SPE=1 TODO: not finished

.. CRC calculation —————

Status flag

寫程式時必須要持續監視的三個 status flag:

Tx buffer empty flag(TXE) Rx buffer not empty(RXNE)

BUSY flag:用以指示SPI 正忙於傳輸的 flag

.. TODO busy flag

Disabling SPI

.. DMA support ———–

Code section

自定義變數: .. code-block:: prettyprint

unsigned char readData[32];
unsigned char writeData[32];
int rxCounter, txCounter;

初始化 SPI:

.. find GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;

  • Master: .. code-block:: prettyprint // enable clock for used IO pins RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);

      // enable SPI2 peripheral clock
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    
      /* configure pins used by SPI1
       * PE7 = NSS(CS)
       * PA5 = SCK
       * PA6 = MISO
       * PA7 = MOSI
       \*/
      GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5| GPIO_Pin_6 | GPIO_Pin_7;
      GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
      GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
      GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
      GPIO_Init(GPIOA, &GPIO_InitStruct);
    
      // connect SPI2 pins to SPI alternate function
      GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
      GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
      GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
    
    
      GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 \|GPIO_Pin_3;
      GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
      GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
      GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOE, &GPIO_InitStruct);	
    
    
      GPIO_SetBits(GPIOE,GPIO_Pin_3);	//Let the LIS302DL disable
      GPIO_SetBits(GPIOE,GPIO_Pin_7); //Pull High
    
      /* configure SPI1 in Mode 0
      * CPOL = 0 --> clock is low when idle
      * CPHA = 0 --> data is sampled at the first edge
      \*/
      SPI_I2S_DeInit(SPI1);
      SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines
      SPI_InitStruct.SPI_Mode = SPI_Mode_Master; // transmit in master mode, NSS pin has to be always high
      SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide
      SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // clock is low when idle
      SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // data sampled at first edge
      SPI_InitStruct.SPI_NSS = SPI_NSS_Soft|SPI_NSSInternalSoft_Set ; // set the NSS management to internal and pull internal NSS high
      SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // SPI frequency is APB2 frequency / 4
      SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first
      SPI_Init(SPI1, &SPI_InitStruct);
      SPI_Cmd(SPI1, ENABLE); // enable SPI1	
  • Slave mode

.. code-block:: prettyprint // enable clock for used IO pins RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);

    // enable SPI2 peripheral clock
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

    /* configure pins used by SPI2
    * PA15 = NSS(CS)
    * PA5 = SCK
    * PA6 = MISO
    * PA7 = MOSI
    \*/
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5| GPIO_Pin_6 | GPIO_Pin_7 |  GPIO_Pin_15;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    // connect SPI2 pins to SPI alternate function
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource15, GPIO_AF_SPI1);

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOE, &GPIO_InitStruct);	
    

    GPIO_SetBits(GPIOE,GPIO_Pin_3);		//Let the LIS302DL disable

    /* configure SPI1 in Mode 0
    * CPOL = 0 --> clock is low when idle
    * CPHA = 0 --> data is sampled at the first edge
    \*/
    SPI_I2S_DeInit(SPI1);
    SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines
    SPI_InitStruct.SPI_Mode = SPI_Mode_Slave; // transmit in master mode, NSS pin has to be always high
    SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide
    SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // clock is low when idle
    SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // data sampled at first edge
    SPI_InitStruct.SPI_NSS = SPI_NSS_Soft ; // set the NSS management to internal and pull internal NSS high
    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // SPI frequency is APB2 frequency / 4
    SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first
    SPI_Init(SPI1, &SPI_InitStruct);
    SPI_Cmd(SPI1, ENABLE); // enable SPI1	

初始化 LED: .. code-block:: prettyprint /in libstm/Utilities/STM32F4-Discovery/discoveryf4utils.c STM_EVAL_LEDInit(LED4); STM_EVAL_LEDInit(LED3); STM_EVAL_LEDInit(LED5); STM_EVAL_LEDInit(LED6);

STM_EVAL_LEDOff(LED4);
STM_EVAL_LEDOff(LED3);
STM_EVAL_LEDOff(LED5);
STM_EVAL_LEDOff(LED6);

初始化按鍵: .. code-block:: prettyprint GPIO_InitTypeDef GPIO_InitStruct;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    /* Here the GPIOA module is initialized.
    * We want to use PA0 as an input because
    * the USER button on the board is connected
    * between this pin and VCC.
    \*/
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;	// we want to configure PA0
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; // we want it to be an input
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//this sets the GPIO modules clock speed
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // this sets the pin type to push / pull (as opposed to open drain)
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; // this enables the pulldown resistor --> we want to detect a high level
    GPIO_Init(GPIOA, &GPIO_InitStruct);	// this passes the configuration to the Init function which takes care of the low level stuff

Master 設定 - 傳送訊號 .. code-block:: prettyprint uint32_t TimeOutLed=10000; GPIO_SetBits(GPIOE,GPIO_Pin_7); //Chip Select

if(action == 1)	//Led On
        SPI_I2S_SendData(SPI1,LED_ON);
else //Led Off
        SPI_I2S_SendData(SPI1,LED_OFF);

GPIO_ResetBits(GPIOE,GPIO_Pin_7);	

while(SPI_I2S_GetFlagStatus(SPI1,SPI_FLAG_TXE) == RESET);
return 1;
  • task: .. code-block:: prettyprint void pb_task(void *pvParameters) { uint8_t bNewLedOnOff=0 ,bOldLedOnOff=0,bLedOnOff=0;

      while(1)
      {
          if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)== Bit_SET)  //User Button Pressed
          {
              bNewLedOnOff = 1;
              if(bNewLedOnOff ^ bOldLedOnOff)
              {
                  if(bLedOnOff)
                  {
                      RemoteLED_OnOff(0);
                      bLedOnOff = 0;
                      STM_EVAL_LEDOff(LED3);
                  }
                  else
                  {
                      RemoteLED_OnOff(1);
                      bLedOnOff = 1;
                      STM_EVAL_LEDOn(LED3);
                  }
                  bOldLedOnOff = bNewLedOnOff;
              }			
          }
          else 
                  bOldLedOnOff = 0;
      }

    }

Slave 設定: - 接收訊息

.. code-block:: prettyprint uint8_t rcv_tmp = 0;

uint32_t TimeOutLed = 10000;



while(1)

{



        while(SPI_I2S_GetFlagStatus(SPI1,SPI_FLAG_RXNE)== RESET);



        rcv_tmp = (uint8_t)SPI_I2S_ReceiveData(SPI1);



        if(rcv_tmp == LED_ON)

        {

                STM_EVAL_LEDOff(LED4);

        STM_EVAL_LEDOff(LED3);

        STM_EVAL_LEDOff(LED5);

        STM_EVAL_LEDOff(LED6);



        }

        else if(rcv_tmp == LED_OFF)

        {

                STM_EVAL_LEDOn(LED4);

        STM_EVAL_LEDOn(LED3);

        STM_EVAL_LEDOn(LED5);

        STM_EVAL_LEDOn(LED6);

        }

}

main

.. code-block:: prettyprint int main(void)

{

        uint8_t  pressed=0,new_button_state,last_button_state;



        init_SPI();



        init_LED();



        init_PB();







#ifdef MASTER

        STM_EVAL_LEDOff(LED4);

    STM_EVAL_LEDOff(LED3);

    STM_EVAL_LEDOn(LED5);

    STM_EVAL_LEDOff(LED6);

        xTaskCreate(pb_task,

                    (signed portCHAR \*) "Push Button Task",

                    512 /* stack size \*/, NULL, tskIDLE_PRIORITY + 2, NULL);

#else



        xTaskCreate(spi_recv_msg_task,

                    (signed portCHAR *) "SPI Recv Task",

                    512 /* stack size \*/, NULL, tskIDLE_PRIORITY + 2, NULL);

#endif



        /* Start running the tasks. \*/

        vTaskStartScheduler();



        STM_EVAL_LEDOff(LED5);



        return 0;

}

Reference

  • Serial Peripheral Interface Bus - Wikipedia, the free encyclopedia <http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus>_
  • Reference manual: STM32F405xx, STM32F407xx , STM32F415xx and ... <http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/REFERENCE_MANUAL/DM00031020.pdf>_
  • Datasheet: DS8626: ARM Cortex-M4 32b MCU+FPU, 210DMIPS, up to 1MB Flash/192+4KB RAM, USB OTG HS/FS, Ethernet, 17 TIMs, 3 ADCs, 15 comm. interfaces & camera <http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/DM00037051.pdf>_

.. need improve

.. _Reference manual: http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/REFERENCE_MANUAL/DM00031020.pdf