C# Prop Serial Boot loader example for the Silabs CP2110
tonyp12
Posts: 1,951
Dirty barebone version, should be easy to follow along.
It does not load an external file as of now, the little pasm toogle program is included in the c# code.
Should be easy to change the hidlib calls to use a generic windows com port if you want to fidle with ftdi uarts.
Video of it actually working.
http://youtu.be/G2yk0gnwKEE
It does not load an external file as of now, the little pasm toogle program is included in the c# code.
Should be easy to change the hidlib calls to use a generic windows com port if you want to fidle with ftdi uarts.
Found 1 counts of UART HID devices. Connected to device number: 1 UART is: Open pulled DTR low pulled DTR high sent 251 bytes: 249,254,255,254,255,255... sent 258 bytes of $F9 as sync bits received 258 bytes: 254,255,254,254,254... Version: 1 sent 11 bytes for command: 1 sent 11 bytes for lenght (19longs) sent 203 bytes of T1/T2 encoded SpinCode sent $f9 3 times Goodbye.
/* version 0.45, programming by Tony P. The DLL is 32bit so don't forget to force x86 output in QuickSharp Tools/Options.../Build Tools/Tool Settings: "Microsoft C# 3.0 Compiler - Release" and add in common options: /platform:x86 */ //$ SLABCP2110.cs using System; using System.Threading; using SLAB_HID_TO_UART; namespace CP2110_UART { public class Program { public static void Main() { IntPtr device = IntPtr.Zero; int i = 1; uint j = 0; ushort dtr = 1<<13; // use GPIO9(opendrain) as DTR uint deviceNum= 0; ushort vid = 0x10C4; ushort pid = 0xea80; byte[] buffer = new byte[258]; // text buffer (max 4096) if(CP2110_DLL.HidUart_GetNumDevices(ref j, vid, pid)==0){ Console.WriteLine("Found " +j+ " counts of UART HID devices."); } if (CP2110_DLL.HidUart_Open(ref device, deviceNum, vid, pid)==0){ Console.WriteLine("Connected to device number: " + (deviceNum+1)); } if (CP2110_DLL.HidUart_SetUartEnable(device, i)!=0){ Console.WriteLine("could not access Device"); } if (CP2110_DLL.HidUart_GetUartEnable(device, ref i)==0){ if (i == 1){Console.WriteLine("UART is: Open");} } buffer[0] = 0x0F9; // time sync i = 80; // seed with "P" for the LSFR, prepare buffer with "secret" handshake. for(j=1; j<251; j++){ if ((i & 1)==1){ buffer[j] = 0x0ff; } else{ buffer[j] = 0x0fe; } i = i << 1 | (i >> 7 ^ i >> 5 ^ i >> 4 ^ i >> 1) & 1; // predictable random numbers } if (CP2110_DLL.HidUart_WriteLatch(device, 0 ,dtr)==0){ Console.WriteLine("pulled DTR low"); } Thread.Sleep(20); // milliseconds Timeout if (CP2110_DLL.HidUart_WriteLatch(device, dtr ,dtr)==0){ Console.WriteLine("pulled DTR high"); } Thread.Sleep(100); // milliseconds Timeout if (CP2110_DLL.HidUart_Write(device, buffer, 251, ref j)==0){ if (j == 251){Console.WriteLine("sent 251 bytes: "+buffer[0]+","+buffer[1]+","+buffer[2]+","+buffer[3]+","+buffer[4]+","+buffer[5]+"...");} } for(j=0; j<258; j++){buffer[j] = 0x0f9;} // set up 258 sync bits in one shoot as we have 480 byte fifo buffer we read later. if (CP2110_DLL.HidUart_Write(device, buffer, 258, ref j)==0){ if (j == 258){Console.WriteLine("sent 258 bytes of $F9 as sync bits");} } if (CP2110_DLL.HidUart_Read(device, buffer, 258, ref j)==0){ Console.WriteLine("received "+j+" bytes: "+buffer[0]+","+buffer[1]+","+buffer[2]+","+buffer[3]+","+buffer[4]+"..."); } i = 0; for(j=250; j<258; j++){ i = i >> 1; if (buffer[j] == 0x0ff){ i += 1 << 7; } } Console.WriteLine("Version: " + i); i = 1; //command 1=load ram, then run, 2=load ram+eeprom+verify, then shutdown, 3=load ram+eeprom+verify, then run buffer[0]=0x092; if (i==1){;buffer[0]=0x093;} if (i==2){;buffer[0]=0x09A;} if (i==3){;buffer[0]=0x09B;} buffer[1]=0x092; buffer[2]=0x092; buffer[3]=0x092; buffer[4]=0x092; buffer[5]=0x092; buffer[6]=0x092; buffer[7]=0x092; buffer[8]=0x092; buffer[9]=0x092; buffer[10]=0x0F2; if (CP2110_DLL.HidUart_Write(device, buffer, 11, ref j)==0){ if (j == 11){Console.WriteLine("sent 11 bytes for command: " + i); } } buffer[0]=0x09b; buffer[1]=0x09a; if (CP2110_DLL.HidUart_Write(device, buffer, 11, ref j)==0){ if (j == 11){Console.WriteLine("sent 11 bytes for lenght (19longs)"); } } byte[] SpinCode = { // 19longs (76 bytes) 0x00, 0xD8, 0xB8, 0x05, 0x6F, 0xDE, 0x10, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x44, 0x00, 0x58, 0x00, 0x3C, 0x00, 0x02, 0x00, 0x34, 0x00, 0x00, 0x00, 0x0A, 0xEC, 0xBF, 0xA0, 0x08, 0xE8, 0xBF, 0x68, 0x05, 0x16, 0xFC, 0xA0, 0xF1, 0x17, 0xBC, 0x80, 0x07, 0x16, 0xBC, 0xF8, 0x0A, 0xE8, 0xBF, 0x6C, 0x04, 0x00, 0x7C, 0x5C, 0xC0, 0xE1, 0xE4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x34, 0xC7, 0x08, 0x35, 0x2C, 0x32, 0x00, 0x00 }; byte bit = 1; uint buffcnt=0; for(j=0; j<258; j++){;buffer[j]=0x092;} // fill buffer with $92 for(j=0; j<76; j++) { for(i=0; i<8; i++) { if ((SpinCode[j] & 1<<i) == 1<<i) // check if bit is set { buffer[buffcnt]+=bit; // turn a %100 in to a %110 } bit<<=3; if(bit==0){; bit=1; buffcnt++;} // rolling bit if shifted out to zero, move on to next byte } } if (CP2110_DLL.HidUart_Write(device, buffer, buffcnt+1, ref j)==0){ if (j == buffcnt+1){Console.WriteLine("sent "+(buffcnt+1)+" bytes of T1/T2 encoded SpinCode");} } for(i=0; i<3; i++){ Thread.Sleep(100); // milliseconds Timeout buffer[0]=0x0f9; CP2110_DLL.HidUart_Write(device, buffer, 1, ref j); } if (j ==1){Console.WriteLine("sent $f9 " +i+" times");} Console.WriteLine("Goodbye."); } } }
Video of it actually working.
http://youtu.be/G2yk0gnwKEE
Comments
That's awesome, when do you expect to be able to load a .spin file this way? I have a c sharp GUI that interfaces with the prop, but I had not tried to write an eeprom file or anything.
You can check actual average rates by continually sending a large buffer of 55H, and using a frequency counter.
Try non std values, to see the granularity of the CP2110.
Data suggests granularity of 24MHz/(2*N), and there is some conflict over 1MBd or 500Kbd as maximum.
Valid values should be 500000/521739/545454/571428/600000/ etc
HidUart_SetUartConfig
Sets the baud rate, data bits, parity, stop bits, and flow control.
Refer to the device data sheet for a list of supported configuration settings.
DWORD baudRate, BYTE dataBits, BYTE parity, BYTE stopBits, BYTE flowControl
http://www.silabs.com/pages/DownloadDoc.aspx?FILEURL=Support Documents/TechnicalDocs/AN433.pdf
According to the CP2110.pdf System Overview, the device is "natively supported"
"The CP2110 uses the standard USB HID device class which is natively supported by most operating systems. Acustom driver does not need to be installed for this device." CP2110 rev 1.1, page 1.
Can propeller tool just find it and use DTR for reset without special code? ... Have you tried it?
All the commands are actually done with hid id report protocols.
I use Silabs Hid library to make it easier and the dll could be compiled
with it so it would still be a all-in-one exe.
Once a complete spin.binary downloader is done
the next step is to emulate a com port that will trick Spin Tool
As official CP2110 support will probably be a while as Parallax is
pretty invested in current uart ic's with 13'034 units in stock.
I'm thinking of maybe moving DTR to GPIO7 as that is an input by default.
I had it there first becuse it was an input but for some reason I went with gpio9.
I use GPIO9 and that is a push/pull output If by default it's in high state and
you press a reset button =short circuit.
My board don't have a reset button and I right away I re-program it to open drain.
btw in input and opendrain mode it have internal 100k pull-up.
There is no official DTR pin on the CP2110.
The GPIOs mode are programmed (burned) once and for all and will always stay in that mode.
The slightly harder to program direct-hid-id-report way.
http://www.silabs.com/pages/DownloadDoc.aspx?FILEURL=Support Documents/TechnicalDocs/AN434.pdf
Yes you can have regular uart chat between the Prop and your C# program through a CP2110.
And you can also program the ram/eeprom using (my) C#.
The Prop is none the wiser as it is regular uart after all.
And if someone wants to program in C / VBasic it would work with those too.
Only thing what could stop you is that it ONLY comes in QFN (0.5mm)
In prop tool Press F8 (View Info...) and you can save binary or eeprom file.
I will make it so that you can load one of these files and send it over to the prop-board using the CP2110.
Eventually I will emulate a com port and you can use Prop tool like normal.
But there is nothing stopping you using C# and programming the eeprom trough a FTDI chip either,
just follow my C# code and use com port calls instead.
P.S you don't have to use the Replay with Quote, you can just copy one or two lines like I do.
That's one reason why Parallax has so many units in stock.
Adding support for a different method in existing tools will be difficult, but not impossible.
IMHO though, Propeller Tool will never have such support. Just based on what I've seen.
The FTDI has to use a driver period, one that install a device DLL that some PCs with high security settings will balk at.
Using HID as the base gives you many options.
I will write a Virtual com port when I have time, I have to do this probono as Silabs is not paying me.
I am working with cp2114-cs42l55. my python code is below .The problem i was facing was i am not able write data into dac registers and read it back from i2c interface.can u help me if u have any idea
import ctypes
import time
import os
os.system("cls")
mydll=ctypes.OleDLL("C:\Python27\SLABHIDtoUART.dll")
mydk=ctypes.OleDLL("C:\Python27\SLABHIDDevice.dll")
SI_SUCCESS =0x00;
j=0;
vid=0x10C4;
pid=0xEAB0;
devicenum=0;
k = ctypes.c_ulong();
R=ctypes.pointer(k);
c=ctypes.c_uint()
m=ctypes.pointer(c)
ro=ctypes.c_ulong();
rd=ctypes.pointer(ro);
kbuf =ctypes.create_string_buffer(255)
B=ctypes.pointer(kbuf)
status = mydll.HidUart_GetNumDevices(R,vid,pid);
print "status is " + str(status)
pk=ctypes.c_ulong();
D=ctypes.pointer(pk);
no=ctypes.c_ulong();
dw=ctypes.pointer(no);
if status != SI_SUCCESS:
print "No of devices found is error "
print k.value
########opening the device
op=mydll.HidUart_Open(m,devicenum,vid,pid)
print "op is " +str(op)
print c.value
enable=mydll.HidUart_SetUartEnable(c.value,1)
print "enable is " +str(enable)
##Getenable=mydll.HidUart_GetUartEnable(c.value,D)
##print Getenable
##print pk.value
##buff=mydll.HidUart_FlushBuffers(c.value,1,1)
##setuartconfig=mydll.HidUart_SetUartConfig(c.value,115200,0x03,0x00,0x00,0x00)
##print "set uart config is "+str(setuartconfig)
##
##setusbconfig=mydll.HidUart_SetUsbConfig(c.value,0x10C4,0xEAB0,0x32,0x00,0100,0x05,0x01)
Gpio=(ctypes.c_ulong*14)()
Gpio[0]=0x03
Gpio[1]=0x03
Gpio[2]=0x03
Gpio[3]=0x03
Gpio[4]=0x03
Gpio[5]=0x04
Gpio[6]=0x04
Gpio[7]=0x04
Gpio[8]=0x04
Gpio[9]=0x03
Gpio[10]=0x04
Gpio[11]=0x03
Gpio[12]=0x02
Gpio[13]=0x02
PGpio=ctypes.pointer(Gpio)
pinconf=mydll.CP2114_SetPinConfig(m.contents,PGpio,0,0x0000,0x0000,0x00)
print "pincnf" + str(pinconf)
Ram=(ctypes.c_ulong*32)()
Ram[0]=0x1E
Ram[1]=0x00
Ram[2]=0x01
Ram[3]=0x00
Ram[4]=0x94
Ram[5]=0xA6
Ram[6]=0xC4
Ram[7]=0x0C
Ram[8]=0x01
Ram[9]=0xE0
Ram[10]=0x1C
Ram[11]=0x1D
Ram[12]=0x1A
Ram[13]=0x1B
Ram[14]=0x1C
Ram[15]=0x1D
Ram[16]=0x1A
Ram[17]=0x1B
Ram[18]=0x70
Ram[19]=0x77
Ram[20]=0x44
Ram[21]=0x0C
Ram[22]=0x00
Ram[23]=0x00
Ram[24]=0x00
Ram[25]=0x00
Ram[26]=0x00
Ram[27]=0x00
Ram[28]=0x00
Ram[29]=0x00
Ram[30]=0x00
Ram[31]=0x00
##Ram[32]=0x94
##Ram[33]=0x10
Ramp=ctypes.pointer(Ram)
RA=mydll.CP2114_SetRamConfig(m.contents,Ramp)
print "RA is "+str(RA);
##time.sleep(4)
##os.startfile('song.wav')
##GRam=(ctypes.c_ulong*32)(255)
##GRamp=ctypes.pointer(GRam)
##
####
##GRA=mydll.CP2114_GetRamConfig(c.value,GRamp)
##print "GRA is "+str(GRA)
##
##print GRamp.contents[0],GRamp.contents[1],GRamp.contents[2],GRamp.contents[3]
##
##
##time.sleep(2)
dac=(ctypes.c_ulong*8)()
dac[0]=0x02;
dac[1]=0x0F
dacp=ctypes.pointer(dac)
IC=mydll.CP2114_SetDacRegisters(m.contents,dacp,2)
print "IC status is "+str(IC)
time.sleep(10)
Gdac=(ctypes.c_ulong*8)()
Gdacp=ctypes.pointer(Gdac)
DC=mydll.CP2114_GetDacRegisters(m.contents,0x02,4,Gdacp)
print "DC status is "+str(DC)
print Gdacp.contents[0],Gdacp.contents[1],Gdacp.contents[2],Gdacp.contents[3]
To preserve code indenting for Python, add your code between the [code ] [/code ] tags (no spaces in the tags).
See this link for an example: http://forums.parallax.com/misc.php?do=bbcode#code