· 

CでFTDI BitBang(3)

CでBitBangしてみます。せっかくなので応用例としてARMのSerialWireDebugに使ってみます。どこまでできるかわからんですが。

 

ARMの仕様はこちらです。

とんでもなく分かりにくいので、こちらこちら、さらにこちらを見たほうが良い。

 

今回はArduinoM0で使用されているATSAMD21G18にFT231XボードでアクセスしてDP-IDCODE(DPのADR0x0)を読み出してみます。

 

早速、コードはこちら。そして解説なし。雑な部分が多いし、エラー処理はしていないです。

#include <windows.h>

/*FT231X pin settings*/
#define SWCLK_pos (0x20) //DSR#(D5)
#define SWDO_pos (0x40) //DCD#(D6)
#define NRES_pos (0x80) //RI#(D7)
#define SWDI_pos (0x10) //DTR#(D4)

#define OUTSET (SWCLK_pos|SWDO_pos|NRES_pos)
#define INSET (SWCLK_pos|NRES_pos)

/*FTDI variable types*/
typedef PVOID   FT_HANDLE;
typedef ULONG   FT_STATUS;

/*FTDI DLL*/
const char dllfile[]="ftd2xx64.dll";

/*FTDI function types*/
typedef FT_STATUS (WINAPI *FT_Open_type)(int deviceNumber,FT_HANDLE *pHandle);
typedef FT_STATUS (WINAPI *FT_Close_type)(FT_HANDLE ftHandle);
typedef FT_STATUS (WINAPI *FT_SetBitMode_type)(FT_HANDLE ftHandle,UCHAR ucMask,UCHAR ucEnable);
typedef FT_STATUS (WINAPI *FT_SetBaudRate_type)(FT_HANDLE ftHandle,ULONG BaudRate);
typedef FT_STATUS (WINAPI *FT_Write_type)(FT_HANDLE ftHandle,LPVOID lpBuffer,DWORD dwBytesToWrite,LPDWORD lpBytesWritten);
typedef FT_STATUS (WINAPI *FT_Read_type)(FT_HANDLE ftHandle,LPVOID lpBuffer,DWORD dwBytesToRead,LPDWORD lpBytesReturned);
typedef FT_STATUS (WINAPI *FT_GetQueueStatus_type)(FT_HANDLE ftHandle,DWORD *dwRxBytes);

/*global variables*/
HMODULE dll;
FT_Open_type FT_Open;
FT_Close_type FT_Close;
FT_SetBitMode_type FT_SetBitMode;
FT_SetBaudRate_type FT_SetBaudRate;
FT_Write_type FT_Write;
FT_Read_type FT_Read;
FT_GetQueueStatus_type FT_GetQueueStatus;
FT_HANDLE ftHandle;
FT_STATUS ftStatus;

/*data structure for sending*/
#define SENDDATA_MEXLEN (4096)
typedef struct {
    unsigned char data[SENDDATA_MEXLEN];
    int len;
} txrxdata_t;

#define DATA_MAXLEN (512)

#define BAUD_FAST (9600)
#define BAUD_SLOW (300)

