なんとかなるさね

マイコンをネタにブログを始めてみました


RL78マイコン基板(RL78/G13)|rl78flashの書き込みボーレート変更不具合の暫定修正('workaround') 

rl78flashというオープンソースソフトウェアのフラッシュ書き込みツールですが、書き込み時の通信ボーレートを
デフォルトの115Kbpsから他のボーレート(250Kbps/500Kbps/1Mbps)へ変更すると以下のようにエラーになって
しまいますので、rl78flashのソースコードを暫定的に修正してみました。(暫定としたのは、FT232RLのWindows
ドライバのバージョンに依存して発生する不具合かも知れず、ドライバのバージョンによっては発生しないのかも
知れないような気がしたからです。私のパソコンのドライバは相当古いのかもしれないと気になり始めましたので、
後でアップデートして、再度確認してみるつもりです。) (それと、SiLabs社のチップでは起きない可能性とか。)
(追記 : FTDI社の以下のWindowsドライバにアップデートして確認してみましたが、結果は変わりませんでした。
他方、SiLabs社のCP2102とSiLabs社の以下のWindowsドライバを試してみるとエラーになりませんでした。
FTDI VCP Driver v2.12.16 (latest version @ Microsoft Update @ 2016/09/16) → NG
FTDI VCP Driver v2.12.18 (latest version @ www.ftdichip.com/Drivers/VCP.htm @ 2016/09/16) → NG
SiLabs VCP Driver v6.7 (latest version @ Microsoft Update @ 2016/09/21) → OK
SiLabs VCP Driver v6.7.3 (latest version @ www.silabs.com/products/mcu/Pages/USBtoUARTBridgeVCPDrivers.aspx @ 2016/09/21) → OK
私のパソコンのOSは Windows7 SP1 です。)
(To be continued... What is the conclusion? What does Kurumi Writer's source code(MIT licence) do?)



修正内容は以下の通りです。

ファイル: serial_win32.c
暫定修正内容: 赤字の箇所を追加

int serial_set_dtr(port_handle_t fd, int level)
{
    int command;
    DCB dcbSerialParams; // Added for a workaround by MON-80 (FTDI's driver problem?)
    if (level)
    {
        //command = CLRDTR;
        command = DTR_CONTROL_DISABLE;
    }
    else
    {
        //command = SETDTR;
        command = DTR_CONTROL_ENABLE;
    }
    //return EscapeCommFunction(fd, command) != 0 ? 0 : -1;
    GetCommState(fd, &dcbSerialParams);
    //dcbSerialParams.fDtrControl may differ from EscapeCommFunction()'s CLRDTR/SETDTR
    //This is true for both FTDI's FT232RL/driver and SiLabs' CP2102/driver (2016/09/22)
    dcbSerialParams.fDtrControl = command;
    return SetCommState(fd, &dcbSerialParams) != 0 ? 0 : -1;
}


修正後はエラーになることは無くなりました。



不具合が発生する理由ですが、ボーレートを変更するには以下のようにしてWindows APIを呼び出す必要がある
のですが、使用する構造体の中にボーレート設定値だけでなくDTR信号線/RTS信号線の設定値も含まれていて、
これが適切な値に設定されていないことが原因のようです。とは言え、構造体の内容はWindows APIで取得した
もので、そもそもWindows APIを呼び出したタイミングでのDTR信号線/RTS信号線の設定値をWindows APIが
返さないことが問題のようにも思われるのですが、実はDTR信号線/RTS信号線は以下とは違うWindows APIで
操作されるのが一般的であり、それにも関わらず、そちらのWindows APIでの設定値が反映されるかどうかに
関してWndows APIのドキュメントに記述がありませんでしたので、ちょっと何とも言えない感じです。加えて、
WindowsはFT232RLのWindowsドライバから情報を取得するようになっている可能性もありますが、その場合
にはFT232RLのWindowsドライバが関係してくるかも知れないという気もしなくもないです。(それと、SiLabs
社のチップでは起きない可能性とか。)

ファイル: serial_win32.c
該当箇所の内容:

int serial_set_baud(port_handle_t fd, int baud)
{
    DCB dcbSerialParams;
    GetCommState(fd, &dcbSerialParams);
    dcbSerialParams.BaudRate = baud;
    //dcbSerialParams.fDtrControl may differ from EscapeCommFunction()'s CLRDTR/SETDTR
    //dcbSerialParams.fRtsControl may differ from EscapeCommFunction()'s CLRRTS/SETRTS
    //Both are true for both FTDI's FT232RL/driver and SiLabs' CP2102/driver (2016/09/22)
    return SetCommState(fd, &dcbSerialParams) != 0 ? 0 : -1;
}


追記 : 補足

更に調べてみると、Windows APIで取得した構造体の内容の初期値はFTDI社の場合とSiLabs社の場合とで違う
値になっていました。

ファイル: serial_win32.c
該当箇所の内容: 赤字の箇所は私が追加したコメントです

port_handle_t serial_open(const char *port)
{
    port_handle_t fd;
    char port_full_name[20];
    snprintf(port_full_name, sizeof port_full_name - 2u,
             "\\\\.\\%s", port);
    if (4 <= verbose_level)
    {
        printf("\t\tOpen port: %s\n", port_full_name);
    }
    fd = CreateFile(port_full_name,
                    GENERIC_READ | GENERIC_WRITE,
                    0,
                    NULL,
                    OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL,
                    0);
    if (INVALID_HANDLE_VALUE == fd)
    {
        int error_num = GetLastError();
        char error_string[1024];
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                      NULL,
                      error_num,
                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                      error_string,
                      sizeof error_string,
                      NULL);
        fprintf(stderr, "Unable to open port: (%i) %s\n", error_num, error_string);
    }
    else
    {
        DCB dcbSerialParams;
        GetCommState(fd, &dcbSerialParams);
        dcbSerialParams.BaudRate = CBR_115200;
        dcbSerialParams.ByteSize = 8;
        dcbSerialParams.StopBits = TWOSTOPBITS;
        dcbSerialParams.Parity = NOPARITY;
        //Initial value of following members depend on vender of chip/driver (2016/09/22)
        //dcbSerialParams.fDtrControl : 1@1st time, or 0* FTDI / 0@1st time, or 1* SiLabs
        //dcbSerialParams.fRtsControl : 1@1st time, or 0* FTDI / 0@1st time, or 1* SiLabs
        //'*' means "depends on last setting of SetCommState() before COM close"
        //Real signal value of following members at this moment(2016/09/23)
        //DTR : low@1st time, or high* FTDI / high@1st time, or low* SiLabs
        //RTS : low@1st time, or high* FTDI / high@1st time, or low* SiLabs
        //'*' means "depends on last setting of SetCommState() before COM close"
        SetCommState(fd, &dcbSerialParams);

        COMMTIMEOUTS timeouts;
        timeouts.ReadIntervalTimeout=50;
        timeouts.ReadTotalTimeoutConstant=50;
        timeouts.ReadTotalTimeoutMultiplier=10;
        timeouts.WriteTotalTimeoutConstant=0;
        timeouts.WriteTotalTimeoutMultiplier=0;
        SetCommTimeouts(fd, &timeouts);
        FlushFileBuffers(fd);
    }
    return fd;
}


