msalau / rl78flash

Tool to program RL78 MCUs via serial bootloader

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

FT232RL causes 'Synchronization failed' error with -b 250000 or 500000 or 1000000 option (Windows)

mon80 opened this issue · comments

I am facing following error while using FT232RL under Windows environment.

>rl78flash -m 2 -b 250000 -iav COM14 cotton_sketch.mot
FAILED
Synchronization failed

or

>rl78flash -m 4 -b 250000 -iav COM14 cotton_sketch.mot
FAILED
Synchronization failed

I debugged this problem for a while and I get an idea to solve it.

port_handle_t serial_open(const char *port)
{
    ...
    if (INVALID_HANDLE_VALUE == fd)
    {
        ...
    }
    else
    {
        DCB dcbSerialParams;
        GetCommState(fd, &dcbSerialParams);
        dcbSerialParams.BaudRate = CBR_115200;
        dcbSerialParams.ByteSize = 8;
        dcbSerialParams.StopBits = TWOSTOPBITS;
        dcbSerialParams.Parity = NOPARITY;
+      dcbSerialParams.fDtrControl = DTR_CONTROL_DISABLE;
+      dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
        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;
}

The reason of the problem is FT232RL's (or its Windows dirver's) initial value of
fDtrControl and fRtsControl are as following and this makes RL78 reset
after SetCommState() is called in serial_set_baud().

dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE; // 'ENABLE' means DTR CONTROL line is set to 'Low'.
dcbSerialParams.fRtsControl = RTS_CONTROL_ENABLE; // 'ENABLE' means RTS CONTROL line is set to 'Low'.

int serial_set_baud(port_handle_t fd, int baud)
{
    DCB dcbSerialParams;
    GetCommState(fd, &dcbSerialParams);
    dcbSerialParams.BaudRate = baud;
    return SetCommState(fd, &dcbSerialParams) != 0 ? 0 : -1;
}

On the other hand, CP2102's (or its Windows dirver's) initial value of
fDtrControl and fRtsControl are as following and this makes no problem.

dcbSerialParams.fDtrControl = DTR_CONTROL_DISABLE; // 'DISABLE' means DTR CONTROL line is set to 'High'.
dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE; // 'DISABLE' means RTS CONTROL line is set to 'High'.

Best Regards,

Thanks for reporting!

The issue, hopefully, has been fixed in release 0.5.4
Binaries can be found here: https://github.com/msalau/rl78flash/releases/tag/v0.5.4
Unfortunately, I don't have a Windows PC to test the changes. My development platform is based on Linux.

BTW, there is also v0.6.0rc1 which introduced an option to invert reset signal, which can be useful with demonstration boards. Binaries are here: https://github.com/msalau/rl78flash/releases/tag/v0.6.0rc1

Best regards,
Maksim.

Hi,

Thank you very much for quick taking care of this issue. I get v0.5.4 and it works well.

On the other hand, regarding v0.6.0rc1, sorry for not trying it yet but as of my first
impression of new source code, there is a lack of inverting initial value which is set to
fDtrControl and fRtsControl.

In case of normal mode: same as above patch.

        dcbSerialParams.fDtrControl = DTR_CONTROL_DISABLE;
        dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;

In case of invert mode: 'ENABLE' should be set instead of 'DISABLE' to avoid reseting RL78.

        dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
        dcbSerialParams.fRtsControl = RTS_CONTROL_ENABLE;

This is only my first impression. I will confirm this in a day.

Best regards,
MON-80

Thanks @mon80,

Is this your blog?
I have a small comment about 1MBit baudrate with CP2102.

