· 

Atmega328PでSWDライター作成(2)

とりあえず、DPのIDCODEとAPのIDRを読み込むところまでやったので、その記録。

スイッチで、どっちを実行するか選択して、実行させる。記録のために全コードを載せる(とりあえず記述はあるけど、まだ使ってない部分も多々ある)。例によって基本的にはコメントなし。

swd_tool_ver0002.ino

#include "voltmeas.h"
#include "sd1602drv.h"
#include "switchdrv.h"

#define pinEXEC (18)

#define EXEC_STATE_NUMBER (4)
#define EXEC_STATE_STANDBY (0)
#define EXEC_STATE_COMPLETE (1)
#define EXEC_STATE_EXECUTING (2)
#define EXEC_STATE_ERROR (3)

#define ERROR_STATE_NUMBER (5)
#define ERROR_STATE_NOERROR (0)
#define ERROR_STATE_VCCLOW (1)
#define ERROR_STATE_IDCODE (2)
#define ERROR_STATE_APIDR (3)
#define ERROR_STATE_OTHER (4)

#define MENU_STATE_NUMBER (2)
#define MENU_STATE_READIDCODE (0)
#define MENU_STATE_READAPIDR (1)

int8_t str_exec_state[EXEC_STATE_NUMBER][17]={
    "STANDBY         ",
    "COMPLETE        ",
    "EXECUTING       ",
    "ERROR           "
};
int8_t str_menu_state[MENU_STATE_NUMBER][17]={
    "1.READ DP-IDCODE",
    "2.READ AP-IDR   "
};

uint8_t menu_state;
uint8_t exec_state;
uint8_t error_state;
uint8_t u8_voltupdate;

uint8_t u8ret;
void setup()
{
    Serial.begin(115200);
    menu_state=0;
    exec_state=0;
    error_state=0;
    pinMode(pinEXEC,OUTPUT);
    digitalWrite(pinEXEC,LOW);
    voltmeas_setup();
    sd1602_setup();
    switch_setup();
    swd_setup();
    u8ret=0xFE;
}
void loop()
{
    uint16_t temp;
    uint32_t u32ret;
    u8_voltupdate=voltmeas_task();
    switch_task();
    if(SW_sel_pressed){
        u8ret=0xFF;
        SW_sel_pressed=0;
        menu_state=menu_state+1;
        if(menu_state==MENU_STATE_NUMBER){
            menu_state=0;
        }
    }
    if(SW_exe_pressed){
        u8ret=0xFF;
        SW_exe_pressed=0;
        digitalWrite(pinEXEC,HIGH);
        u8ret=swd_exec(menu_state,&u32ret);
        digitalWrite(pinEXEC,LOW);
    }
    sprintf(lcdlinebuf[0], "%s", str_menu_state[menu_state]);
    sprintf(lcdlinebuf[1], "%s", str_exec_state[exec_state]);
    if(u8ret==0x00){
        sprintf(lcdlinebuf[1], "%08lX", u32ret);
    }
    temp=(uint16_t)(u16_volt/100);
    sprintf(&(lcdlinebuf[1][12]), "%01u.%01uV",(int)(temp/10),(int)(temp%10));
    sd1602_update();
}

voltmeas.h

#ifndef _VOLTMEAS_H
#define _VOLTMEAS_H
extern uint8_t u8_volt_status;
extern uint16_t u16_volt;
#endif

voltmeas.ino

/*
VTGT --> PC0(A0)
*/
#define pinVTGT (A0)
#define pinVOLTOK (19)
#define VOLTMEAS_CNT (100)
#define VOLT_OK_THRESH (2700)

