前回あまりにも稚拙なコードだったので、書き直した。
flipはルックアップテーブル法(ていうのかな?)とグルーピングしたビットシフト法(ていうのかな?)とを併用。どっちかだけでもできるんだけど、演算時間とコード領域占有量から併用したほうが効率よさそうだなって、、、実際のところコード量がだいぶ少ないし。
パリティは半分にずらしながらXORする方法で。これは調べればすぐわかる方法。
SWDコマンドも定数テーブル化して、いちいち判断しないようにした。
AP-IDRまで読めるようになったので、保管しておく。
#include <avr/iotnx4.h> #define UART_DEBUG 1 #if (UART_DEBUG==1) char dbgstr[40]; #endif typedef union { uint32_t asU32; uint8_t asU8[4]; } u32u8_t; /*SWD command definition*/ #define APnDP_DP (0) #define APnDP_AP (1) char APnDP_str[2][4]={"DP\0","AP\0"}; #define RnW_W (0) #define RnW_R (1) char RnW_str[2][3]={"W\0","R\0"}; #define TXorRX_TX (0) #define TXorRX_RX (1) #define ACK_OK (0x80) #define ACK_WAIT (0x40) #define ACK_FAULT (0x20) #define ACK_DISCONNECT_H (0xE0) #define ACK_DISCONNECT_L (0x00) #define ACK_MASK (0xE0) #define PIN_SWDI (0x40) #define PIN_SWDO (0x20) #define PIN_SWCLK (0x10) #define PIN_NRST (0x08) volatile uint8_t txCompleted; volatile uint8_t rxUSIDR; uint8_t txBuf[32]; uint8_t rxBuf[32]; ISR(TIM1_COMPA_vect){ USICR|=0x01;/*Toggle Clock Port Pin*/ } ISR(USI_OVF_vect){ TIMSK1&=~(0x02);/*clear Timer/Counter1 Output Compare A Match Interrupt Enable*/ TCCR1B&=0xF8; USISR=0x40;/*Write 1 to clear Counter Overflow Interrupt Flag*/ txCompleted=1; rxUSIDR=USIDR; } uint8_t USISR_val[]={0xEE,0xEC,0xEA,0xE8,0xE6,0xE4,0xE2,0xE0}; void Send_or_Receive_Data(uint8_t tx_or_rx,uint8_t dataLength_in_bit,uint8_t NRST_const){ uint8_t data_num_remain,byte_pos,data_num_tx; rxBuf[0]=0x00; if(txCompleted==1){ PORTA|=(PIN_SWDO|PIN_SWCLK); if(NRST_const){ PORTA|=PIN_NRST; }else{ PORTA&=~PIN_NRST; } data_num_remain=dataLength_in_bit; byte_pos=0; while(data_num_remain>0){ data_num_tx=data_num_remain; if(data_num_remain>8){ data_num_tx=8; } data_num_remain=data_num_remain-data_num_tx; if(tx_or_rx==TXorRX_RX){//Rx USICR=0x5E; txBuf[byte_pos]=0xFF; }else{//Tx USICR=0x5A; } USIDR = txBuf[byte_pos]; USISR=USISR_val[data_num_tx-1]; txCompleted=0; TIFR1|=0x02; TCCR1B|=0x01; TIMSK1=0x02; while(txCompleted==0){ // } rxBuf[byte_pos]=rxUSIDR<<(8-data_num_tx); byte_pos=byte_pos+1; } } } uint8_t flip4_table[]={0x00,0x08,0x04,0x0C,0x02,0x0A,0x06,0x0E,0x01,0x09,0x05,0x0D,0x03,0x0B,0x07,0x0F}; uint8_t flip_8bit(uint8_t src,uint8_t num_bit){ uint8_t ret; ret=(flip4_table[src&0x0F]<<4)|(flip4_table[(src>>4)&0x0F]); return ret<<(8-num_bit); } void JTAG_to_SWD(uint8_t NRST_const){ int i,j; for(i=0,j=0;j<7;i++,j++){ txBuf[i]=0x00; } for(j=0;j<7;i++,j++){ txBuf[i]=0xFF; } txBuf[i+1]=flip_8bit(0xE7,8); txBuf[i]=flip_8bit(0x9E,8); i=i+2; for(j=0;j<7;i++,j++){ txBuf[i]=0xFF; } txBuf[i-1]=0xF0; Send_or_Receive_Data(TXorRX_TX,i*8,NRST_const); } void SWD_SYNC(uint8_t NRST_const){ txBuf[0]=0x00; Send_or_Receive_Data(TXorRX_TX,8,NRST_const); } uint32_t CalcParity32(uint32_t src){ src^=(src>>16); src^=(src>>8); src^=(src>>4); src^=(src>>2); src^=(src>>1); return (src&0x00000001); } /*cmd database - [APnDP][RnW][ADDR>>2]*/ uint8_t SWDCMD[2][2][4]={{{0x81,0x95,0x8D,0x99},{0xA5,0xB1,0xA9,0xBD}},{{0xC5,0xD1,0xC9,0xDD},{0xE1,0xF5,0xED,0xF9}}}; uint8_t SendSWDCommand_and_ReceiveAck(uint8_t APnDP,uint8_t RnW,uint8_t ADDR,uint8_t NRST_const){ txBuf[0]=SWDCMD[APnDP&0x01][RnW&0x01][(ADDR>>2)&0x03]; txBuf[1]=0xFF; Send_or_Receive_Data(TXorRX_TX,9,NRST_const);//Cmd+Trn Send_or_Receive_Data(TXorRX_RX,3,NRST_const);//ACK return (rxBuf[0]&ACK_MASK); } void SendWDATA(uint32_t WDATA,uint8_t NRST_const){ u32u8_t u32u8_WDATA; u32u8_WDATA.asU32=WDATA; txBuf[0]=0xFF; Send_or_Receive_Data(TXorRX_TX,1,NRST_const);//Trn txBuf[0]=flip_8bit(u32u8_WDATA.asU8[0],8); txBuf[1]=flip_8bit(u32u8_WDATA.asU8[1],8); txBuf[2]=flip_8bit(u32u8_WDATA.asU8[2],8); txBuf[3]=flip_8bit(u32u8_WDATA.asU8[3],8); if(CalcParity32(WDATA)){ txBuf[4]=0xFF; }else{ txBuf[4]=0x00; } Send_or_Receive_Data(TXorRX_TX,33,NRST_const);//WDATA+Parity } uint8_t ReceiveRDATA(uint32_t* RDATA,uint8_t NRST_const){ u32u8_t u32u8_RDATA; uint8_t ui8_calc_parity; uint8_t ui8_recv_parity; Send_or_Receive_Data(TXorRX_RX,34,NRST_const);//RDATA+Parity+Trn u32u8_RDATA.asU8[0]=flip_8bit(rxBuf[0],8); u32u8_RDATA.asU8[1]=flip_8bit(rxBuf[1],8); u32u8_RDATA.asU8[2]=flip_8bit(rxBuf[2],8); u32u8_RDATA.asU8[3]=flip_8bit(rxBuf[3],8); *RDATA=u32u8_RDATA.asU32; ui8_calc_parity=(uint8_t)(CalcParity32(*RDATA)); ui8_recv_parity=(rxBuf[4]>>7); return (ui8_calc_parity^ui8_recv_parity); } uint32_t SWD_READ(uint8_t APnDP,uint8_t ADDR,uint8_t NRST_const){ uint8_t ack=0; uint8_t cnt=0; uint32_t RDATA; while((cnt<3)&&(ack!=0x80)){ ack=SendSWDCommand_and_ReceiveAck(APnDP,RnW_R,ADDR,NRST_const); if(ack!=0x80){ SWD_SYNC(NRST_const); SWD_SYNC(NRST_const); SWD_SYNC(NRST_const); SWD_SYNC(NRST_const); } cnt++; } ReceiveRDATA(&RDATA,NRST_const); #if (UART_DEBUG==1) sprintf(dbgstr,"%s %s %02X %02X %04X%04X",APnDP_str[APnDP],RnW_str[RnW_R],ADDR,ack,(uint16_t)((RDATA>>16)&0x0000FFFF),(uint16_t)((RDATA>>0)&0x0000FFFF)); Serial.println(dbgstr); #endif return RDATA; } void SWD_WRITE(uint8_t APnDP,uint8_t ADDR,uint32_t WDATA,uint8_t NRST_const){ uint8_t ack=0; uint8_t cnt=0; while((cnt<3)&&(ack!=0x80)){ ack=SendSWDCommand_and_ReceiveAck(APnDP,RnW_W,ADDR,NRST_const); if(ack!=0x80){ SWD_SYNC(NRST_const); SWD_SYNC(NRST_const); SWD_SYNC(NRST_const); SWD_SYNC(NRST_const); } cnt++; } SendWDATA(WDATA,NRST_const); #if (UART_DEBUG==1) sprintf(dbgstr,"%s %s %02X %02X %04X%04X",APnDP_str[APnDP],RnW_str[RnW_W],ADDR,ack,(uint16_t)((WDATA>>16)&0x0000FFFF),(uint16_t)((WDATA>>0)&0x0000FFFF)); Serial.println(dbgstr); #endif } void DP_WRITE(uint8_t ADDR,uint32_t WDATA,uint8_t NRST_const){ SWD_WRITE(APnDP_DP,ADDR,WDATA,NRST_const); } uint32_t DP_READ(uint8_t ADDR,uint8_t NRST_const){ return SWD_READ(APnDP_DP,ADDR,NRST_const); } uint32_t AP_READ(uint8_t APSEL,uint8_t APBANKSEL,uint8_t NRST_const){ uint32_t SELECT; uint32_t RDATA; SELECT=(((uint32_t)APSEL)<<24)|((uint32_t)(APBANKSEL&0xF0)); DP_WRITE(0x8,SELECT,NRST_const); RDATA=SWD_READ(APnDP_AP,APBANKSEL&0x0C,NRST_const); RDATA=DP_READ(0xc,NRST_const); return RDATA; } void AP_WRITE(uint8_t APSEL,uint8_t APBANKSEL,uint32_t WDATA,uint8_t NRST_const){ uint32_t SELECT; uint32_t rxData32; SELECT=(((uint32_t)APSEL)<<24)|((uint32_t)(APBANKSEL&0xF0)); DP_WRITE(0x8,SELECT,NRST_const); SWD_WRITE(APnDP_AP,APBANKSEL&0x0C,WDATA,NRST_const); } void setup(void){ Serial.begin(57600); DDRA|=(PIN_SWDO|PIN_SWCLK|PIN_NRST); DDRA&=~(PIN_SWDI); PORTA|=(PIN_SWDI|PIN_SWCLK|PIN_NRST); TCCR1A=0x00; OCR1A=0x0040; TCCR1B=0x08; txCompleted=1; } void loop(void){ uint32_t rxData32; uint8_t ack; char buf[80]; u32u8_t u32u8_data; Serial.println("START"); JTAG_to_SWD(1); DP_READ(0x0,1); DP_READ(0x4,1); DP_WRITE(0x4,0x50000000,1); DP_READ(0x4,1); AP_READ(0x0,0xFC,1); delay(200); }
UART出力は
START
DP R 00 80 0BC11477
DP R 04 80 F0000040
DP R 04 80 50000000
DP R 04 80 F0000040
DP R 08 80 000000F0
AP R 0C 80 00000000
DP R 0C 80 04770031
となっていて、たぶんうまくいっている。
しかし、エラー処理とかまだまだ甘い点がある。なぜかUSIの極性がおかしくなることもある。やっぱダメかもUSI、、、
ところで、今まで触れなかったけど、SWDの仕様と実際のデバイスの動きは違う。
仕様はこちら。
HostフェーズもTargetフェーズもrisingでセットfallingでキャプチャになっている。
実際のread operationはこちら。
Hostフェーズはfallingでセットrisingでキャプチャっぽい波形なのに、Targetフェーズはrisingでセットfallingでキャプチャになっている。そしてしょーがないので上のコードも実際に合わせて作ってある。なんなんだろう。
コメントをお書きください