CH340B: How to configure internal EEPROM using libusb (Linux)? - Page 1
Forum section: electronics / projects

author: vobs
author_rank: Newbie
timestamp: March 31, 2023, 10:04:13 am
content: Dear all,I'd like to write configuration data, like serial number, product id etc., into the internal EEPROM of a CH340B USB-to-RS232 converter. Unfortunately I don't find any information about the USB interface and the related vendor or control transfers of this device. The data sheet contains the EEPROM's byte addresses, but gives not hints about EEPROM access.There is an open source project available on github, calledtools-ch340b-configuration. But this relies on some undocumented features of the device's proprietary vendor specific windows driver.I'd like to write a small command line configuration tool running under Linux and using libusb.Any information about CH340B EEPROM access using libusb would be appreciated!Regards,Volker

author: vobs
author_rank: Newbie
timestamp: April 11, 2023, 07:46:16 pm
content: Dear all,in the meantime I managed to eavesdrop on the communication between my mother's outdated Windows PC (Vista) running CH340B EEPROM config software "tools-ch340b-configuration" (available from github) and CH340B using Hantek 4032L and Sigrok's USB protocol decoder.My findings:1. Initialization sequence of USB setup/control/vendor transmissions while the PC config software was started:SETUP out: [ 40 A1 9C C3 8A D9 00 00 ][ ] : ACKSETUP out: [ 40 9A 2C 0F 07 00 00 00 ][ ] : ACKSETUP out: [ 40 A4 DF 00 00 00 00 00 ][ ] : ACKSETUP out: [ 40 A4 9F 00 00 00 00 00 ][ ] : ACKSETUP out: [ 40 9A 12 13 80 D9 00 00 ][ ] : ACKSETUP out: [ 40 9A 2C 0F EB 00 00 00 ][ ] : ACK2. Initialization sequence, sent before reading EEPROM data:SETUP out: [ 40 A1 9C C3 E8 D9 00 00 ][ ] : ACKSETUP out: [ 40 A4 DF 00 00 00 00 00 ][ ] : ACKSETUP out: [ 40 A4 9F 00 00 00 00 00 ][ ] : ACK3. Reading one Byte (0xFF) @ EEPROM address0x04(Vendor-ID low byte):SETUP in: [ C0 54 000401 A0 01 00 ]4. In Initialization sequence, sent before writing EEPROM data:SETUP out: [ 40 A1 9C C3 E8 D9 00 00 ][ ] : ACKSETUP out: [ 40 A4 DF 00 00 00 00 00 ][ ] : ACKSETUP out: [ 40 A4 9F 00 00 00 00 00 ][ ] : ACK5. Writing a byte (0xFF) to EEPROM address0x04:SETUP out: [ 40 54FF0401 A0 00 00 ][ ] : ACKSETUP out: [ 40 5E 0A 00 00 00 00 00 ][ ] : ACKThe 2nd transfer seems to activate a kind of delay as the request byte 0x5E is named CH341A_DELAY_MS in some sources.The above data bytes can be used as parameters for libusb functionlibusb_control_transfer()1st byte: bmRequestType,2nd byte: bRequest3rd byte: wValue low byte4th byte: wValue high byte5th byte: wIndex low byte6th byte: wIndex high byte7th byte: wLength low byte8th byte: wLength high byteRegards,Volker

author: quinot
author_rank: Newbie
timestamp: January 10, 2025, 06:56:59 pm
content: Hello, Were you able to create a Linux programming tool for the CH340B in the end?

author: vobs
author_rank: Newbie
timestamp: January 16, 2025, 09:43:32 am
content: Yes, and it works quite well -- for me.Unfortunately I lack the time for writing "foolprove" code and a user's manual, so I hesitate to share the software.Also the program is a very simple and quite uncomfortable command line tool that might do a lot of damage...But in my posting above you find all information required for read or write access to the ch340b eeprom by using function "libusb_control_transfer()".

author: voltsandjolts
author_rank: Unknown
timestamp: January 16, 2025, 11:57:17 am
content: This would be a good fit for a small python script which would be nicely cross-platform.It could be something based on this completely untested never run scribbling of mine:Code:try:import usb.core,usb.utilexcept ImportError as e:print("The pyusb module needs to be installed.\n""At command prompt type:\npy -m pip install pyusb\n""Also, the libusb library needs to be on the system path")CH340B_VID = 0x1a86CH340B_PID = 0x7523VENDOR_CTRL_IN = 0xC0 #USB control transfer typesVENDOR_CTRL_OUT = 0x40mydev = usb.core.find(idVendor=CH340B_VID, idProduct=CH340B_PID)if mydev is None:raise ValueError('Device not found')mydev.set_configuration()# ctrl_transfer(bmRequestType, bRequest, wValue, wIndex, payload)# where payload=byte[] for OUT transfer, or num bytes to read for IN transfer#4. In Initialization sequence, sent before writing EEPROM data:#SETUP out: [ 40 A1 9C C3 E8 D9 00 00 ][ ] : ACKmydev.ctrl_transfer(VENDOR_CTRL_OUT, 0xA1, 0xc39c, 0xd9e8, None)#SETUP out: [ 40 A4 DF 00 00 00 00 00 ][ ] : ACKmydev.ctrl_transfer(VENDOR_CTRL_OUT, 0xA4, 0x00df, 0x0000, None)#SETUP out: [ 40 A4 9F 00 00 00 00 00 ][ ] : ACKmydev.ctrl_transfer(VENDOR_CTRL_OUT, 0xA4, 0x009f, 0x0000, None)usb.util.dispose_resources(mydev)