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

版本 87b303b595ac1b87e0da44c94ff24d3c215e6340

embedded/I2C

Changes from 87b303b595ac1b87e0da44c94ff24d3c215e6340 to 9df185f6d341d9a1ec99000f8f61b60e871d5a7e

---
title: I2C
categories: I2C, Peripherals, STM32F4, STM32F429
...

I²C 簡介
=====================================
I²C(Inter-Integrated Circuit)是內部整合電路的稱呼,是一種串列通訊匯流排,由Philips公司在1980年代為了讓主機板、手機及嵌入式系統用以連接低速週邊裝置而發展,主要應用在board-to-board,它的設計並不能應用到長距離裝置的通訊,由於協定中從樸裝置位址只有7個位元,因此一組I²C的最多裝置位址定義至127個。
I²C只使用兩條雙向開放汲極(Open Drain)(master and slave只能把電位拉到LOW或是讓他OPEN)(串列資料(SDA)及串列時脈(SCL))並利用電阻將電位上拉。I²C允許相當大的工作電壓範圍,但典型的電壓準位為+3.3V或+5v。

I²C bus
...................


.. image:: /embedded/i2c_bus.png

藉由Master發送訊號來控制與Slave之間的通訊


I²C 特性
...................

- I²C 串列傳輸包括四個部分:起始信號、設備位址發送、數據傳送和停止信號。

 - 只能Master<->Slave,無法Slave<->Slave,每個slave都要有一個特定且唯一的位址。



 - START condition: SCL=High 且 SDA為負緣

 - STOP condition: SCL=High 且 SDA=為正緣

  .. image:: /embedded/i2c_condition.png

 - 由Master發送起始信號來開起通訊,所有的slave device接收到起始信號後會進入接收數據模式。接著Master需要發送通訊目標設備的address及R/W資訊。

  - STM32F429提供兩種 address mode - 7bit and 10bit

   - 7bit mode: 發送 7bit 的address (MSB) 及一位元的 R(1)/W(0)後,該 address 的slave端會發送一個bit的 Ack(acknowledge) bit,ACK=0表設定成功(Slave把SDA拉到LOW),開始數據傳送。 

    .. image:: /embedded/i2c_com.png

    (7bit mode)

   - 10bit mode: 總共用兩個byte來傳送 address資訊。第一個byte的前五個位元需為 "11110" 來表示要使用 10-bit addressing。
    


    .. image:: /embedded/i2c_10bit.gif

    (10bit mode)

 - 資料傳輸

  - 在 SCL 為 HIGH 時,SDA 必須是 stable 的。

  - SDA 只能在 SCL 為 LOW 時改變。

  - 一次傳一個 byte,每個byte都跟著一個 ACK bit ,在 ACK bit 時 Master 會釋放bus,此時 Slave 端需把 SDA 拉 LOW,否則 Master 需要發出 STOP訊號 或是重新發送 START 訊號。

 - 在每個 byte 之間 Slave 端可以把 SCL 拉 LOW  來強制讓傳輸暫停。

I²C interrupt and Event
......................................

