Fixing upload problem with Arduino Uno Clone with CH340 on Linux


I just got my first Arduino Uno board with a CNC shield and wanted to setup the development environment on my freshly installed Linuxmint 18.1 laptop to start playing with it.

Once I got the Arduino IDE installed and tried to upload some of the example sketches. I was greeted with the following errors.

         Using Port                    : /dev/ttyUSB3
         Using Programmer              : arduino
         Overriding Baud Rate          : 115200
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0x00
...

After Googling to get some idea of what is the problem. It seem that this clone is using the CH340G USB to serial chip instead of the FTDI chipset used on the Genuine board.

lsusb

Bus 002 Device 005: ID 03f0:231d Hewlett-Packard Broadcom 2070 Bluetooth Combo
Bus 002 Device 004: ID 1bcf:2805 Sunplus Innovation Technology Inc.
Bus 002 Device 015: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter

The ch341 module that came with Linuxmint distribution was able to detect and load the module but uploading sketch using USB to serial communicating with this chipset is still a problem.

lsmod | grep ch34
ch341                  20480  0
usbserial              40960  7 ch341,qcserial,usb_wwan

To resolve this. First remove the ch341 module and replace it with one build locally from source provided by the manufacturer.

sudo rmmod ch341
sudo mv /lib/modules/$(uname -r)/kernel/drivers/usb/serial/ch341.ko /lib/modules/$(uname -r)/kernel/drivers/usb/serial/ch341.ko~

Then download the driver source from here.

Unzip it and compile the kernel module locally and install it.

cd ~/CH341SER_LINUX
sudo make 
sudo mv ch34x.ko /lib/modules/$(uname -r)/kernel/drivers/usb/serial
sudo depmod -a

Unplug the board and reconnect and reconfirm the board selection is “Arduino/Genuino Uno” and the port is properly selected in Arduino IDE and the upload should work.

 

I am currently unemployed and produce and share knowledge to help other people problems. I would like to raise some fund to get the stand alone domain for this blog. If you find these information helpful and would like to show your appreciation. Please consider Donate.

Advertisements

6 thoughts on “Fixing upload problem with Arduino Uno Clone with CH340 on Linux”

  1. Hi, the tutorial was a great find! I’m using a chinese nano, not uno. Will the code still be same? I got some errors at the sudo make stage, and its failing. If it helps, here’s the stuff…
    /CH341SER_LINUX$ sudo make
    make -C /lib/modules/4.13.0-16-generic/build M=/home/david/CH341SER_LINUX
    make[1]: Entering directory ‘/usr/src/linux-headers-4.13.0-16-generic’
    CC [M] /home/david/CH341SER_LINUX/ch34x.o
    /home/david/CH341SER_LINUX/ch34x.c: In function ‘ch34x_close’:
    /home/david/CH341SER_LINUX/ch34x.c:566:2: error: unknown type name ‘wait_queue_t’; did you mean ‘wait_event’?
    wait_queue_t wait;
    ^~~~~~~~~~~~
    wait_event
    /home/david/CH341SER_LINUX/ch34x.c:566:15: warning: unused variable ‘wait’ [-Wunused-variable]
    wait_queue_t wait;
    ^~~~
    /home/david/CH341SER_LINUX/ch34x.c:565:7: warning: unused variable ‘timeout’ [-Wunused-variable]
    long timeout;
    ^~~~~~~
    /home/david/CH341SER_LINUX/ch34x.c:564:6: warning: unused variable ‘bps’ [-Wunused-variable]
    int bps;
    ^~~
    /home/david/CH341SER_LINUX/ch34x.c: In function ‘wait_modem_info’:
    /home/david/CH341SER_LINUX/ch34x.c:772:7: error: implicit declaration of function ‘signal_pending’; did you mean ‘timer_pending’? [-Werror=implicit-function-declaration]
    if( signal_pending(current) )
    ^~~~~~~~~~~~~~
    timer_pending
    cc1: some warnings being treated as errors
    scripts/Makefile.build:309: recipe for target ‘/home/david/CH341SER_LINUX/ch34x.o’ failed
    make[2]: *** [/home/david/CH341SER_LINUX/ch34x.o] Error 1
    Makefile:1546: recipe for target ‘_module_/home/david/CH341SER_LINUX’ failed
    make[1]: *** [_module_/home/david/CH341SER_LINUX] Error 2
    make[1]: Leaving directory ‘/usr/src/linux-headers-4.13.0-16-generic’
    Makefile:5: recipe for target ‘default’ failed
    make: *** [default] Error 2

    thanks, Dave:)

    1. I am still running 4.10.0 kernel and I don’t get that error. Try to use the following command to find where wait_queue_t is.

      find /usr/src -type f -name wait.h 2>/dev/null | xargs grep -l wait_queue_t

      On my system, it is in:

      /usr/src/linux-headers-4.8.0-53/include/linux/wait.h
      /usr/src/linux-headers-4.10.0-35/include/linux/wait.h
      /usr/src/linux-headers-4.10.0-37/include/linux/wait.h

      If not use the following command to install the kernel headers.

      sudo apt-get install linux-headers-$(uname -r)

  2. In kernel 4.13.x you need a patch.

    copy the contents below to a file and run the command patch ch34x.c

    — CH341SER_LINUX/ch34x.c 2018-01-28 14:14:46.331670914 +0000
    +++ old/CH341SER_LINUX/ch34x.c 2018-01-28 14:17:56.343009512 +0000
    @@ -9,7 +9,6 @@

    // Support linux kernel version 2.6.25 and later
    //
    -// Patched to kernel 4.13.x by

    #include
    #ifndef KERNEL_VERSION
    @@ -31,7 +30,6 @@
    //#include
    #include
    #include
    -#include

    #define DRIVER_DESC “WCH CH34x USB to serial adaptor driver”
    #define DRIVER_AUTHOR “”
    @@ -565,7 +563,7 @@
    unsigned int c_cflag;
    int bps;
    long timeout;
    – wait_queue_entry_t wait;
    + wait_queue_t wait;

    #if(LINUX_VERSION_CODE number);

    1. Thanks Ronaldo. I think the diff order is reversed. Also, it would be nice if the patched file support old and new kernels like so.

      #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
      wait_queue_entry_t wait;
      #else
      wait_queue_t wait;
      #endif

  3. Thank you,
    My mistake 🙂
    I followed your suggestion of pre-processing. I updated the link with the new patch file.
    Keep up the good work.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s