void AppendSenddata(txrxdata_t* d1,txrxdata_t d2){
    int i,j;
    for(i=d1->len,j=0;j<d2.len;i++,j++){
        d1->data[i]=d2.data[j];
    }
    d1->len+=d2.len;
}
void ClearSenddata(txrxdata_t* tgt){
    int i;
    for(i=0;i<SENDDATA_MEXLEN;i++){
        tgt->data[i]=0;
    }
    tgt->len=0;
}
txrxdata_t DataArrayToSamplingArrayL(char* src,int nbit,char nresval){
    txrxdata_t s;
    char c,nres_out;
    int i,j;
    int nbyte;
    nbyte=(nbit-1)/8+1;
    ClearSenddata(&s);
    if(nresval>0){
        nres_out=NRES_pos;
    }else{
        nres_out=0;
    }
    for(i=0;i<nbyte;i++){
        c=src[nbyte-1-i];
        for(j=0;j<8;j++){
            if((c&0x01)>0){
                s.data[(i*8+j)*2+0]=(SWDO_pos|nres_out);
                s.data[(i*8+j)*2+1]=(SWDO_pos|SWCLK_pos|nres_out);
            }else{
                s.data[(i*8+j)*2+0]=(nres_out);
                s.data[(i*8+j)*2+1]=(SWCLK_pos|nres_out);
            }
            //s.len=s.len+2;
            c=c>>1;
        }
    }
    s.len=nbit*2;
    return s;
};
txrxdata_t DataArrayToSamplingArrayM(char* src,int nbit,char nresval){
    txrxdata_t s;
    char c,nres_out;
    int i,j;
    int nbyte;
    nbyte=(nbit-1)/8+1;
    ClearSenddata(&s);
    if(nresval>0){
        nres_out=NRES_pos;
    }else{
        nres_out=0;
    }
    for(i=0;i<nbyte;i++){
        c=src[i];
        for(j=0;j<8;j++){
            if((c&0x80)>0){
                s.data[(i*8+j)*2+0]=(SWDO_pos|nres_out);
                s.data[(i*8+j)*2+1]=(SWDO_pos|SWCLK_pos|nres_out);
            }else{
                s.data[(i*8+j)*2+0]=(nres_out);
                s.data[(i*8+j)*2+1]=(SWCLK_pos|nres_out);
            }
            //s.len=s.len+2;
            c=c<<1;
        }
    }
    s.len=nbit*2;
    return s;
};

void SamplingArrayToDataArrayM(unsigned char* sarr,int slen,unsigned char pos,txrxdata_t* d){
    int i;
    int dpos,bpos;
    dpos=0;
    bpos=0;
    for(i=1;i<slen;i=i+2){
        if(sarr[i]&pos){
            d->data[dpos]|=(0x01<<(7-bpos));
        }else{
            d->data[dpos]&=~(0x01<<(7-bpos));
        }
        if(bpos<7){
            bpos=bpos+1;
        }else{
            bpos=0;
            dpos=dpos+1;
        }
    }
    if(bpos==0){
        dpos=dpos-1;
    }
    d->len=dpos+1;
}
/*SamplingArrayToDataArrayL is not completed.*/
/*Do not use!*/
#if 0
void SamplingArrayToDataArrayL(unsigned char* sarr,int slen,unsigned char pos,txrxdata_t* d){
    int i;
    int dpos,bpos;
    dpos=0;
    bpos=7;
    for(i=slen-1;i>0;i=i-2){
        if(sarr[i]&pos){
            d->data[dpos]|=(0x01<<(7-bpos));
        }else{
            d->data[dpos]&=~(0x01<<(7-bpos));
        }
        if(bpos>0){
            bpos=bpos-1;
        }else{
            bpos=7;
            dpos=dpos+1;
        }
    }
    if(bpos==0){
        dpos=dpos-1;
    }
    d->len=dpos+1;
}
#endif

ULONG DATA_OUT(txrxdata_t txData,unsigned char* rxBuffer){
    ULONG RxBytes=0;
    ULONG RRxBytes;
    ULONG written;
    //unsigned char rxBuffer[SENDDATA_MEXLEN];
    txData.data[txData.len]=txData.data[txData.len-1];
    txData.len=txData.len+1;
    ftStatus=FT_Write(ftHandle,&(txData.data[0]),txData.len,&written);
    ftStatus=FT_GetQueueStatus(ftHandle,&RxBytes);
    while(RxBytes<written){
        ftStatus=FT_GetQueueStatus(ftHandle,&RxBytes);
    }
    ftStatus=FT_Read(ftHandle,rxBuffer,RxBytes,&RRxBytes);
    //SamplingArrayToDataArrayM(RxBuffer,RRxBytes,SWDI_pos,rxData);
    return RRxBytes;
}