[The page 15 of the datasheet](https://www.silabs.com/Support Documents/TechnicalDocs/CP2102-9.pdf#page=15) have a table with supported baudrates. CP2102 supports 921600 bps, but not 1000000 bps.

When you set 1000000 in software, 921600 is actually used instead. I have verified this with logic analyzer. I observed that CP2102 sends bytes to RL78 using 921600 baudrate, RL78 accepts them and answers using true 1000000 baudrate, but CP2102 can't interpret them correctly and marks received bytes as damaged.

Regards,
Maksim.

Hi,

First of all, thank you for the information and I am glad to hear that you visited my blog again.

Regarding v0.6.0rc1, I notice your mistake as following other than serial_win32.c.

File: main.c

int main(int argc, char *argv[])
{
    char erase = 0;
    char verify = 0;
    char write = 0;
    char reset_after = 0;
    char wait = 0;
    char display_info = 0;
-  char mode = 0;
+  short mode = 0;
    char invert_reset = 0;
    int baud = 115200;
    float voltage = 3.3f;
    char terminal = 0;
    int terminal_baud = 0;

About serial_win32.c, I propose following modification.

File: serial_win32.c

extern int verbose_level;
+static int last_dtr_setting;
+static int last_rts_setting;

port_handle_t serial_open(const char *port)
{
    ...
    if (INVALID_HANDLE_VALUE == fd)
    {
        ...
    }
    else
    {
        DCB dcbSerialParams;
        GetCommState(fd, &dcbSerialParams);
        dcbSerialParams.BaudRate = CBR_115200;
        dcbSerialParams.ByteSize = 8;
        dcbSerialParams.StopBits = TWOSTOPBITS;
        dcbSerialParams.Parity = NOPARITY;
-      dcbSerialParams.fDtrControl = DTR_CONTROL_DISABLE;
-      dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
+      last_dtr_setting = (DTR_CONTROL_ENABLE == dcbSerialParams.fDtrControl) ? SETDTR : CLRDTR;
+      last_rts_setting = (RTS_CONTROL_ENABLE == dcbSerialParams.fRtsControl) ? SETRTS : CLRRTS;
        SetCommState(fd, &dcbSerialParams);
...
    }
    return fd;
}

int serial_set_baud(port_handle_t fd, int baud)
{
    DCB dcbSerialParams;
    GetCommState(fd, &dcbSerialParams);
    dcbSerialParams.BaudRate = baud;
+  dcbSerialParams.fDtrControl = (SETDTR == last_dtr_setting) ? DTR_CONTROL_ENABLE : DTR_CONTROL_DISABLE;
+  dcbSerialParams.fRtsControl = (SETRTS == last_rts_setting) ? RTS_CONTROL_ENABLE : RTS_CONTROL_DISABLE;
    return SetCommState(fd, &dcbSerialParams) != 0 ? 0 : -1;
}

int serial_set_dtr(port_handle_t fd, int level)
{
    int command;
    if (level)
    {
        command = CLRDTR;
    }
    else
    {
        command = SETDTR;
    }
+  last_dtr_setting = command;
    return EscapeCommFunction(fd, command) != 0 ? 0 : -1;
}

int serial_set_rts(port_handle_t fd, int level)
{
    int command;
    if (level)
    {
        command = CLRRTS;
    }
    else
    {
        command = SETRTS;
    }
+  last_rts_setting = command;
    return EscapeCommFunction(fd, command) != 0 ? 0 : -1;
}

I try rl78flash.exe which was built using above two files (attached as zip, I am sorry that I am not
familiar with GitHub's workflow yet) and it works well as following table. (Not only FT232RL but
also CP2102. Using CP2102 is for regression check.)

proposal.zip

   FT232RL  CP2102 
 -m 1 -b 250000 -iv   OK  OK 
 -m 2 -b 250000 -iv   OK  OK 
 -m 3 -b 250000 -iv   OK  OK 
 -m 4 -b 250000 -iv   OK  OK 
 -nm 1 -b 250000 -iv  OK  OK 
 -nm 2 -b 250000 -iv  OK  OK 
 -nm 3 -b 250000 -iv  OK  OK 
 -nm 4 -b 250000 -iv  OK  OK 

I add two static variables but I am not sure whether you prefer such modification or not.
If you will choice another modification, there will be no problem for me to confirm it again.

Best regards,
MON-80

Hi,

Now I notice that main_g10.c has the same mistake as main.c.

File: main_g10.c

int main(int argc, char *argv[])
{
    char verify = 0;
    char write = 0;
    char reset_after = 0;
    char wait = 0;
-  char mode = 0;
+  short mode = 0;
    char invert_reset = 0;
    char terminal = 0;
    int terminal_baud = 0;

Best regards,
MON-80

Hi,

After confirming various modes, I notice following mistakes.

File: rl78g10.c

static void rl78g10_set_reset(port_handle_t fd, int mode, int value)
{
    int level = (mode & MODE_INVERT_RESET) ? !value : value;
-  if (MODE_RESET_RTS == mode)
+  if (MODE_RESET_RTS == (mode & MODE_RESET))
    {
        serial_set_rts(fd, level);
    }
    else
    {
        serial_set_dtr(fd, level);
    }
}

File: rl78g10.h

+#define MODE_RESET        1
#define MODE_RESET_DTR    0
-#define MODE_RESET_RTS    1
+#define MODE_RESET_RTS    MODE_RESET
#define MODE_MAX_VALUE    MODE_RESET_RTS
#define MODE_INVERT_RESET 0x100

Best regards,
MON-80

Many thanks!

In few days I'll add your changes to the repo.
Before release I'd like to try these changes on my own. So, sorry if it will take long.

Best regards,
Maksim.

Hi,

It is no problem. I will keep my hardware available for Windows environment's check
until final RC version.

Best regards,
MON-80

Hi MON-80,

Please, take a look at v0.6.0rc2
I added your changes with minor modifications.
In general, I understand idea behind 'last_rts_setting,' but I don't fully understand implementation and why it is required in the first place.

I'll try test this on my own, and will make a release version, when done.

Thanks and regards,
Maksim.

Hi Maksim,

I added the following two lines as an error-proofing code for something new improvement
in the future by someone other than us. If someone calls serial_set_baud() before calling
serial_set_dtr() or serial_set_rts(), serial_set_baud() will use uninitialized last_XXX_setting
which are not initialized with SETXXX nor CLRXXX. I wanted to avoid such situation if it was
possible by easy way like following two lines.

Or in other words, calling SetCommState() with DTR_CONTROL_ENABLE has the same effect as
calling EscapeCommFunction() with SETDTR (also DTR_CONTROL_DISABLE<-->CLRDTR,
RTS_CONTROL_ENABLE <--> SETRTS, RTS_CONTROL_DISABLE<-->CLRRTS). So I think it is
natural to initialize last_XXX_setting with SETXXX or CLRXXX at the time when SetCommState()
is called in serial_open().

port_handle_t serial_open(const char *port)
{
    ...
    if (INVALID_HANDLE_VALUE == fd)
    {
        ...
    }
    else
    {
        DCB dcbSerialParams;
        GetCommState(fd, &dcbSerialParams);
        dcbSerialParams.BaudRate = CBR_115200;
        dcbSerialParams.ByteSize = 8;
        dcbSerialParams.StopBits = TWOSTOPBITS;
        dcbSerialParams.Parity = NOPARITY;
        last_dtr_setting = (DTR_CONTROL_ENABLE == dcbSerialParams.fDtrControl) ? SETDTR : CLRDTR;
        last_rts_setting = (RTS_CONTROL_ENABLE == dcbSerialParams.fRtsControl) ? SETRTS : CLRRTS;
        SetCommState(fd, &dcbSerialParams);
...
    }
    return fd;
}

Best regards,
MON-80

Hi Maksim,

Regarding v0.6.0rc2, it is OK as following.

rl78flash.exe

   FT232RL  CP2102 
 -m 1 -b 250000 -iv COMxx  OK  OK 
 -m 2 -b 250000 -iv COMxx  OK  OK 
 -m 3 -b 250000 -iv COMxx  OK  OK 
 -m 4 -b 250000 -iv COMxx  OK  OK 
 -nm 1 -b 250000 -iv COMxx  OK  OK 
 -nm 2 -b 250000 -iv COMxx  OK  OK 
 -nm 3 -b 250000 -iv COMxx  OK  OK 
 -nm 4 -b 250000 -iv COMxx  OK  OK 

rl78g10flash.exe

   FT232RL  CP2102 
 -m 1 -cv COMxx blank.mot 2K  OK  OK 
 -m 2 -cv COMxx blank.mot 2K  OK  OK 
 -nm 1 -cv COMxx blank.mot 2K  OK  OK 
 -nm 2 -cv COMxx blank.mot 2K  OK  OK 

Best regards,
MON-80

Thanks!