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

コメントをお書きください