追記 : 補足

DTR信号線を使用する-m 2オプションだけでなく、RTS信号線を使用する-m 4オプションでも、同じくエラーに
なりましたので、これについても修正して、エラーにならないようにしました。



int serial_set_rts(port_handle_t fd, int level)
{
    int command;
    DCB dcbSerialParams; // Added for a workaround by MON-80 (FTDI's driver problem?)
    if (level)
    {
        //command = CLRRTS;
        command = RTS_CONTROL_DISABLE;
    }
    else
    {
        //command = SETRTS;
        command = RTS_CONTROL_ENABLE;
    }
    //return EscapeCommFunction(fd, command) != 0 ? 0 : -1;
    GetCommState(fd, &dcbSerialParams);
    //dcbSerialParams.fRtsControl may differ from EscapeCommFunction()'s CLRRTS/SETRTS
    //This is true for both FTDI's FT232RL/driver and SiLabs' CP2102/driver (2016/09/22)
    dcbSerialParams.fRtsControl = command;
    return SetCommState(fd, &dcbSerialParams) != 0 ? 0 : -1;
}




追記 : メモ

Windows Communication API - MSDN

DCB structure
https://msdn.microsoft.com/library/aa363214.aspx

GetCommState
https://msdn.microsoft.com/library/cc429283.aspx

SetCommState
https://msdn.microsoft.com/library/cc429715.aspx

EscapeCommFunction
https://msdn.microsoft.com/library/cc429215.aspx

追記 : メモ

Tool to program RL78 MCUs via serial bootloader - GitHub

master
https://github.com/msalau/rl78flash/

releases
https://github.com/msalau/rl78flash/releases/

v0.5.2
https://github.com/msalau/rl78flash/tree/v0.5.2/

関連記事

2016/09/14   blog-entry-810   category: RL78 /* 16bit,8bit CISC */

go page top