(內容待補)
    .. image:: /embedded/i2c_interrupt.png

  - status register

    .. image:: /embedded/i2c_status_register(1).png

    .. image:: /embedded/i2c_status_register(2).png

  .. code-block:: c

   /** 
    * @brief  SR1 register flags  
    */
   #define I2C_FLAG_SMBALERT               ((uint32_t)0x10008000)
   #define I2C_FLAG_TIMEOUT                ((uint32_t)0x10004000)
   #define I2C_FLAG_PECERR                 ((uint32_t)0x10001000)
   #define I2C_FLAG_OVR                    ((uint32_t)0x10000800)
   #define I2C_FLAG_AF                     ((uint32_t)0x10000400)
   #define I2C_FLAG_ARLO                   ((uint32_t)0x10000200)
   #define I2C_FLAG_BERR                   ((uint32_t)0x10000100)
   #define I2C_FLAG_TXE                    ((uint32_t)0x10000080)
   #define I2C_FLAG_RXNE                   ((uint32_t)0x10000040)
   #define I2C_FLAG_STOPF                  ((uint32_t)0x10000010)
   #define I2C_FLAG_ADD10                  ((uint32_t)0x10000008)
   #define I2C_FLAG_BTF                    ((uint32_t)0x10000004)
   #define I2C_FLAG_ADDR                   ((uint32_t)0x10000002)
   #define I2C_FLAG_SB                     ((uint32_t)0x10000001) 

   /** 
    * @brief  SR2 register flags  
    */
   #define I2C_FLAG_DUALF                  ((uint32_t)0x00800000)
   #define I2C_FLAG_SMBHOST                ((uint32_t)0x00400000)
   #define I2C_FLAG_SMBDEFAULT             ((uint32_t)0x00200000)
   #define I2C_FLAG_GENCALL                ((uint32_t)0x00100000)
   #define I2C_FLAG_TRA                    ((uint32_t)0x00040000)
   #define I2C_FLAG_BUSY                   ((uint32_t)0x00020000)
   #define I2C_FLAG_MSL                    ((uint32_t)0x00010000) 

  (暫存器可參考 http://www.eng.auburn.edu/~nelson/courses/elec5260_6260/STM32F4%20I2C.pdf)

  - I2C bus “events” from flags

  I2C Master Events

  .. code-block:: c

   /* --EV5 */
   #define  I2C_EVENT_MASTER_MODE_SELECT                      ((uint32_t)0x00030001)  /* BUSY, MSL and SB flag */
   /* --EV6 */
   #define  I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED        ((uint32_t)0x00070082)  /* BUSY, MSL, ADDR, TXE and TRA flags */
   #define  I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED           ((uint32_t)0x00030002)  /* BUSY, MSL and ADDR flags */
   /* --EV9 */
   #define  I2C_EVENT_MASTER_MODE_ADDRESS10                   ((uint32_t)0x00030008)  /* BUSY, MSL and ADD10 flags */
   /* Master RECEIVER mode -----------------------------*/ 
   /* --EV7 */
   #define  I2C_EVENT_MASTER_BYTE_RECEIVED                    ((uint32_t)0x00030040)  /* BUSY, MSL and RXNE flags */  

   /* Master TRANSMITTER mode --------------------------*/
   /* --EV8 */
   #define I2C_EVENT_MASTER_BYTE_TRANSMITTING                 ((uint32_t)0x00070080) /* TRA, BUSY, MSL, TXE flags */
   /* --EV8_2 */
   #define  I2C_EVENT_MASTER_BYTE_TRANSMITTED                 ((uint32_t)0x00070084)  /* TRA, BUSY, MSL, TXE and BTF flags */



  I2C Slave Events

  .. code-block:: c

   /* --EV1 */
   #define  I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED          ((uint32_t)0x00020002) /* BUSY and ADDR flags */
   #define  I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED       ((uint32_t)0x00060082) /* TRA, BUSY, TXE and ADDR flags */
   /* Slave RECEIVER mode --------------------------*/ 
   /* --EV2 */
   #define  I2C_EVENT_SLAVE_BYTE_RECEIVED                     ((uint32_t)0x00020040)  /* BUSY and RXNE flags */
   /* --EV4  */
   #define  I2C_EVENT_SLAVE_STOP_DETECTED                     ((uint32_t)0x00000010)  /* STOPF flag */

   /* Slave TRANSMITTER mode -----------------------*/
   /* --EV3 */
   #define  I2C_EVENT_SLAVE_BYTE_TRANSMITTED                  ((uint32_t)0x00060084)  /* TRA, BUSY, TXE and BTF flags */
   #define  I2C_EVENT_SLAVE_BYTE_TRANSMITTING                 ((uint32_t)0x00060080)  /* TRA, BUSY and TXE flags */
   /* --EV3_2 */
   #define  I2C_EVENT_SLAVE_ACK_FAILURE                       ((uint32_t)0x00000400)  /* AF flag */



four I²C modes
...................

(內容待補) (要怎麼把圖縮小= =?)

以下都以7 bit adress mode 作範例

Slave transmitter
------------------------------------

.. image:: /embedded/i2c_slave_transmitter.png

Slave receiver
------------------------------------

.. image:: /embedded/i2c_slave_receiver.png

Master transmitter
------------------------------------

.. image:: /embedded/i2c_master_transmitter.png


WriteOneByte

- 產生 start bit: I2C_GenerateSTART()
- 等待EV5:  while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
- 傳送7bit address與傳輸模式: I2C_Send7bitAddress(i2cx, i2c_ADDR, I2C_Direction_Transmitter);
- 等待EV6: while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
- 傳送一個byte: I2C_SendData(I2Cx);
- 確認BYTE傳送完成: while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTER) );
- 產生 stop bit: I2C_GenerateSTOP();

Master receiver
------------------------------------

.. image:: /embedded/i2c_master_receiver.png

ReadOneByte

- 產生 start bit: I2C_GenerateSTART()
- 等待EV5:  while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
- 傳送7bit address與傳輸模式: I2C_Send7bitAddress(i2cx, i2c_ADDR, I2C_Direction_Receiver);
- 等待EV6: while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
- 確認BYTE接收完成: while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
- 讀取暫存器: I2C_ReceiveData(I2Cx);
- 產生 stop bit: I2C_GenerateSTOP();

