一、概述
? ? ? ? SCCB(串行攝像頭控制總線)是由歐姆尼圖像技術公司(OmniVision)開發的一種類IIC的總線,主要用于其OV系列的圖像傳感器上(但目前有很多家的圖像傳感器都有采用該控制總線)。相對于IIC總線來說SCCB與之最主要的差異在于連續讀寫模式;SCCB不支持該模式,即每次讀寫完一個字節,主機必須發送一個NA信號。
? ? ? ? 采用了SCCB總線的圖像傳感器都工作在Slave模式,對應的主控端為Master模式,也就是說和IIC一樣的為主從模式的總線,同樣的支持一主多從和單主單從(通過SCCB_E控制從機使能,低電平使能)。
二、信號線定義
? ? ? ? 完整的SCCB總線包含:SCCB_E、SIO_C、SIO_D、PWDN四根信號線,其具體的作用分別為:
? ? ? ? SCCB_E:傳輸使能,主端輸出,從端輸入,默認空閑狀態為高電平。低電平時傳輸有效,電平高到低表示 總線通信開始,電平低到高表示 總線通信結束。
? ? ? ? SIO_C:數據傳輸時鐘,主端輸出,從端輸入,默認空閑狀態為高電平。在SCCB_E使能(拉低)傳輸開始后電平由高到低表示數據傳輸開始,數據傳輸過程中高電平期間SIO_D數據采樣有效,低電平期間SIO_D狀態切換。
? ? ? ? SIO_D:數據傳輸信號,雙向輸入、輸出,默認總線空閑為浮空電平(通常主端在空閑狀態會選擇將其拉高),高電平表示邏輯1(bit 1),低電平表示邏輯0(bit 0)。在總線通信開始,SCCB_E產生下降沿前,主機需要將SIO_D拉高,可以有效的避免總線出現未知錯誤。
? ? ? ? PWDN:輸出、輸入關閉。
三、通信過程
? ? ? ? SCCB的數據傳輸發生在通信開始信號(起始信號)和通信結束信號(結束信號)之間,由稱之為相(phase)的基礎傳輸單元組成。
? ? ? ? 通信開始(起始信號):通信開始時序由SCCB_E下降沿前后的各信號線的序列時序狀態組成;在SCCB_E下降沿前主端將SIO_D置1,并且SIO_D必須保持間隔一個不低于15ns的tPRC的高電平時間;在SCCB_E下降沿后SIO_D必須要保持間隔一個不低于1.25us的tPRA的高電平時間;在此期間,SIO_C必須始終保持在高電平狀態。
? ? ? ? 通信結束(結束信號):通信開始時序由SCCB_E上升沿前后的各信號線的序列時序狀態組成;在SCCB_E上升沿前SIO_C拉高,并且要保持間隔一個不低于0ns的tPSA時間;在SCCB_E上升沿后SIO_D拉低,并且期間要保持間隔一個不低于15ns的tPSC時間。
? ? ? ? SCCB的數據傳輸主要分為:3相寫、2相寫、2相讀,三種傳輸時序類型。這里的3相、2相的相指的是基礎傳輸單元。
? ? ? ? 每一個相元(phase)由8位數據位 + 1位 don’t care/NA位組成。如果是主端發數據(寫操作),第9位就是don’t care(不關心)位;如果是從端發數據(讀操作),第9位就是NA位。數據比特流都是MSB高比特在前的方式傳輸的。
? ? ? ? 相元1傳輸的主要是從機的ID信息,SCCB支持單主多從,所以主機需要在相元1階段發送從機ID信息,以便總線上的從機識別當前主機要與誰通信(單主單從時也不可省略)。從機ID為7bit,表示范圍為0~127,bit 0 用于表示讀/寫操作,0為讀取數據,1為寫入。在相元1的8位數據之后的x位為don’t care位(但有的sensor會在該位通過SIO_D向主端發送一個邏輯0的NA數據,主機端可以通過該位判斷對應ID的從機是否在線)。
? ? ? ? 相元2傳輸的主要是從機寄存地址信息或者讀取的數據信息;8bit后的1bit位也同樣的為don’t care/NA位。
? ? ? ? 相元3傳輸的主要是主機向從機寄存要寫入的數據信息;8bit后的1bit位也同樣的為don’t care/NA位。
? ? ? ? 3相寫時序:3相寫時序是一個完整的主機向指定從機的指定寄存地址寫入指定8bit數據的一個完整數據傳輸周期(相元1的bit0為1),每一個相元的第9bit都是don’t care位。
? ? ? ? 2相寫時序:2相寫時序實際上是前半個主機從指定從機的指定寄存地址讀取8bit數據的完整數據傳輸周期(和2相讀時序共同組成一個完整的讀時序),每一個相元的第9bit都是don’t care位。先向目標從機傳輸讀標志(相元1的bit0和相元2中的8bit寄存地址)。
? ? ? ? 2相讀時序:2相讀序實際上是后半個主機從指定從機的指定寄存地址讀取8bit數據的完整數據傳輸周期(和2相寫時序共同組成一個完整的讀時序))。第一個相元的第9bit都是don’t care位,第二個相元的第9bit為NA位(主端向從端發送的確認信號)。
四、偽代碼實現
//通信開始
void sccb_start(void)
{sccb_sda_out();sccb_sda_set(1);sccb_scl_set(1);delay_us(25);sccb_sda_set(0);delay_us(25);sccb_scl_set(0);delay_us(25);return;
}//通信結束
void sccb_stop(void)
{sccb_sda_out();sccb_sda_set(0);delay_us(25);sccb_scl_set(1);delay_us(25);sccb_sda_set(1);delay_us(25);return;
}//NA信號
void sccb_na(void)
{sccb_sda_out();delay_us(25);sccb_sda_set(1);sccb_scl_set(1);delay_us(25);sccb_scl_set(0);delay_us(25);sccb_sda_set(0);delay_us(25);return;
}//讀取1字節,返回讀取的數據
unsigned char sccb_read_byte(void)
{unsigned char byte = 0, index = 0;sccb_sda_in();for(index = 0; index < 8; index++) {delay_us(25);sccb_scl_set(1);byte = byte << 1;if(1 == sccb_read_sda()) {byte++;}delay_us(25);sccb_scl_set(0);}sccb_sda_out();return byte;
}//寫入1字節,寫入成功返回1,失敗返回0
unsigned char sccb_write_byte(unsigned char data)
{unsigned char res = 0, index = 0;for(index = 0; index < 8; inde++) {if(1 == (data & 0x80)) {sccb_sda_set(1);} else {sccb_sda_set(0);}data <<= 1;delay_us(25);sccb_scl_set(1);delay_us(25);sccb_scl_set(0);}sccb_sda_in();delay_us(25);sccb_scl_set(1);delay_us(25);if(1 == sccb_read_sda()) {res = 1;} else {res = 0;}sccb_scl_set(0);sccb_sda_out();return res;
}//向寄存器寫入1字節,寫入成功返回1,失敗返回0
unsigned char sccb_write_reg(unsigned char reg, unsigned char data)
{unsigned char res = 0;sccb_start();if(1 == sccb_write_byte(sccb_dev_id)) {res = 1;}delay_us(50);if(1 == sccb_write_byte(reg)) {res = 1;}delay_us(50);if(1 == sccb_write_byte(data)) {res = 1;}delay_us(50);sccb_stop();return res;
}//從寄存器讀取1字節
unsigned char sccb_read_reg(unsigned char reg)
{unsigned char res = 0;sccb_start();sccb_write_byte(sccb_dev_id);delay_us(50);sccb_write_byte(reg);delay_us(50);sccb_stop();sccb_start();sccb_write_byte(sccb_dev_id | 0x01);delay_us(50);res = sccb_read_byte();sccb_na();sccb_stop();return res;
}