void CONST_OUT(data_one){
    txrxdata_t txData;
    unsigned char rxBuffer[SENDDATA_MEXLEN];
    txData.data[0]=data_one;
    txData.len=1;
    DATA_OUT(txData,rxBuffer);
}

/*Send "RESET JTAG_to_SWD RESET"*/
void JTAG_to_SWD(int nres_const){
    ULONG written;
    txrxdata_t txData;
    unsigned char rxBuffer[SENDDATA_MEXLEN];
    unsigned char data[DATA_MAXLEN];
    int i;
    for(i=0;i<7;i++){
        data[i]=0x00;
    }
    txData=DataArrayToSamplingArrayL(data,50,nres_const);
    for(i=0;i<7;i++){
        data[i]=0xFF;
    }
    AppendSenddata(&txData,DataArrayToSamplingArrayL(data,50,nres_const));
    data[0]=0xE7;
    data[1]=0x9E;
    AppendSenddata(&txData,DataArrayToSamplingArrayL(data,16,nres_const));
    for(i=0;i<7;i++){
        data[i]=0xFF;
    }
    AppendSenddata(&txData,DataArrayToSamplingArrayL(data,50,nres_const));
    data[0]=0x00;
    AppendSenddata(&txData,DataArrayToSamplingArrayL(data,4,nres_const));

    DATA_OUT(txData,rxBuffer);
}
void SWD_Unknown(int nres_const){
    ULONG written;
    txrxdata_t txData;
    unsigned char rxBuffer[SENDDATA_MEXLEN];
    unsigned char data=0x00;
    txData=DataArrayToSamplingArrayL(&data,6,nres_const);
    ftStatus=FT_SetBaudRate(ftHandle,BAUD_SLOW);
    DATA_OUT(txData,rxBuffer);
    ftStatus=FT_SetBaudRate(ftHandle,BAUD_FAST);
}

unsigned char bit_invert_8bit(unsigned char src){
    unsigned char ret=0;
    if(src&0x01){ret|=0x80;}
    if(src&0x02){ret|=0x40;}
    if(src&0x04){ret|=0x20;}
    if(src&0x08){ret|=0x10;}
    if(src&0x10){ret|=0x08;}
    if(src&0x20){ret|=0x04;}
    if(src&0x40){ret|=0x02;}
    if(src&0x80){ret|=0x01;}
    return ret;
}

int CheckParityRead32(unsigned char* data){
    int ret=-1;
    int i,j;
    unsigned char par=0;
    for(i=0;i<4;i++){
        for(j=0;j<8;j++){
            if((data[i]<<j)&0x80){
                par=par+1;
            }
        }
    }
    if(par&0x01){
        if(data[4]&0x80){
            ret=0;
        }
    }else{
        if(!(data[4]&0x80)){
            ret=0;
        }
    }
    return ret;
}

int SWD_Read32(int APnDP,unsigned char ADDR,int nres_const,unsigned char* rxData32){
    unsigned char ret;
    int i;
    ULONG written;
    txrxdata_t txData;
    unsigned char rxBuffer[SENDDATA_MEXLEN];
    unsigned long rnBytes;
    txrxdata_t rxData;
    unsigned char data[DATA_MAXLEN];
    unsigned char parity=1;//Read
    data[0]=0xA1;
    data[1]=0xF0;
    if(APnDP){
        data[0]|=0x40;
        parity+=1;
    }
    if((ADDR==0x08)||(ADDR==0x04)){
        parity+=1;
    }

    data[0]|=(((ADDR&0x0C)<<1)&0x18);
    data[0]|=((parity&0x01)<<2);

    txData=DataArrayToSamplingArrayM(data,12,nres_const);
    rnBytes=DATA_OUT(txData,rxBuffer);
    SamplingArrayToDataArrayM(rxBuffer,rnBytes,SWDI_pos,&rxData);
    ret=-1;
    if((rxData.data[1]&0x70)==0x40){// ACK OK
        for(i=0;i<5;i++){
            data[i]=0xFF;
        }
        txData=DataArrayToSamplingArrayM(data,34,nres_const);
        rnBytes=DATA_OUT(txData,rxBuffer);
        SamplingArrayToDataArrayM(rxBuffer,rnBytes,SWDI_pos,&rxData);
        if(CheckParityRead32(&(rxData.data[0]))==0){
            rxData32[3]=bit_invert_8bit(rxData.data[0]);
            rxData32[2]=bit_invert_8bit(rxData.data[1]);
            rxData32[1]=bit_invert_8bit(rxData.data[2]);
            rxData32[0]=bit_invert_8bit(rxData.data[3]);
            ret=0;
        }
    }else{// ACK NOT OK

    }
    return ret;
}