I²C on STM32F429-Discovery
=====================================

實驗一: touch panel
...................

觀察及使用stm32f429i_discovery_ioe.c,並量測對應的訊號

- `Data sheet <http://www.st.com/web/en/resource/technical/document/datasheet/CD00186725.pdf>`_

demo code:

[stm32f429i_discovery_ioe.h]


.. code-block:: c

 #define IOE_I2C                    I2C3
 #define IOE_I2C_CLK                RCC_APB1Periph_I2C3
 #define IOE_I2C_SCL_PIN            GPIO_Pin_8
 #define IOE_I2C_SCL_GPIO_PORT      GPIOA
 #define IOE_I2C_SCL_GPIO_CLK       RCC_AHB1Periph_GPIOA
 #define IOE_I2C_SCL_SOURCE         GPIO_PinSource8
 #define IOE_I2C_SCL_AF             GPIO_AF_I2C3
 #define IOE_I2C_SDA_PIN            GPIO_Pin_9
 #define IOE_I2C_SDA_GPIO_PORT      GPIOC
 #define IOE_I2C_SDA_GPIO_CLK       RCC_AHB1Periph_GPIOC
 #define IOE_I2C_SDA_SOURCE         GPIO_PinSource9
 #define IOE_I2C_SDA_AF             GPIO_AF_I2C3
 #define IOE_I2C_DR                 ((uint32_t)0x40005C10)


GPIO 設定

.. code-block:: c

  GPIO_InitTypeDef GPIO_InitStructure;
  

  /* 設定RCC clock*/
  /* Enable IOE_I2C and IOE_I2C_GPIO_PORT & Alternate Function clocks */
  RCC_APB1PeriphClockCmd(IOE_I2C_CLK, ENABLE);
  RCC_AHB1PeriphClockCmd(IOE_I2C_SCL_GPIO_CLK | IOE_I2C_SDA_GPIO_CLK |
                         IOE_IT_GPIO_CLK, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
  
  /* Reset IOE_I2C IP */
  RCC_APB1PeriphResetCmd(IOE_I2C_CLK, ENABLE);
  /* Release reset signal of IOE_I2C IP */
  RCC_APB1PeriphResetCmd(IOE_I2C_CLK, DISABLE);


  /*設定PA8、PC9 的Alternate function設為 GPIO_AF_I2C3*/
  /* Connect PXx to I2C_SCL*/
  GPIO_PinAFConfig(IOE_I2C_SCL_GPIO_PORT, IOE_I2C_SCL_SOURCE, IOE_I2C_SCL_AF);
  /* Connect PXx to I2C_SDA*/
  GPIO_PinAFConfig(IOE_I2C_SDA_GPIO_PORT, IOE_I2C_SDA_SOURCE, IOE_I2C_SDA_AF); 
    
  /* 設定 SCL、SDA pin*/
  /* IOE_I2C SCL and SDA pins configuration */
  GPIO_InitStructure.GPIO_Pin = IOE_I2C_SCL_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
  GPIO_Init(IOE_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = IOE_I2C_SDA_PIN;
  GPIO_Init(IOE_I2C_SDA_GPIO_PORT, &GPIO_InitStructure);

  
I2C參數設定

.. code-block:: c

  I2C_InitTypeDef I2C_InitStructure;

  /* If the I2C peripheral is already enabled, don't reconfigure it */
  if ((IOE_I2C->CR1 & I2C_CR1_PE) == 0)
  {   

    /* 設定 I2C參數*/
    /* IOE_I2C configuration */
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = 0x00;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED;
  
    /* Initialize the I2C peripheral */
    I2C_Init(IOE_I2C, &I2C_InitStructure);
  
    /* Enable the I2C peripheral */
    I2C_Cmd(IOE_I2C, ENABLE);
  }   

(待補)

SCL: PA8 

SDA: PC9

slave address: 0x82 (0x01000010)

.. image:: /embedded/I2C_touchpanel_test.jpg
.. image:: /embedded/i2c_scope_0.bmp


實驗二: 兩塊(以上)板子的數據傳輸
...................

一塊板子當作Master,其他的作為Slave,實驗I2C的資料傳輸
(待補)
(NVIC & I2C interrupt)


Reference
=====================================
- `reference_manual <http://www.st.com/web/en/resource/technical/document/reference_manual/DM00031020.pdf>`_
- `wikipedia <http://zh.wikipedia.org/wiki/I%C2%B2C>`_
- `http://www.eng.auburn.edu/~nelson/courses/elec5260_6260/STM32F4%20I2C.pdf <_http://www.eng.auburn.edu/~nelson/courses/elec5260_6260/STM32F4%20I2C.pdf>`_