# [Note] CAN Bus & I2C
>[name=David][time=Mon, 04,10,2023]
[TOC]
###### tags: `Note` `CAN Bus` `I2C` `通訊` `Communication`
## CAN BUS
CAN協議(Conroller Area Network Protocol)為Robert Bosch公司開發(1982年),最初應用於汽車內部網絡的通訊,允許網路上的多個微控制器或設備直接互相通訊。CAN通訊具有嚴格的錯誤檢測機制、高傳輸速率,兼低成本、易於實施,特別適合節點之間關鍵數據傳輸的小型嵌入式網絡通訊。
**Type 是定義為Extend or Standard, Data frame or Remote frame.**
### 特點優點
1. CAN網絡各節點平等競爭,無所謂主從
2. 具有實時性強、傳輸距離較遠、抗電磁干擾能力強、成本低
3. 採用雙線串行通信方式(差動訊號),檢錯能力強,可在高雜訊干擾環境中工作
4. 具有優先權和仲裁功能,多個控制模塊通過CAN 控制器掛到CAN-bus 上,形成多主機局部網絡
5. 可根據報文的ID決定接收或屏蔽該報文
6. 可靠的錯誤處理和檢錯機制
7. 發送的信息遭到破壞後,可自動重發
8. 節點在錯誤嚴重的情況下具有自動退出總線的功能
<img src = "http://wiki.csie.ncku.edu.tw/embedded/CAN%20Bus_Diagram1.png">
ISO 11898-2,也稱為高速度CAN。它在總線的兩端均接有120Ω電阻。
電阻可以穩定通訊,避免信號反射的問題導致資料傳輸出現錯誤!
> * CAN總線上通過差動信號進行數據傳輸
> * CAN收發器將差動信號轉換為TTL數位訊號,或者將TTL數位訊號轉換為差動信號
> * CAN控制器將TTL數位信號接收,並傳輸給MCU
### 輸出訊號
CAN是串列非同步通訊,只有 CAN_HIGH 和 CAN_LOW 兩條差動信號線,
數據通過差動信號的方式進行通訊,
其優點就是可以增加信號的抗干擾能力,抑制共模信號的干擾。
* CAN_H 與 CAN_L 電壓均為2.5V時,表示"1",為隱性(Recessive)
* CAN_H=3.75V 與 CAN_L=1.25V時,表示"0",為顯性(Dominant)
<img src = "http://mianbaoban-assets.oss-cn-shenzhen.aliyuncs.com/xinyu-images/MBXY-CR-41511c94f5bf538e4e5ee5c427f3bfe2.png">
簡單來說,當CAN_HIGH減去CAN_LOW大於某閾值的時候,輸出為高電位,反之,當小於某一個閾值時,就變成低電位。
### 如何收發
CAN Bus其實沒有主從的概念,每個設備都是一個節點(Node),
節點直接可以相互通訊,每個節點不需要設置節點的地址,
而是通過消息的標識符(Identifier)來區別信息。
因為CAN總線的消息是廣播的(就是大家都可以收到消息),
比如總線上有節點A,節點B,節點C,那麼節點A發消息,
節點B和節點C都會收到消息,節點B 和節點C 會根據消息中的標識符,
以及B和C中的消息過濾規則進行比較,如果不滿足規則,就不接受這條信息。
>* **發送消息的時候,總線必須處於空閒狀態**
>* **標識符(ID)越小,則消息獲取的優先權越高**
<img src = "https://www.hoautom.com/wp-content/uploads/2021/03/3227.png">
### CAN Protocol
CAN的通訊格式主要分為五個部分
1. Data Frame(資料通訊格式)
1. Remote Frame(遠端通訊格式)
1. Error Frame(錯誤通訊格式)
1. Overload Frame(過載通訊格式)
1. Interframe Spacing(通訊格式間隔)
#### Data Frame (資料通訊格式)
正常傳送資料的通訊格式,CAN分為兩個版本,分別為CAN2.0A(Standard)與 CAN2.0B(Extended)。
<img src = "http://wiki.csie.ncku.edu.tw/embedded/CAN_dataframe1.png">
> **CAN2.0A(Standard) :最多可支援2^11^個節點,單一訊息可傳送8 Bytes資料。**
> **CAN2.0B(Extended) :最多可支援2^29^個節點,單一訊息可傳送8 Bytes資料,可以接收CAN2.0A的訊息。**
* Start of Frame(SOF): 開始時送出一位元的Dominant (0) 用來作為同步用途
* Arbitration Field: 仲裁碼,用來判斷優先權。
當多節點同時發送時會一個一個判斷。這邊分為CAN 2.0A與CAN 2.0B分別為 11bits 與 29bits。
>SRR: 預設為 recessive(1)
>IDE: Standard為dominant(0),Extended Identifier為 recessive(1)
>RTR: 判斷要傳送還是接收,`RTR = 0` 表示要傳送,`RTR = 1`表示要接收
* Control Field: 資料長度也就是DLC的部分,有4個bit對應如下表:
>R1與R0保留,Dominant(0)。
| DLC | DLC3 | DLC2 | DLC1 | DLC0 |
|:---:|:----:|:----:|:----:|:----:|
| 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 0 | 0 | 1 |
| 2 | 0 | 0 | 1 | 0 |
| 3 | 0 | 0 | 1 | 1 |
| 4 | 0 | 1 | 0 | 0 |
| 5 | 0 | 1 | 0 | 1 |
| 6 | 0 | 1 | 1 | 0 |
| 7 | 0 | 1 | 1 | 1 |
| 8 | 1 | 0/1 | 0/1 | 0/1 |
* Data Field : 寫入要發送的資料或存入要接收的資料,共 8Bytes。
* CRC Field : 錯誤檢查機制,共15bits。
* ACK Field : 確認應答機制,傳送端送出一個1後當接收正確該接收設備會傳送 0。
* EOF : 通訊結束欄位,每筆資料都是由7個bit的1當作結束的判斷。
#### Remote Frame (遠端通訊格式)
<img src = "http://wiki.csie.ncku.edu.tw/embedded/CAN_RTRF.png">
用途為請求遠端節點(設備)傳送資料,**資料長度為0**。
並依照2.0A or B來選擇,當A設備要B設備給資料時,A送出遠端格式同時將B的ID寫入開頭的仲裁位,並且在`RTR=1`後續接上3bit的間歇時間。
#### Error Frame (錯誤通訊格式)
當接收到的訊息錯誤時,接收到的設備會發送錯誤格式告訴其他節點。
#### Overload Frame (過載通訊格式)
通知其他節點延遲傳送資料的格式。
節點處理資料中,對於下一筆資料需要延遲時使用,通常接在遠端通訊格式或資料通訊格式後面。
<img src = "http://wiki.csie.ncku.edu.tw/embedded/CAN_overloadframe.png">
#### Interframe Spacing (通訊格式間隔)
與前一個資料間隔的格式。
* 有3bit的Intermission和一直處於recessive(1)的Bus Idle
* 除了過載通訊格式和錯誤通訊格式之外,訊息之間至少都要有Intermission
### 錯誤偵測
* CRC Error (CRC錯誤) : 主要用來**檢查數據傳送後可能出現的錯誤**。產生的數字在傳送之前會計算出來並且附加到資料後面,也就是上方的CRC Field,然後接收方進行檢驗確定資料是否發生變化。
* ACK Error (ACK錯誤) : 傳送端會傳出2個bit的1為ACK Field,前者為ACK Slot後者為ACK區隔位元。
**當傳送端在ACK Slot送出1的時候,接收端要回傳0**。如果不是的話那就會在ACK 區隔位元後面傳送error frame。
* Format Error (格式錯誤) : CRC與ACK都有區隔位元(delimiter),這些bit都為1如果在這些bit上讀到0,
那從下一個bit開始就傳送Error Frame。
* Stuff Error (填充錯誤) : **接收端和傳送端共同說好傳送幾個相同的bits就要傳送一個相反的bit**,
用來跟delimiter 做區隔。當訊息中連續偵測到6個相同的bit的時候,就會從下一個bit開始傳送Error Frame。
* Bit Error (位元錯誤) : 處於發送資料中的設備會比較發送的資料和匯流排中的電位變化是否一致,
如果不一致則直接在位傳完的訊息後面接著傳送一個Error Frame。
### CAN Bus 硬體
CAN-Bus在接收or傳送資料時,主要須設定三個部分來判斷CAN是否優先傳送or正確接收資料。
1. 節點仲裁碼(Arbitration/ ID)→傳送
1. 訊息遮罩 (Mask)→接收 :
當Mask都為0時,代表沒有開啟Mask功能,不管ID與Filter是多少都能通過。
當Mask為1時,需檢查Filter與ID位元是否相等,相等才能通過。
1. 訊息過濾器 (Filter)→接收
| Mask | Filter | ID | Pass |
| :--: | :----: | :--: | :--: |
| 0 | 0/1 | 0/1 | Y |
| 1 | 0 | 0 | N |
| 1 | 1 | 0 | N |
| 1 | 1 | 1 | Y |
## I2C
* I2C bus 為 Inter-Integrated Circuit Bus 的縮寫,中文叫做積體電路匯流排,其功用為提供 IC 之間的連接與通訊。
* 只有兩條訊號線,SCL (Serial CLock Line) 負責傳時脈,SDA (Serial Data line)負責傳資料。
* I2C bus 是同步串列半雙工模式。
### I2C匯流排架構
使用時允許多個Master進行通訊,將各設備SCL與SDA連結即可。
每一設備皆有屬於自己的地址,不管是任何設備SDA與SCL都屬於Open Drain 的IO腳,同時並接(Wired-And)在兩條線路上,皆需要加入上拉電阻。
**當導通時是低電位不導通時為浮接,所以利用上拉電阻將電位拉高。**
<img src = "https://d1dwq032kyr03c.cloudfront.net/upload/images/20220319/20146325OD2gqO4fyV.png">
* Wired: 意思是二組 (或者是多組) 接線直接就接在一起。
* AND: 意思是它具備邏輯閘 AND 的功能。
以下為AND閘的真值表
| A | B | output |
| :-: | :-: | :----: |
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
也就是說,當所有輸入皆為 High 時,輸出才是High,當有一個輸入為Low時輸出就為Low。
### I2C Protocol
#### 基本時序
<img src = "https://d1dwq032kyr03c.cloudfront.net/upload/images/20220319/20146325Sm651XEd1g.png">
上圖為I2C傳送資料的訊號,可以看到透過SDA和SCL兩條訊號線來傳輸。
* SDA (Serial Data line): 資料線,所以的資料交換都是在SDA上完成。
* SCL (Serial CLock Line): 由Master輸出。
<img src = "https://d1dwq032kyr03c.cloudfront.net/upload/images/20220319/20146325Gmhm8jZnDl.png">
如上圖,訊號的開始和結束分別有 Start/Stop Condition
* START Condition: `SCL = High` 且 `SDA = 負緣`
* STOP Condition: `SCL = High` 且 `SDA = 正緣`
也就是說當SCL(時脈訊號)穩定時,
SDA(資料線)正在改變,負緣 (由High -> Low)表示開始信號,
正緣 (由Low -> High)表示停止信號。
<img src = "https://d1dwq032kyr03c.cloudfront.net/upload/images/20220319/20146325XfAsAjtWmS.png">
透過上圖可以看到在傳輸資料的過程中,當時脈信號穩定 `SCL = 1`時,資料`SDA`要保持穩定,不可更動。
當`SCL = 0`時,資料`SDA`狀態可以改變。
**當 I²C bus 上沒有任何活動時,SCL 和 SDA 都維持在 high。**
### 基本時序-Acknowledge(ACK)
每一組 8-bit 的資料傳輸結束後,後方會跟著一個 Acknowledge bit。
這個bit會由接收端產生。其中又分為ACK與NACK,
**ACK 為 Low** 而 **NACK 為 High**。
* ACK 為 Low 表示「好、OK、收到、請繼續」。當 Master 讀到 ACK 回應,即可以繼續傳輸下一個 Byte。
* NACK 為 High 表示「出錯了、沒有人在家、不要繼續、讀取完畢」。
當 Master 讀到 NACK 回應,意思是 **Slave 沒有回應**,此時 Master 應送出 (結束) 訊號放棄該命令。
### 如何傳輸
<img src = "https://ithelp.ithome.com.tw/upload/images/20210922/20141979fXlK8sfSbV.png">
:::info
:bulb: **Note**: 傳地址後的 Acknowledge bit 必為 slave 傳送給 master,
傳送 Data 後的 Acknowledge bit 則須視前面 R/W 的值而定。
:::
當 Master 對 Slave 寫入時:
1. 先將 SDA 拉 Low,發送開始信號
1. 將設備地址(Slave address)設定為(1 0 1 0 A2 A1 A0)
1. 設定讀寫,Write = 0
1. 每個節點將 Master 設定的地址與自己的地址相比較,若地址匹配,則接收者輸出一個Ack (由 Slave 傳給 Master 回應 OK)
1. Master 輸入要寫入的資料
1. 接收者輸出一個Ack (由 Slave 傳給 Master 回應 OK)
1. 最後 Master 輸出停止信號。(將 SCL 拉 High 時,然後將 SDA 切換為 High)
<img src = "https://d1dwq032kyr03c.cloudfront.net/upload/images/20220320/201463252ZCHH0WBDj.png">
當 Master 對 Slave 讀取時:
* 隨機地址讀取 : 上圖的Dummy Write其實是去寫入一個地址改變Slave上次所儲存的讀寫地址,接著透過當前地址讀的方法讀取資料。
下方的前6個步驟是Dummy Write的拆解
1. 先將 SDA 拉 Low,發送開始信號
1. 將設備地址(Slave address)設定為(1 0 1 0 A2 A1 A0)
1. 設定讀寫,Write = 0 (要寫入地址資料)
1. 接收者輸出一個Ack (由 Slave 傳給 Master 回應 OK)
1. 寫入一個地址去改變Slave上一次儲存的地址
1. 接收者輸出一個Ack (由 Slave 傳給 Master 回應 OK)
1. 再發送一次起始信號(開始當前位置讀的步驟)
1. 將設備地址(Slave address)設定為(1 0 1 0 A2 A1 A0)
1. 設定讀寫,Read = 1 (要讀取地址資料)
1. 接收者輸出一個Ack (由 Slave 傳給 Master 回應 OK)
1. Master 帶回讀取到的資料
1. Master 傳送一個 NACK,表示讀取完畢
1. 最後 Master 輸出停止信號 (將 SCL 拉 High 時,然後將 SDA 切換為 High)
## Reference
[CAN - 成大資工Wiki](http://wiki.csie.ncku.edu.tw/embedded/CAN#data-frame%E8%B3%87%E6%96%99%E9%80%9A%E8%A8%8A%E6%A0%BC%E5%BC%8F)
[STM32-12 CANBus概念介紹](https://ithelp.ithome.com.tw/articles/10284348)
[I2C: Inter-Integrated Circuit - 成大資工Wiki](http://wiki.csie.ncku.edu.tw/embedded/I2C)
[STM32-16 I²C EEPROM DataSheet](https://ithelp.ithome.com.tw/articles/10284401)