int main(int argc,char** argv){

    unsigned char rx32[4];

    dll=LoadLibrary(dllfile);

    FT_Open=(FT_Open_type)GetProcAddress(dll, "FT_Open");
    FT_Close=(FT_Close_type)GetProcAddress(dll, "FT_Close");
    FT_SetBitMode=(FT_SetBitMode_type)GetProcAddress(dll, "FT_SetBitMode");
    FT_SetBaudRate=(FT_SetBaudRate_type)GetProcAddress(dll, "FT_SetBaudRate");
    FT_Write=(FT_Write_type)GetProcAddress(dll, "FT_Write");
    FT_Read=(FT_Read_type)GetProcAddress(dll, "FT_Read");
    FT_GetQueueStatus=(FT_GetQueueStatus_type)GetProcAddress(dll, "FT_GetQueueStatus");

    printf("dll              =%d\n",dll);
    printf("FT_Open          =%d\n",FT_Open);
    printf("FT_Close         =%d\n",FT_Close);
    printf("FT_SetBitMode    =%d\n",FT_SetBitMode);
    printf("FT_SetBaudRate   =%d\n",FT_SetBaudRate);
    printf("FT_Write         =%d\n",FT_Write);
    printf("FT_Read          =%d\n",FT_Read);
    printf("FT_GetQueueStatus=%d\n",FT_GetQueueStatus);

    ftStatus=FT_Open(0,&ftHandle);
    ftStatus=FT_SetBaudRate(ftHandle,BAUD_FAST);
    ftStatus=FT_SetBitMode(ftHandle,OUTSET,4);

    CONST_OUT(SWCLK_pos|SWDO_pos|NRES_pos);
    Sleep(100);
    CONST_OUT(0);
    Sleep(100);
    CONST_OUT(SWCLK_pos|SWDO_pos|NRES_pos);
    Sleep(100);

    JTAG_to_SWD(1);
    //SWD_Unknown(0);
    SWD_Read32(0,0x0,1,rx32);
    printf("IDCODE=%02X%02X%02X%02X\n",rx32[0],rx32[1],rx32[2],rx32[3]);

    ftStatus=FT_Close(ftHandle);
    printf("%d\n",ftStatus);
    Sleep(1000);

    FreeLibrary(dll);

    return 0;
}

ArduinoM0のSWDピンの半田面から線だししています。

ArduinoM0側のSWDIO端子はFT231XのDTR#(D4)につなぎます。

DCD#(D6)とDTR#(D4)は3.3kΩでつないでいます。

で、実行結果。

あっているのかわからんけど、0BC11477ってのが読み取れました。

↑通信シーケンスの全体

↓各部分

JTAG-to-SWD

コマンドからACKまで

データの受信

ロジアナの結果と同じ値が読み取れていることがわかります。

 

、、、ACK判定して読み取り用のCLKを送るまでの隙間を短くしたいんだけど、ライター作っている人たちはどうやっているんだろう?

 

眠気と戦った(戦ってない)1週間、、、しんどい。むしろ腰が痛くなってきた。

一方、もうすぐ健康診断があるので、酒量を減らさんといかん。、、、もっとしんどい。