· 

ATtinyのUSIでARM Serial Wire Debug(3)

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を成り行きで上げ下げするって方法もある。そういう(無制御なパルスが出る)ライターもあるようですが、いけないことだと思います。要求値より遅くなる分にはいいけど、早くなることがあると、ラインの設計ができんやん)

また、眠くなる薬を処方されたので、とんでもなく眠い。整形外科は「様子を見ましょう」の期間が長い。他の病院にも行ってみようかどうか、、、