SPI Signal and Timing 參考

No Comments

此規格相較於 IIC 而單純。後附以前寫過的 spi timing。
原則上,spi timing 就是遵循以上的 timing 資料。實際的運用將看該 device 所定義的,原則上是可對應到以上四種模式的其中一/幾種。
另常見的狀況補充,例如,daisy-chain,單一支 CS 已成為被各 devices 所共享,故需有 device address 以定址到某一個特定的 device。故而,如以下程式所使用到,MISO pin 在 master 定址時,可被告知 slave 處於 busy 與否。(但 daisy-chain 有時序延遲的附帶影響與所該因應)。
其次,SPI 的可應用時脈相較於 IIC 的高。再因例如 ESP8266 的 GPIO toggle 有 1us 的延遲與中斷有 4us 的 payload。故 nonblocking mode 應是不合適。
因此假若實作 timer-triggered nonblocking mode,應是較適合用在 gpio 擴展上。相反地說,或許可實作 shift-register IC 類別,來套用各種 digital-signal timing specs。


#define MOSI_OUTPUT(bit)      ((bit)?MOSI_HIGH:MOSI_LOW)
#define MISO_INPUT            ((P1IN&0x04)?1:0)
#define CS_LOCK               (P1OUT&=0xF7)
#define CS_UNLOCK             (P1OUT|=0x08)
#define SPI_DELAY_TRANSIENT   (Delay_us(3))
#define SPI_DELAY_LOW         (Delay_us(158))
#define SPI_DELAY_HIGH        (Delay_us(87))
#define SPI_SET_READ(addr)    ((addr)=((addr)&0x3F|0x00))
#define SPI_SET_WRITE(addr)   ((addr)=((addr)&0x3F|0x80))
#define SPI_SIGNAL_START      (CS_LOCK,SCLK_LOW)

int SPI_ReadByte(unsigned char addr, unsigned char *r_data){
    int i;

    SPI_SET_READ(addr);
    SPI_SIGNAL_START;
    SPI_DELAY_TRANSIENT;
    MOSI_OUTPUT(addr&0x80);

    for (i=0; i<7; i++){
        if (!MISO_INPUT){
            SCLK_HIGH;
            MOSI_HIGH;
            CS_UNLOCK;
            return 0;
        }
        SPI_DELAY_LOW;
        SCLK_TOGGLE;
        SPI_DELAY_HIGH;
        SCLK_LOW;
        SPI_DELAY_TRANSIENT;
        addr<<=1;
        MOSI_OUTPUT(addr&0x80);
    }
    SPI_DELAY_LOW;
    SCLK_TOGGLE;
    SPI_DELAY_HIGH;
    for (++i; i<16; i++){
        SCLK_LOW;
        SPI_DELAY_TRANSIENT;
        *r_data<<=1;
        *r_data|=MISO_INPUT;
        SPI_DELAY_LOW;
        SCLK_TOGGLE;
        SPI_DELAY_HIGH;
    }
    CS_UNLOCK;
    MOSI_HIGH;
    SPI_DELAY_LOW; SPI_DELAY_HIGH;
    return 1;
}

int SPI_WriteByte(unsigned char addr, unsigned char data){
    int i;
    long int j;
    SPI_SET_WRITE(addr);
    j=((addr<<8)&0xFF00|data);
    SPI_SIGNAL_START;
    SPI_DELAY_TRANSIENT;
    MOSI_OUTPUT(j&0x8000);

    for (i=0; i<15; i++){
        if (0 && !MISO_INPUT){ // because MISO floating@1st write(before enabled)
            SCLK_HIGH;
            MOSI_HIGH;
            CS_UNLOCK;
            return 0;
        }
        SPI_DELAY_LOW;
        SCLK_TOGGLE;
        SPI_DELAY_HIGH;
        SCLK_LOW;
        SPI_DELAY_TRANSIENT;
        j<<=1;
        MOSI_OUTPUT(j&0x8000);
    }
    SPI_DELAY_LOW;
    SCLK_HIGH;
    CS_UNLOCK;
    MOSI_HIGH;
    SPI_DELAY_LOW; SPI_DELAY_HIGH;
    return 1;
}

Categories: Arduino 其他

Tags:

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

PHP Code Snippets Powered By : XYZScripts.com