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週間、、、しんどい。むしろ腰が痛くなってきた。
一方、もうすぐ健康診断があるので、酒量を減らさんといかん。、、、もっとしんどい。
コメントをお書きください