uint8_t u8_volt_status;
uint16_t u8_volt_meas_exec_counter;
uint16_t u16_volt;
void voltmeas_setup(void){
    pinMode(pinVOLTOK, OUTPUT);
    digitalWrite(pinVOLTOK, LOW);
    analogReference(DEFAULT);
    u8_volt_meas_exec_counter=0;
    u8_volt_status=false;
}
uint8_t voltmeas_task(void){
    uint32_t u32_volt;
    uint8_t ret;
    ret=false;
    if(u8_volt_meas_exec_counter==0){
        digitalWrite(pinVOLTOK, HIGH);
        ret=true;
        u32_volt=(uint32_t)(analogRead(pinVTGT))*5000/1024;
        u16_volt=(uint16_t)u32_volt;
        digitalWrite(pinVOLTOK, LOW);
        if(u16_voltVOLTMEAS_CNT){
        u8_volt_meas_exec_counter=0;
    }
    return ret;
}

sd1602drv.h

#ifndef _SD1602DRV_H
#define _SD1602DRV_H
extern char lcdlinebuf[2][17];
#endif

sd1602drv.ino

/*
 * LCD RS pin to PC3 digital pin 17
 * LCD Enable pin to PC2 digital pin 16
 * LCD D4 pin to PD4 digital pin 4
 * LCD D5 pin to PD5 digital pin 5
 * LCD D6 pin to PD6 digital pin 6
 * LCD D7 pin to PD7 digital pin 7
 * LCD R/W pin to PC1 pin 15
 * LCD VSS pin to ground
 * LCD VCC pin to 5V
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)
 */
#define pinRS (17)
#define pinE (16)
#define pinRW (15)
#define pinD4 (4)
#define pinD5 (5)
#define pinD6 (6)
#define pinD7 (7)

#include 

LiquidCrystal lcd(pinRS, pinE, pinD4, pinD5, pinD6, pinD7);
char lcdlinebuf[2][17];

void sd1602_setup()
{
    pinMode(pinRW, OUTPUT);
    digitalWrite(pinRW, LOW);
    lcd.begin(16, 2);
}
void sd1602_update()
{
    lcd.setCursor(0, 0);
    lcd.print(lcdlinebuf[0]);
    lcd.setCursor(0, 1);
    lcd.print(lcdlinebuf[1]);
}

switchdrv.h

#ifndef _SWITCHDRV_H
#define _SWITCHDRV_H
extern uint8_t SW_exe_pressed;
extern uint8_t SW_sel_pressed;
#endif

switchdrv.ino

#define pinINT0 (2)
#define pinINT1 (3)

#define count_max (4)

uint8_t SW_exe_pressed;
uint8_t SW_sel_pressed;

uint8_t exe_press_count;
uint8_t sel_press_count;

void switch_setup(void){
    pinMode(pinINT0,INPUT_PULLUP);
    pinMode(pinINT1,INPUT_PULLUP);
    SW_exe_pressed=0;
    SW_sel_pressed=0;
    exe_press_count=0;
    sel_press_count=0;
}

void switch_task(void){
    int stInt0,stInt1;
    stInt0=digitalRead(pinINT0);
    stInt1=digitalRead(pinINT1);

    if(stInt1==LOW){
        if(sel_press_count=count_max){
                SW_sel_pressed=1;
            }
        }
    }else{
        sel_press_count=0;
    }

    if(stInt0==LOW){
        if(exe_press_count=count_max){
                SW_exe_pressed=1;
            }
        }
    }else{
        exe_press_count=0;
    }
}

swddrv.ino(どうしても正しく表示できないので、pdf化して貼っておく)

ダウンロード
swddrv.ino.pdf
PDFファイル 1.8 MB

swddrv.ino(どうしても正しく表示できないので、こちらに貼っておく)

ターゲットの電圧測定はArduinoのAnalogReadです。AVCCを基準にしてただ測定しているだけ。AVCC=5Vと信じてやってます。ターゲットの電圧測定の結果で制御を変える(電圧が低いとエラー表示する)ところまでは作りこんでないです。とりあえず表示しているだけ。

スイッチ入力は割り込みではなく、ポーリングにしています。で、一定回数押され続けていたらON判定としています。

SWDはTimer1を使ってます。Timer0がArduinoに乗っ取られているので、SWD中はdelayは使わずにdelayMicrosecondsを使ってます(delay使ってもよさそうだったけど、念のため)。

で、SeeeduinoXIAOのATSAMD21G18にアクセスしてみる。

DP-IDCODE

ちゃんと読めてそうです。

AP-IDR

たぶんイケてます。

AP-IDRを読み込んでいるときのロジアナで取得した波形とその解析結果はこちら。クロックは111kHzで、これ以上は速くできないみたい。

色々な失敗を乗り越えてとりあえず、ここまでできました。きれいな心で願望を描くを実践した結果ですよ、きっと。