USIの極性があっちゃこっちゃなるのを修正。いったん止める(USICR=0)ことで解決できた。正しいのかどうかはわからない。ついでにSWD_SYNCのレートを遅くした。、、、なんとなく。
#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)
/*SWD pins are in PORTA*/
#define PIN_SWDI (0x40)
#define PIN_SWDO (0x20)
#define PIN_SWCLK (0x10)
#define PIN_NRST (0x08)
/*INT0 pin is in PORTB*/
#define PIN_INT0 (0x04)
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){
TCCR1B&=0xF8;
TIMSK1&=~(0x02);/*clear Timer/Counter1 Output Compare A Match Interrupt Enable*/
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){
if(NRST_const){
PORTA|=PIN_NRST;
}else{
PORTA&=~PIN_NRST;
}
if(tx_or_rx==TXorRX_RX){//Rx
USICR=0x5E;
}else{//Tx
USICR=0x5A;
}
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
txBuf[byte_pos]=0xFF;
}
USIDR=txBuf[byte_pos];
USISR=USISR_val[data_num_tx-1];
txCompleted=0;
TCNT1=0x0000;;
TIFR1=0x27;/*clear interrupt request flag*/
TIMSK1=0x02;/*enable timer1 compare A,B interrupt*/
TCCR1B|=0x01;/*start timer1*/
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]=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){
uint16_t tempOCR1A;
uint8_t tempTCCR1A,tempTCCR1B;
tempTCCR1A=TCCR1A;
tempOCR1A=OCR1A;
tempTCCR1B=TCCR1B;
TCCR1A=0x00;
OCR1A=0x0200;
TCCR1B=0x08;
if(NRST_const){
PORTA|=PIN_NRST;
}else{
PORTA&=~PIN_NRST;
}
PORTA&=~PIN_SWDO;delayMicroseconds(50);
txBuf[0]=0x00;
Send_or_Receive_Data(TXorRX_TX,6,NRST_const);
PORTA|=PIN_SWCLK;delayMicroseconds(50);
PORTA|=PIN_SWDO;delayMicroseconds(550);
PORTA&=~PIN_SWDO;delayMicroseconds(50);
TCCR1A=tempTCCR1A;
OCR1A=tempOCR1A;
TCCR1B=tempTCCR1B;
}
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;//Todo : which is better
//Send_or_Receive_Data(TXorRX_TX,1,NRST_const);//Trn//Todo : which is better
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,33,NRST_const);//RDATA+Parity
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);
txBuf[0]=0xFF;
Send_or_Receive_Data(TXorRX_TX,1,NRST_const);//Trn
*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;
uint8_t parity;
uint32_t RDATA;
PORTA&=~PIN_SWDO;
PORTA|=PIN_SWCLK;delayMicroseconds(50);
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++;
}
parity=ReceiveRDATA(&RDATA,NRST_const);
PORTA&=~PIN_SWDO;
PORTA|=PIN_SWCLK;
USICR=0x00;delayMicroseconds(50);
#if (UART_DEBUG==1)
sprintf(dbgstr,"%s %s %02X %02X %04X%04X %02X",APnDP_str[APnDP],RnW_str[RnW_R],ADDR,ack,(uint16_t)((RDATA>>16)&0x0000FFFF),(uint16_t)((RDATA>>0)&0x0000FFFF),parity);
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;
PORTA&=~PIN_SWDO;
PORTA|=PIN_SWCLK;delayMicroseconds(50);
while((cnt<3)&&(ack!=0x80)){
ack=SendSWDCommand_and_ReceiveAck(APnDP,RnW_W,ADDR,NRST_const);
txBuf[0]=0xFF;//Todo : which is better
Send_or_Receive_Data(TXorRX_TX,1,NRST_const);//Trn//Todo : which is better
if(ack!=0x80){
SWD_SYNC(NRST_const);
SWD_SYNC(NRST_const);
SWD_SYNC(NRST_const);
SWD_SYNC(NRST_const);
}
cnt++;
}
SendWDATA(WDATA,NRST_const);
PORTA&=~PIN_SWDO;
PORTA|=PIN_SWCLK;
USICR=0x00;delayMicroseconds(50);
SWD_SYNC(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
}
uint32_t DP_READ(uint8_t ADDR,uint8_t NRST_const){
return SWD_READ(APnDP_DP,ADDR,NRST_const);
}
void DP_WRITE(uint8_t ADDR,uint32_t WDATA,uint8_t NRST_const){
SWD_WRITE(APnDP_DP,ADDR,WDATA,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);
}
volatile uint8_t trigger;
void INT0_interrupt_handler(){
trigger=1;
}
void swd_sequence(){
uint32_t rxData32;
uint8_t ack;
u32u8_t u32u8_data;
DDRA|=(PIN_SWDO|PIN_SWCLK|PIN_NRST);
DDRA&=~(PIN_SWDI);
PORTA|=(PIN_SWDO|PIN_SWCLK);
PORTA&=~(PIN_NRST);
delay(300);
Serial.println("START");
JTAG_to_SWD(0);delayMicroseconds(50);
DP_READ(0x0,0);
DP_READ(0x4,0);
DP_WRITE(0x4,0x50000000,0);
DP_READ(0x4,0);
DP_WRITE(0x0,0x0000001C,0);
DP_READ(0x0,0);
AP_READ(0x0,0xFC,1);
DDRA&=~(PIN_SWDO|PIN_SWCLK|PIN_NRST);
PORTA&=~(PIN_SWDI|PIN_SWDO|PIN_SWCLK|PIN_NRST);
}
void setup(void){
Serial.begin(57600);
TCCR1A=0x00;
OCR1A=0x0040;
TCCR1B=0x08;
txCompleted=1;
trigger=0;
DDRB&=~(PIN_INT0);
PORTB|=(PIN_INT0);
attachInterrupt(0,INT0_interrupt_handler,FALLING);
}
void loop(void){
if(trigger){
detachInterrupt(0);
delay(10);
if((PINB&PIN_INT0)==0x00){
trigger=0;
swd_sequence();
}
attachInterrupt(0,INT0_interrupt_handler,FALLING);
}
}
とりあえず、極性がおかしくなることはなくなりました。めでたしめでたし。と言いたいところだけど、ビットレートが62.5KHz、、、やっぱりだめなんかいなー、、、もうちょっと(いや、かなり)早くしたい。
ATmega(Arduino PRO):SPIを使って8ビット送って、残りをタイマーで。、、、満足いくほど高速化できるか不安。
SAMD21(Seeeduino XIAO):SPIを使って8ビット送って、残りをタイマーで。、、、タイマーの使い方がわからん。(GPIOを成り行きで上げ下げするって方法もある。そういう(無制御なパルスが出る)ライターもあるようですが、いけないことだと思います。要求値より遅くなる分にはいいけど、早くなることがあると、ラインの設計ができんやん)
また、眠くなる薬を処方されたので、とんでもなく眠い。整形外科は「様子を見ましょう」の期間が長い。他の病院にも行ってみようかどうか、、、

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