PDA

View Full Version : C# Prop Serial Boot loader example for the Silabs CP2110



tonyp12
03-11-2012, 01:32 AM
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.

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://i4.ytimg.com/vi/G2yk0gnwKEE/default.jpg
http://youtu.be/G2yk0gnwKEE

turbosupra
03-11-2012, 01:15 PM
Just to be clear, you can write to the prop using the Silabs CP2110 and c sharp?

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.






Dirty barebone version, should be easy to follow along.

It does not load an external file as of now, as the the little asm toogle program is included in the source 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.4, 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");}
}

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

buffer[0] = 0x0F9; // time sync

i = 80; // seed with "P" for the LSFR
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_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 };

int bit = 1;
int 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]+=(byte)bit;
}
bit<<=3;if (bit==512){;bit=1;buffcnt++;} // rolling bit, every 3 times move to next byte
}
}

if (CP2110_DLL.HidUart_Write(device, buffer, 203, ref j)==0){
if (j == 203){Console.WriteLine("sent 203 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

jmg
03-11-2012, 07:04 PM
Can you try varying the baud rate ?
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

tonyp12
03-11-2012, 07:23 PM
I did not have to change it as default is the values I needed anyway.

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

jazzed
03-11-2012, 09:43 PM
This is a good idea. Is it possible to find/write a driver that can be visible to the O/S as a virtual serial port?

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?

tonyp12
03-11-2012, 09:57 PM
You don't need a driver but it will not show up as a com port either.
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

turbosupra
03-11-2012, 11:17 PM
Was this a dumb question?


Just to be clear, you can write to the prop using the Silabs CP2110 and c sharp?

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.

tonyp12
03-11-2012, 11:23 PM
>Just to be clear, you can write to the prop using the Silabs CP2110 and c sharp?

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)

turbosupra
03-11-2012, 11:56 PM
That's great, I'd rather use your class. I have a c sharp program that can auto query which com port the prop is on and even check to see if more than one prop is connected to a pc, as well as send and receive variable values, but nothing that could load an eeprom file. When you say it cannot load an "external file" do you mean eeprom file or something else?



>Just to be clear, you can write to the prop using the Silabs CP2110 and c sharp?

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 some make a 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)

tonyp12
03-12-2012, 12:01 AM
>When you say it cannot load an "external file" do you mean eeprom file or something else?

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.

jazzed
03-12-2012, 12:15 AM
The path of least resistance is to have a virtual com port driver similar to the FT232.
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.



You don't need a driver but it will not show up as a com port either.
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. ....

tonyp12
03-12-2012, 12:25 AM
>virtual com port driver similar to the FT232.That's one reason why Parallax has so many units in stock.

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.

dileep254
02-04-2014, 10:00 AM
Hi tony,

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.valu e,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]

jazzed
02-04-2014, 03:57 PM
@dileep254 welcome to the forums.

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