Developing PC Applications for USB-I2C Bridge AN27079 Author: Andrew Smetana Associated Project: Yes Associated Part Family: CY8C24894 Software Version: C#, Visual Basic, Delphi, C++ Associated Application Notes: AN2352 Application Note Abstract This application note describes how to use a USB-I2C bridge ActiveX control (bridge driver) in software designs. It discusses the history of ActiveX, ActiveX interface documentation, and its use in popular programming environments (languages). Introduction The USB-I2C bridge is popularly used in many applications. The bridge enables debugging the hardware and software of PSoC® applications by connecting the board to a USB port on a PC and communicating with the application’s I2C interface. The USB-I2C bridge software GUI simplifies use of the bridge. It is a powerful tool that allows you to use many of the bridge features from an easy-to-operate form. Some of these features are: Interactive communication through the I2C bus using a simple script language Configuration of the bridge and I2C bus (such as set power and speed settings) Build graphs in quasi-real time mode based on the data from the I2C device This is great, until you need to develop your own GUI using the bridge. Developing your own GUI requires an understanding of bridge protocol details, USB-HID device functionality, and Windows APIs for I/O operations. In other words, you must develop your own bridge driver. This is a lot of work for one application, especially if it is not the key function of your software. It is only a low level communication protocol. You do not have to work with low level Windows APIs to communicate with the bridge; everything is hidden inside an ActiveX control. It has bridge names (not system PnP identifiers) to address one bridge or another. It enables you to use bridge ActiveX control in different programming environments. It is a cross-language, integrating technology. You are not limited to a single development environment. Choose the language you like best. The ActiveX control is a high level abstraction of the bridge hardware, developed for programmers. A software-hardware model of a typical developer system is shown in Figure 1 on page 2; the placement of Bridge ActiveX control is also shown. It shows the “long path” between the application and target device (bridge or I2C device). ActiveX simplifies the path from application to device from the standpoint of the software developer. You need not know the details of the packet travel. The dash line is the logical connection between software and target I2C device established by the Bridge ActiveX Control. Each application works with its own instance of the ActiveX control. Two or more applications cannot work at the same time with one bridge. This is done to eliminate collisions between applications. The special ActiveX control makes it easier for you to use the bridge in your software applications. The advantages of the ActiveX bridge driver are: It is a simple software interface to the bridge hardware. You need to just call the required function of the ActiveX control to communicate with the I2C bus devices and configure the bridge. There are no complex bridge protocols. May 5, 2010 Document No. 001-27079 Rev. *A -1- [+] Feedback AN27079 Figure 1. Software-Hardware Model of Working Environment Application 1 Application 2 Bridge ActiveX Control (instance 1) Bridge ActiveX Control (instance 2) Win APIs Application N ... Hid.dll Bridge ActiveX Control (instance N) SetupAPI.dll USB Driver Stack USB Host Controller HW USB cable USB-I2C Bridge 1 I2C bus ... USB-I2C Bridge 2 I2C bus USB-I2C Bridge N I2C bus Device 1 Device 1 Device 1 Device 2 Device 2 Device 2 ... ... Device X ... Device Y Device Z ActiveX Control for a Programmer Bridge ActiveX control is implemented as an external COM-server. It is external because it is executed in its own context and implemented as a Windows executable file. It can be run only within your application. It cannot be started as an independent Windows application. Figure 2. Application and Bridge Control Architecture with ActiveX Technology C A L L E R S Application (Client) Bridge Reference A C T I O N S Bridge ActiveX Control (Server) USB-I2C interface implementation Local Events OnTransferFinished OnTransferError Sink – Events (Outgoing) Interface Implementation Source - Connection Point, referenced to Sink Events Windows Events OnBridgeConnect OnBridgeDisconnect Figure 2 clarifies the communication interface between the application and the Bridge ActiveX Control. ActiveX (COM) technology defines the application as a Client, and the ActiveX (COM) control as a Server. To start work with the Bridge Control, run the ActiveX control from your client application. Register the ActiveX control in Windows (instructions to follow) before running it. After that, your client application creates a Bridge Control instance and then it can reference the USB-I2C interface of the server in the Bridge Reference variable. Then different fragments of the client code (Callers in Figure 2) can use bridge services. These functions are discussed later. Some of them are: May 5, 2010 Win APIs (HW) Requests SendIICdata(BridgeID, SlaveAddress, Data) – sends an array of data addressed by SlaveAddress to the I2C device connected to the bridge with BridgeID. ReadIICdata(BridgeID, SlaveAddress, DataLen, Data) – reads DataLen bytes from the slave device of the BridgeID bridge. SetPower(BridgeID, PowerValue) – supply power to the bridge (+5V,+3.3V, External Power). Also shown in Figure 2 is the events (outgoing) interface. This interface can be implemented in your client application, Document No. 001-27079 Rev. *A -2- [+] Feedback AN27079 but it is optional. This interface is called Sink, and the part of the server (Bridge Control) that generates events for the client is Source. In some cases, it is useful to respond to events instead of long polling. This saves system resources and allows the processor to do more useful work. Using events, the server provides information necessary for non-synchronous operation. OnBridgeDisconnect(BridgeID) – Fires when the bridge is disconnected from the PC. OnTransferFinished(Data) – Fires when the server receives the result of an asynchronous operation. OnTransferError(ErrorCode) – Fires when an error occurs during an asynchronous operation. Figure 3 is a communication diagram of a typical session with the Bridge ActiveX Control. Usually, it consists of two stages: initialization and working process. During the initialization process, the following actions occur: As a rule, a client application interested in the server events connects its event interface (Sink) to the server, immediately after the server is created. After that, the server directs all events to the client Sink interface. The client’s Sink receives notifications from the server and executes corresponding Actions. Currently, four events are available. Only the OnBridgeConnect and OnBridgeDisconnect events can be used in your applications. The other two, TransferFinished and TransferError are used in asynchronous transactions. They are called from the bridge side as a result of asynchronous requests to the bridge services. The current Bridge ActiveX control supports only synchronous (blocking) transactions. These events cannot be used at this time. They may be added in the future. Create a new instance of ActiveX Control. Set an event mechanism between Client and Server. Call the InitUSB2IIC() function to start communication. During the working process the Client application can use any Bridge services and respond to its events. All requests from both sides (application and ActiveX Control) are blocking (synchronous). Therefore, you should not do a lot of work in the event handlers. When the application is complete or terminates the ActiveX Control does the same. It monitors its Client to know whether it is alive. If it is dead, the Server terminates as well. OnBridgeConnect(BridgeID,PnPId) – Fires when a new bridge is connected to the USB port of the PC. Figure 3. Typical Diagram of Interaction between Application and ActiveX Control Application Bridge ActiveX Control new BridgeInstance Initialization stage Connect Events InitUSB2IIC(ProcessID) Legend OnBridgeConnect(BridgeID,PnP) – Time of Object living SetPower(BridgeID,+5V) SetSpeed(BridgeID,100K) – Object doesn’t exist SendIICData(BridgeID,Addr,Data) – Object is active ReadIICData(BridgeID..Data) Working Process ... OnBridgeDisconnect(BridgeID) ExitProcess(ExitCode) ExitProcess(ExitCode) May 5, 2010 Document No. 001-27079 Rev. *A -3- [+] Feedback AN27079 2. Installing and Uninstalling The current version of ActiveX Control contains only one file, usb2iic.exe. Before initial use of the ActiveX Control in your application (or after you get an updated version), register the ActiveX control in Windows: 1. Copy the control to your hard drive, for example in C:\BridgeActiveX folder. 2. Run the ActiveX Control from the command line with a /regserver parameter: Place two buttons on the form and name the corresponding objects buttonConnect and buttonDisconnect. Change the captions on the buttons to Connect and Disconnect respectively. Your form should resemble Figure 4. Figure 4. First Application for Quick Start C:\BridgeActiveX\usb2iic.exe /regserver If the control registers successfully you will not see any messages. If none of your applications have any use for the control it is a good idea to unregister it. Do this with the following command: C:\BridgeActiveX\usb2iic.exe /unregserver 3. Doing this unregisters the ActiveX control in Windows, but it does not delete it from your machine. You can do this manually if required. Using the ActiveX Control This section describes how to use the Bridge ActiveX Control in programming languages such as C#, Visual Basic, Delphi, and C++. All functions are divided into three groups according to how they are used. All functions mentioned here are documented. The ActiveX Control has some functions that are not documented. They are used internally and they should not be used in your applications because they may be changed or eliminated in future versions of the bridge. 4. 5. Borland C++ Builder 6.0 As an exercise, create a frame (sample) application that can Connect to and Disconnect from the ActiveX component. This application is developed into a demo program later in the application note. All bridge functions explored later are included in this demo even if they are not used. 1. Find and select the USB2IIC Library component. Make sure that the Path of this component is the same as the path you used when you registered it. Click OK. Add the USB2IIC namespace to the source file. Switch into the Code View of the Form. To the end of the list of using directives add two more: Declare the Bridge variable. In the class Form1 add following code: This declares the Bridge variable of the wrapper class of the ActiveX Control. It encapsulates all functionality and the event sink of the Bridge. 6. 7. Double click on the Click event handler to generate two event handlers for the Connect and Disconnect buttons. The two event handlers are generated in the Form1 class: buttonConnect_Click buttonDisconnect_Click. Add two private methods which are event handlers for the Bridge Control: private void OnBridgeConnect(string BridgeID, string str); Start Microsoft Visual Studio and create a new Visual C# project of Windows Application (Forms) type. Name it USB2IIC_CS_Example. May 5, 2010 In the Add Reference window select the COM tab. USB2IICcom_EXEClass Bridge; Import and Initialize the ActiveX Control C# Example: The second line adds the namespace of the Type Library and wrapper class created by Visual Studio for the USB2IIC ActiveX Control. Now you can use all types and definitions from ActiveX component in this source file. Borland Delphi 7.0 Before beginning this example, be sure to install and register the Active X control as explained in Installing and Uninstalling. Select Project > Add Reference. using USB2IIC; Microsoft Visual Studio 2005 using C#, Visual Basic, and C++ (MFC) examples The demo program demonstrates the abilities of the bridge control. It is developed in all of the programming languages named earlier and is a good start point when learning to use the bridge driver. using System.Diagnostics; The following IDEs were tested for this application note: Import the USB2IIC ActiveX Control into the project. private BridgeID); Document No. 001-27079 Rev. *A void OnBridgeDisconnect(string -4- [+] Feedback AN27079 Code 1. A C# Sample Application public partial class Form1 : Form { USB2IICcom_EXEClass Bridge; public Form1() { InitializeComponent(); } private void buttonConnect_Click(object sender, EventArgs e) { if (Bridge!=null) return; // Bridge is already connected // Create Bridge Instance Bridge = new USB2IICcom_EXEClass(); // Connect Events Bridge.BridgeConnected += OnBridgeConnect; Bridge.BridgeDisconnected += OnBridgeDisconnect; // Start USB Communication Bridge.InitUSB2IIC(Process.GetCurrentProcess().Id); } private void buttonDisconnect_Click(object sender, EventArgs e) { Bridge = null; GC.GetTotalMemory(true); } private void OnBridgeConnect(string BridgeID, string str) { MessageBox.Show("Connected: " + BridgeID); } private void OnBridgeDisconnect(string BridgeID) { MessageBox.Show("Disconnected: " + BridgeID); } } The most interesting parts of this code sample are the initialization and finalization of the Bridge object. In the buttonConnect_Click method, the code first checks to see if the object exists. If it does then it exits. It does not make sense for one application to have multiple Bridge controls running. Then a new instance of the bridge wrapper class is created. Later, events are connected and communication is started. You can now connect the bridge to and disconnect the bridge from the PC and watch the attendant messages. In the buttonDisconnect_Click handler, the Bridge control is detached from the application and frees Windows resources. .NET Visual Basic Example 1. Start MS Visual Studio and create new Visual Basic project of Windows Application (Forms) type. Name it USB2IIC_VB_Example. 2. Put two buttons on the form and name the corresponding objects buttonConnect and buttonDisconnect. Change the captions on the buttons to Connect and Disconnect respectively. Your form should resemble Figure 4 on page 4. 3. Import the USB2IIC ActiveX Control into the project. Use this sample code to develop your program and use any of the Bridge functions described later. In the demo project is a class called BridgeFunctionsUsage that shows how to use each of the Bridge functions in the C# environment. 4. May 5, 2010 Select Project > Add Reference. In the Add Reference window select the COM tab. Find and select the USB2IIC Library component. Make sure that the path of this component is the same as the path you used when you registered it. Click OK. Add the USB2IIC namespace to the source file. Switch into the Code View of the Form. At the end of the list of Imports directives add two more: Document No. 001-27079 Rev. *A -5- [+] Feedback AN27079 Imports System.Diagnostics Imports USB2IIC each. There are two functions in the Form1 class: buttonConnect_Click and buttonDisconnect_Click. The second line adds the namespace of the Type Library and wrapper class created by Visual Studio for the USB2IIC ActiveX Control. It is now possible to use all types and definitions from ActiveX component in this source file. 5. 7. Add two private methods which are event handlers of Bridge Control: Sub OnBridgeConnect(ByVal BridgeID As String, ByVal Str As String) Handles Bridge.BridgeConnected Declare the Bridge variable. In the class Form1 and add following code Sub OnBridgeDisconnect(ByVal BridgeID String) Handles Bridge.BridgeDisconnected Dim WithEvents Bridge As As Code 2 shows an implementation of the event handlers added. USB2IICcom_EXE This declares the Bridge variable of wrapper class of ActiveX Control. It encapsulates all functionality and the event sink of the Bridge. 6. Generate two event handlers for Connect and Disconnect buttons. For that make left double click on Code 2. .NET Visual Basic Sample Application Imports System.Diagnostics Imports USB2IIC Public Class Form1 Dim WithEvents Bridge As USB2IICcom_EXE Private Sub buttonConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonConnect.Click 'Is Bridge is already connected? If Not (Bridge Is Nothing) Then Return 'Create Bridge Instance Bridge = New USB2IICcom_EXEClass() 'Start USB Communication Bridge.InitUSB2IIC(Process.GetCurrentProcess().Id) End Sub Private Sub buttonDisconnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonDisconnet.Click Bridge = Nothing GC.GetTotalMemory(True) End Sub Sub OnBridgeConnect(ByVal BridgeID As String, ByVal Str As String) Handles Bridge.BridgeConnected MessageBox.Show("Connected: " + BridgeID) End Sub Sub OnBridgeDisconnect(ByVal BridgeID As String) Handles Bridge.BridgeDisconnected MessageBox.Show("Disconnected: " + BridgeID) End Sub End Class The most interesting parts of this code sample are the initialization and finalization of the Bridge object. In the buttonConnect_Click method, the code first checks to see if the object exists. If it does then it exits. It does not make sense for one application to have multiple Bridge controls running. Then a new instance of the bridge wrapper class is created. Later, events are connected and communication is started. You can now connect the bridge to and disconnect the bridge from the PC and watch the attendant messages. In the buttonDisconnect_Click handler, the Bridge control is detached from your application and frees Windows resources. May 5, 2010 Use this sample code to develop your program and use any of the other Bridge functions described later. The demo project contains a class called BridgeFunctionsUsage that shows how to use each of the Bridge functions in the .Net Visual Basic environment. Delphi Example 1. Start Borland Delphi and create a new Application. 2. Create a directory with the name USB2IIC_Delphi_Example. This is your project directory. 3. Select File >Save Project As. Document No. 001-27079 Rev. *A -6- [+] Feedback AN27079 4. In the Save Unit1 As window enter the path to the project directory (USB2IIC_Delphi_Example) and click Save. 5. In the Save Project As window, select the same path as before and name the project USB2IIC_Delphi_Example and definitions from imported ActiveX components in this source file. 11. Declare the Bridge variable. In the class definition TForm1 add following code: public Bridge: TUSB2IICcom_EXE; 6. Click Save. 7. Put two buttons on the form and name the corresponding objects buttonConnect and buttonDisconnect. 8. Change their captions to Connect and Disconnect. Your form should resemble Figure 4 on page 4. 9. Import the USB2IIC ActiveX Control into the project. buttonConnectClick To do this, select Project > Import Type Library. buttonDisconnectClick In the Import Type Library window find and select the component USB2IIC Library. Make sure that the path of this component is the same as the control you registered. In the Unit Dir Name field set the path to your project directory (USB2IIC_Delphi_Example). Check Generate Component Wrapper. Click Create Unit. The USB2IIC_TLB.pas module is added to the project. This declares the Bridge variable of the wrapper class of the ActiveX Control. It encapsulates all functionality and the event sink of the Bridge. 12. Generate two event handlers for the Connect and Disconnect buttons. Double click on each button. You will get two functions in the TForm1 class: 13. Add two private methods which are event handlers of Bridge Control: procedure OnBridgeConnect (ASender:TObject; const BridgeID: WideString; const DeviceID:WideString); procedure OnBridgeDisconnect (ASender:TObject; 10. In the file Unit1.pas add the USB2IIC_TLB module to the uses clause of interface section: uses Windows, ... , USB2IIC_TLB; The definition of the ActiveX control wrapper class is added to the Unit1 module. Now you can use all types const BridgeID:WideString); Code 3 shows an implementation of all event handlers added to the Unit1.pas file. Code 3. Borland Delphi Sample Application unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, USB2IIC_TLB; type TForm1 = class(TForm) buttonConnect: TButton; buttonDisconnect: TButton; procedure buttonConnectClick(Sender: TObject); procedure buttonDisconnectClick(Sender: TObject); private { Private declarations } procedure OnBridgeConnect(ASender:TObject; const BridgeID:WideString; const DeviceID:WideString); procedure OnBridgeDisconnect(ASender:TObject; const BridgeID:WideString); public Bridge: TUSB2IICcom_EXE; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.buttonConnectClick(Sender: TObject); May 5, 2010 Document No. 001-27079 Rev. *A -7- [+] Feedback AN27079 begin if (Bridge <> nil) then exit; // Bridge is already connected // Create Bridge Instance Bridge := TUSB2IICcom_EXE.Create(nil); // Connect Events Bridge.OnBridgeConnected := OnBridgeConnect; Bridge.OnBridgeDisconnected := OnBridgeDisconnect; // Start USB Communication Bridge.InitUSB2IIC(GetCurrentProcessId()); end; procedure TForm1.buttonDisconnectClick(Sender: TObject); begin if (Bridge=nil) then exit; FreeAndNil(Bridge); end; procedure TForm1.OnBridgeConnect(ASender:TObject; const BridgeID:WideString; const DeviceID:WideString); begin MessageDlg('Connected: '+BridgeID,mtInformation,[mbOk],0); end; procedure TForm1.OnBridgeDisconnect(ASender:TObject; const BridgeID:WideString); begin MessageDlg('Disconnected: '+BridgeID,mtInformation,[mbOk],0); end; end. The most interesting parts of this code sample are the initialization and finalization of the Bridge object. In the buttonConnectClick the code first checks to see if the object exists. If it does then it exits. It does not make sense for one application to have multiple Bridge controls running. Then a new instance of the bridge wrapper class is created. Later, events are connected and communication is started. You can now connect the bridge to and disconnect the bridge from the PC and watch the attendant messages. In the buttonDisconnectClick handler, the Bridge control is detached from your application and frees Windows resources. Use this sample code to develop your program and use any of the other Bridge functions described later. The demo project contains a class called TBridgeFunctionsUsage that shows how to use each Bridge function in the Borland Delphi environment. C++ Builder Example: 1. Start Borland C++ Builder and create a new Application. Create a directory with the name USB2IIC_C++Builder_Example. This is your project directory. 2. Select File > Save Project As. 3. In the Save Unit1 As window enter the path to the previously created project directory (USB2IIC_C++Builder_Example) 7. Add two buttons to the form and name the corresponding objects buttonConnect and buttonDisconnect. 8. Change the captions on the buttons to Connect and Disconnect respectively. Your form should resemble Figure 4 on page 4. 9. Import the USB2IIC ActiveX Control into the project. Select Project > Import Type Library In the Import Type Library window find and select the component USB2IIC Library. Make sure that the path of the selected component matches the path of the ActiveX control you installed. In the Unit Dir Name field set the path to your project directory (USB2IIC_C++Builder_Example). Check Generate Component Wrapper. Click Create Unit. The project is added to the USB2IIC_TLB.cpp file. You should also see a new file in the project directory; USB2IIC_OCX.cpp. This is the wrapper class implementation. You need to add it to your project. Select Project->Add to project and select USB2IIC_OCX.cpp from the project directory. 10. In the file Unit1.h file add the USB2IIC_OCX.h header file to the end of the #include list. 4. Click Save. #include "usb2iic_ocx.h" 5. In the Save Project As window select the same path, and name the project USB2IIC_CppBuilder_Example 6. Click Save. This adds the definition of the ActiveX control’s wrapper class to the Unit1 module. Now you can use all types and definitions from the imported ActiveX components in this source file. May 5, 2010 Document No. 001-27079 Rev. *A -8- [+] Feedback AN27079 11. Declare the Bridge variable. In the class definition for TForm1, add the following code: void __fastcall OnBridgeConnect (System::TObject * Sender, public: BSTR BridgeID, BSTR DeviceID); TUSB2IICcom_EXE* Bridge; This declares the Bridge variable of the wrapper class of the ActiveX Control. It encapsulates all functionality and the event sink of the Bridge. 12. Generate two event handlers for the Connect and Disconnect buttons. Double click on each to add event handlers. There are two functions in the TForm1 class: buttonConnectClick and buttonDisconnectClick. void __fastcall OnBridgeDisconnect (System::TObject * Sender, BSTR BridgeID); Code 4 shows an implementation of all event handlers added in the Unit1.cpp file. 13. Add two private methods to the TForm1 class that will be event handlers of the Bridge Control: Code 4. Borland C++ Builder Sample Application #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------void __fastcall TForm1::buttonConnectClick(TObject *Sender) { if (Bridge != NULL) return; // Bridge is already connected // Create Bridge Instance Bridge = new TUSB2IICcom_EXE(NULL); // Connect Events Bridge->OnBridgeConnected = OnBridgeConnect; Bridge->OnBridgeDisconnected = OnBridgeDisconnect; // Start USB Communication Bridge->InitUSB2IIC(GetCurrentProcessId()); } //--------------------------------------------------------------------------void __fastcall TForm1::buttonDisconnectClick(TObject *Sender) { if (Bridge == NULL) return; delete Bridge; Bridge=NULL; } May 5, 2010 Document No. 001-27079 Rev. *A -9- [+] Feedback AN27079 //--------------------------------------------------------------------------void __fastcall TForm1::OnBridgeConnect(System::TObject * Sender, BSTR BridgeID,BSTR DeviceID) { WideString str = L"Connected: "; str += BridgeID; MessageDlg(str.c_bstr(),mtInformation,TMsgDlgButtons() << mbOK,0); } //--------------------------------------------------------------------------void __fastcall TForm1::OnBridgeDisconnect(System::TObject * Sender, BSTR BridgeID) { WideString str = L"Disconnected: "; str += BridgeID; MessageDlg(str.c_bstr(),mtInformation,TMsgDlgButtons() << mbOK,0); } The most interesting parts of this code sample are the initialization and finalization of the Bridge object. In the buttonConnect_Click method, the code first checks to see if the object exists. If it does then it exits. It does not make sense for one application to have multiple Bridge controls running. A new instance of the bridge wrapper class is created. Later, events are connected and communication is started. You can now connect the bridge to and disconnect the bridge from the PC and view the attendant messages. In the buttonDisconnect_Click handler, the Bridge control is detached from your application and frees Windows resources. IDConnect and IDDisconnect. Delete the static label in the center of the form. Arrange the form and its buttons so it is similar to Figure 4 on page 4. 4. Generate OnClick event handlers for buttons. To do this, double click on each of the event handlers. Two dummy functions, OnBnClickedConnect() and OnBnClickedDisconnect() are created in the file USB2IIC_C++MFC_ExampleDlg.cpp. These functions are implemented later. 5. Import the USB2IIC ActiveX Control into the project. Use this sample code to develop your program and use any of the other Bridge functions described later. The demo project contains a class called TBridgeFunctionsUsage that shows how to use each of the Bridge functions in the Borland C++ Builder environment. C++ MFC Example: 1. Start MS Visual Studio and create a new C++ MFC based application. Select File > New > Project. In the New Project window select Other Languages\Visual C++\MFC from the Project Types tree. In Templates select MFC Application. Name your project USB2IIC_C++MFC_Example. Specify the location of this project and click OK. 2. In the MFC Application Wizard, click on Application Type and choose Dialog based instead of the default Multiple documents. Click on User Interface Features and uncheck the About box control. Specify a title for your project, USB2IIC C++MFC Example. Click the Finish button. 3. Open the Resource View window by selecting View > Other Windows > Resource View and then open the Dialog resource. To do this, double click on the IDD_USB2IIC_CMFC_EXAMPLE_DIALOG form resource. By default, this form has two buttons, Ok and Cancel. Change the text on these two buttons to Connect and Disconnect. Change their IDs to May 5, 2010 From the Project menu, select Add Class. In the Add Class dialog, choose the MFC branch in the Categories tree. In Templates select the MFC Class From TypeLib option. Click the Add button. In the wizard, choose add class from Registry. In the Available Type Libraries list find and select USB2IIC Library <1.0>. In the Interfaces section there are two interfaces available from the USB2IIC control, they are: IUSB2IICcom_Exe and IUSB2IICcomEvents. Add only one IUSB2IICcom_Exe interface to the Generated classes section. Click Finish. The wrapper class of Bridge ActiveX control is generated and added to the project file (CUSB2IICcom_Exe.h). Note that it only implements access to the methods and properties of Bridge control, the event mechanism must be added manually. 6. Add the event sink interface to the Bridge client. On the Project menu item, select Add Class. In Add Class dialog, select MFC Class. Document No. 001-27079 Rev. *A - 10 - [+] Feedback AN27079 In the wizard, on the Name page, under Base Class, select CCmdTarget. Select the Automation option and type the name of the generated class, CUSB2IICevent_Sink. Click Finish. There are now two more files in your project: USB2IICevent_Sink.cpp and USB2IICevent_Sink.h. You must now implement the Sink class. 7. Open USB2IICevent_Sink.cpp and find line which begins as following: static {...}; const IID IID_IUSB2IICevent_Sink = Change the value of this constant to: { 0x80efe271, 0xeb62, 0x4e20, { 0x96, 0x9f, 0x23, 0x20, 0x8b, 0xe1, 0x9e, 0x10} }; This is the GUID (Globally Unique Identifier) of the IUSB2IICcomEvents interface (declared in the type library of the Bridge ActiveX). 8. In the DISPATCH_MAP of the CUSB2IICevent_Sink class, add a DISP_FUNCTION_ID macro for each of the events defined in the source interface. In this case only two events are used: BridgeConnected and BridgeDisconnected. The resulting dispatch map and corresponding event handlers appears as shown in Code 5. Code 5. Sink Interface Event Handlers in the C++ MFC Example void CUSB2IICevent_Sink::OnBridgeConnect(BSTR BridgeID, BSTR str) { CString msg = L"Connected: "; msg += BridgeID; AfxMessageBox(msg, MB_ICONINFORMATION | MB_OK); } void CUSB2IICevent_Sink::OnBridgeDisconnect(BSTR BridgeID) { CString msg = L"Disconnected: "; msg += BridgeID; AfxMessageBox(msg, MB_ICONINFORMATION | MB_OK); } BEGIN_DISPATCH_MAP(CUSB2IICevent_Sink, CCmdTarget) DISP_FUNCTION_ID(CUSB2IICevent_Sink,"BridgeConnected",1,OnBridgeConnect,VT_EMPTY, VTS_BSTR VTS_BSTR) DISP_FUNCTION_ID(CUSB2IICevent_Sink,"BridgeDisconnected",2,OnBridgeDisconnect, VT_EMPTY,VTS_BSTR) END_DISPATCH_MAP() 9. Add two prototypes for the event handlers shown in Code 5 to the CUSB2IICevent_Sink class definition (in CUSB2IICevent_Sink.h): private: void OnBridgeConnect(BSTR BridgeID, BSTR str); void OnBridgeDisconnect(BSTR BridgeID); At the end of this header file add the following external reference: extern const IID IID_IUSB2IICevent_Sink; 10. To tie all of this together, open USB2IIC_C++MFC_ExampleDlg.cpp make the following additions to the #include section: #include "CUSB2IICcom_Exe.h" #include "USB2IICevent_Sink.h" #include "afxctl.h" In the same file, declare three global variables (or members of CUSB2IIC_CMFC_ExampleDlg class): CUSB2IICcom_Exe* Bridge; CUSB2IICevent_Sink* BridgeEventSink; DWORD dwCookie; Now, implement the event handlers for the Connect and Disconnect buttons. May 5, 2010 Document No. 001-27079 Rev. *A - 11 - [+] Feedback AN27079 Code 6. Connect and Disconnect Button Event Handlers Code for the C++ MFC Example void CUSB2IIC_CMFC_ExampleDlg::OnBnClickedConnect() { if (Bridge!=NULL) return; //Initialize the COM library on the current thread CoInitialize(NULL); //Create Bridge Instance Bridge = new CUSB2IICcom_Exe(); BOOL r = Bridge->CreateDispatch(L"USB2IIC.USB2IICcom_EXE"); if (r == 0) { AfxMessageBox(L"Cann't Connect to the USB2IIC Automation Object", MB_ICONERROR | MB_OK); delete Bridge; Bridge = NULL; CoUninitialize(); return; } //Connect Events BridgeEventSink = new CUSB2IICevent_Sink(); LPUNKNOWN pUnkSink = BridgeEventSink->GetIDispatch(FALSE); r = AfxConnectionAdvise(Bridge->m_lpDispatch,IID_IUSB2IICevent_Sink, pUnkSink,FALSE,&dwCookie); if (r==0){ AfxMessageBox(L"Cann't Connect Events"); } // Start USB Communication with Bridge Bridge->InitUSB2IIC(GetCurrentProcessId()); } void CUSB2IIC_CMFC_ExampleDlg::OnBnClickedDisconnect() { if (Bridge == NULL) return; // Disconnect Events LPUNKNOWN pUnkSink = BridgeEventSink->GetIDispatch(FALSE); BOOL r = AfxConnectionUnadvise(Bridge->m_lpDispatch,IID_IUSB2IICevent_Sink, pUnkSink,FALSE,dwCookie); if (r==0){ AfxMessageBox(L"Cann't Disconnect Events"); } // Destroy Bridge Object Bridge->m_bAutoRelease = TRUE; delete Bridge; delete BridgeEventSink; Bridge = NULL; //Closes the COM library on the current thread CoUninitialize(); } The most interesting parts of this code sample are the initialization and finalization of the Bridge object. In the buttonConnect_Click method, the code first checks to see if the object exists. If it does, then it exits. It does not make sense for one application to have multiple Bridge controls running. A COM library is initialized before it calls any of the library functions. Then a new instance of the bridge wrapper class is created using the CreateDispatch method of the Bridge variable. Its parameter is ProgID of the USB2IIC Automation object (ActiveX control). It uniquely identifies this object in the system along with its GUID. The next step is to connect the events. First, the event sink object is created (which implements the event sink interface), and then the connection is established between May 5, 2010 the Sink (BridgeEventSink object) and Source (Bridge object) by means of an AfxConnectionAdvise() MFC function. You can now connect the bridge to and disconnect the bridge from the PC and view the attendant messages. In the OnBnClickedDisconnect handler the Bridge control is detached from your application and frees Windows resources. With this sample code you can develop your programs that use any other Bridge functions, described later. The demo project contains a class CBridgeFunctionsUsage that shows how to use each Bridge function in the Visual C++ environment. Document No. 001-27079 Rev. *A - 12 - [+] Feedback AN27079 Function Reference Initialization Functions InitUSB() – This function starts communication between the ActiveX Control and Bridge Hardware. It initiates the USB interface; after it completes, all other ActiveX Control functions can be called. Language Interface and Usage Example C# void InitUSB(); Bridge.InitUSB(); Visual Basic .NET Delphi Sub InitUSB() Bridge.InitUSB() procedure InitUSB; Bridge.InitUSB; C++ Builder void InitUSB(void); Bridge->InitUSB(); C++ MFC void InitUSB(); Bridge->InitUSB(); InitUSB2IIC(ProcessID) – This function does the same as InitUSB() with one exception. It has a ProcessID parameter that is the identifier of current (client) process in the Windows. Use this function instead of InitUSB() because it allows the ActiveX control to unload (terminate) if the client quits abnormally. When the client quits abnormally, the Bridge Control terminates by itself and frees resources. Language Interface and Usage Example C# void InitUSB2IIC(int ProcessID); using System.Diagnostics; ... Bridge.InitUSB2IIC(Process.GetCurrentProcess().Id); Visual Basic .NET Sub InitUSB2IIC(ByVal ProcessID As Integer) Imports System.Diagnostics ... Bridge.InitUSB2IIC(Process.GetCurrentProcess().Id) Delphi procedure InitUSB2IIC(ProcessID: SYSINT); uses Windows; ... Bridge.InitUSB2IIC(GetCurrentProcessId()); C++ Builder void InitUSB2IIC(int ProcessID); #include <Windows.h> ... Bridge->Init2USBIIC(GetCurrentProcessId()); C++ MFC void InitUSB2IIC(long ProcessID); Bridge->Init2USBIIC(GetCurrentProcessId()); UnInitUSB() – This is a satellite function to InitUSB(). Currently, it is a dummy routine, but it may be used in future versions. There is no need to call it to finish communication. May 5, 2010 Document No. 001-27079 Rev. *A - 13 - [+] Feedback AN27079 Language Interface and Usage Example C# void UnInitUSB(); Bridge.UnInitUSB(); Visual Basic Sub UnInitUSB() .NET Bridge.UnInitUSB() Delphi procedure UnInitUSB; Bridge.UnInitUSB; C++ Builder void UnInitUSB(void); Bridge->UnInitUSB(); C++ MFC void UnInitUSB(); Bridge->UnInitUSB(); Configuration and Status Functions GetBridgeList() – This function returns a list (array) of bridges currently connected to the PC. A list element is a BridgeID. This function is especially useful in the applications that do not use ActiveX events (OnBridgeConnect/OnBridgeDisconnect). Note the first element index in the array is 1 (not 0). Language Interface and Usage Example C# object GetBridgeList(); object List = Bridge.GetBridgeList(); Array bl = List as Array; int count = bl.GetLength(0); // Bridges count string s="Bridges Count:"+count.ToString()+'\n'; for (int i=1; i<=count; i++) s+=(bl.GetValue(i) as string+'\n'); MessageBox.Show(s); Visual Basic Function GetBridgeList() As Object .NET Dim List As System.Array = Bridge.GetBridgeList() Dim count = List.GetLength(0) 'Bridges count Dim s = "Bridges Count: " + count.ToString()+Chr(Keys.Return) Dim i As Integer For i = 1 To count Step 1 s += (List.GetValue(i) + Chr(Keys.Return)) Next MessageBox.Show(s) Delphi Function GetBridgeList: OleVariant; var s:string; List:OleVariant; highBound,lowBound,count,i:integer; begin List := Bridge.GetBridgeList(); highBound := VarArrayHighBound(List,1); lowBound := VarArrayLowBound(List,1); count:=highBound-LowBound+1; s:='Bridges Count: '+IntToStr(count)+#13#10; for i:=lowBound to highBound do begin s:=s+List[i]+#13#10; end; MessageDlg(s,mtInformation,[mbOk],0); end; May 5, 2010 Document No. 001-27079 Rev. *A - 14 - [+] Feedback AN27079 Language Interface and Usage Example C++ Builder TVariant GetBridgeList(void); Variant List = Bridge->GetBridgeList(); int highBound = List.ArrayHighBound(1); int lowBound = List.ArrayLowBound(1); int count = highBound - lowBound + 1; WideString str = L"Bridges Count: "; str += IntToStr(count).c_str(); str += L"\r\n"; for (int i=lowBound; i<=highBound; i++){ BSTR bridgeID = List.GetElement(i); str += bridgeID; str += L"\r\n"; } MessageDlg(str->c_bstr(),mtInformation, TMsgDlgButtons()<< mbOK, 0); delete str; C++ MFC VARIANT GetBridgeList(); VARIANT data = Bridge->GetBridgeList(); SAFEARRAY FAR *List = data.parray; long highBound, lowBound, count; SafeArrayGetUBound(List, 1, &highBound); SafeArrayGetLBound(List, 1, &lowBound); count = highBound - lowBound + 1; CString str; str.Format (L"Bridges Count: %d%s",count,L"\r\n"); for (long i=lowBound; i<=highBound; i++){ LPCTSTR bridgeID; SafeArrayGetElement(List,&i,&bridgeID); str += bridgeID; str += L"\r\n"; } AfxMessageBox(str,MB_ICONINFORMATION | MB_OK); GetBridgeStatus(WhatStatus) – This function returns the status of the last executed Bridge function or the function currently being executed (depending on parameter). Possible values of the WhatStatus parameter: 0x00 – current operation status (for asynchronous operations, currently not used) 0x01 – status of last operation (last function call) This function can be used with other functions that do not return the status of an executed operation (for example, GetDeviceList(BridgeID)). Use this function to test whether another function completed successfully, for example to see if the results of that function are valid before using the results. Language Interface and Usage Example C# sbyte GetBridgeStatus(sbyte WhatStatus); int lastError = Bridge.GetBridgeStatus(1); Visual Basic .NET Delphi Function GetBridgeStatus(ByVal WhatStatus As SByte) As SByte Dim lastError As SByte = Bridge.GetBridgeStatus(1) Function GetBridgeStatus(WhatStatus:Shortint): Shortint; var lastError:Shortint; begin lastError := Bridge.GetBridgeStatus(1); ... end; May 5, 2010 Document No. 001-27079 Rev. *A - 15 - [+] Feedback AN27079 Language Interface and Usage Example C++ Builder signed char GetBridgeStatus(signed char WhatStatus); int lastError = Bridge->GetBridgeStatus(1); C++ MFC signed char GetBridgeStatus(signed char WhatStatus); int lastError = Bridge->GetBridgeStatus(1); GetStatusMsg(MsgCode) – This function returns a description of the status code returned by an operation. This function is useful to know what a status code means. Language Interface and Usage Example C# string GetStatusMsg(int MsgCode); string msg = Bridge.GetStatusMsg(34); Visual Basic .NET Delphi Function GetStatusMsg(ByVal MsgCode As Integer) As String Dim msg As String = Bridge.GetStatusMsg(34) Function GetStatusMsg(MsgCode:SYSINT): WideString; var msg: string; begin msg := Bridge.GetStatusMsg(34); ... end; C++ Builder BSTR GetStatusMsg(int MsgCode); BSTR msg = Bridge->GetStatusMsg(34); C++ MFC CString GetStatusMsg(long MsgCode); CString msg = Bridge->GetStatusMsg(34); GetBridgeVersion(BridgeID,Version) – This function returns the version of the given bridge in the string format in the Version parameter. The result of this function is a status code of this transaction. Analyze the status code before using the Version parameter. In the case of a transaction failure the function returns the string “Unknown” and an error code as a result. Language Interface and Usage Example C# object GetBridgeVersion(string BridgeID, out object Version); object str, r; r = Bridge.GetBridgeVersion("86A4D2890E0B", out str); if ((int)r == 34) // operation finished successfully { MessageBox.Show("Version = " + str.ToString()); } Visual Basic Function GetBridgeVersion(ByVal BridgeID As String, ByRef Version As Object) .NET As Object Dim str = "", r r = Bridge.GetBridgeVersion("86A4D2890E0B", str) If (r = 34) Then 'operation finished successfully MessageBox.Show("Version = " + str.ToString()) End If Delphi Function GetBridgeVersion(const BridgeID: WideString; out Version: OleVariant): OleVariant; May 5, 2010 Document No. 001-27079 Rev. *A - 16 - [+] Feedback AN27079 Language Interface and Usage Example var r: byte; str: OleVariant; begin r := Bridge.GetBridgeVersion('86A4D2890E0B', str); if (r = 34) then // operation finished successfully MessageDlg('Version = ' + str, mtInformation, [mbOk],0); End; C++ Builder TVariant GetBridgeVersion(BSTR BridgeID, VARIANT* Version); WideString BridgeID = L"86A4D2890E0B"; Variant version; TVariant r = Bridge->GetBridgeVersion(BridgeID, version); if (r == 34) // operation finished successfully { WideString str = "Version = " + version; MessageDlg(str,mtInformation,TMsgDlgButtons() << mbOK,0); } C++ MFC VARIANT GetBridgeVersion(LPCTSTR BridgeID, VARIANT* Version); VARIANT version; VariantInit(&version); VARIANT r = Bridge->GetBridgeVersion(L"86A4D2890E0B", &version); if (r.bVal == 34) // operation finished successfully { CString str = L"Version = "; str += version.bstrVal; AfxMessageBox(str,MB_ICONINFORMATION | MB_OK); } VariantClear(&version); GetPowerSpeed(BridgeID,Power,Speed) – This function returns the Power and Speed settings of the given bridge. The result of the function is a status code of this transaction. Possible values of the Power and Speed parameters are: Power: 0x00 – The bridge does not supply power to the connected board. The board is self-powered. 0x01 – The bridge supplies +5V voltage to the connected board. 0x02 – The bridge supplies +3.3V voltage to the connected board. Speed: 0x20 – The data exchange frequency on the I2C bus bridge is 100K. 0x24 – The data exchange frequency on the I2C bus bridge is 400K. 0x28 – The data exchange frequency on the I2C bus bridge is 50K. Language Interface and Usage Example C# object GetPowerSpeed(string BridgeID, out object Power, out object Speed); object r, Power, Speed; int iPower, iSpeed; r=Bridge.GetPowerSpeed("86A4D2890E0B", out Power, out Speed); if ((int)r == 34) // operation finished successfully { iPower = (int)Power; iSpeed = (int)Speed; ... } Visual Basic Function GetPowerSpeed(ByVal BridgeID As String, ByRef Power As Object, .NET ByRef Speed As Object) As Object Dim r Dim Power As Integer = 0, Speed As Integer = 0 r = Bridge.GetPowerSpeed("86A4D2890E0B", Power, Speed) If (r = 34) Then 'operation finished successfully MessageBox.Show("Power: " + Power.ToString() + _ Chr(Keys.Return) + "Speed: " + Speed.ToString()) End If May 5, 2010 Document No. 001-27079 Rev. *A - 17 - [+] Feedback AN27079 Language Interface and Usage Example Delphi Function GetPowerSpeed(const BridgeID: WideString; out Power: OleVariant; Out Speed: OleVariant): OleVariant; var r: byte; Power,Speed: OleVariant; iPower,iSpeed: integer; begin r := Bridge.GetPowerSpeed('86A4D2890E0B', Power, Speed); if (r = 34) then begin // operation finished successfully iPower:=Power; iSpeed:=Speed; MessageDlg('Power: '+VarToStr(Power)+#13#10+ 'Speed: '+VarToStr(Speed), mtInformation,[mbOk],0); end; end; C++ Builder TVariant GetPowerSpeed(BSTR BridgeID, VARIANT* Power, VARIANT* Speed); WideString BridgeID = L"86A4D2890E0B"; Variant Power, Speed, r; r = Bridge->GetPowerSpeed(BridgeID, Power, Speed); if (r == 34) // operation finished successfully { int iPower = Power; int iSpeed = Speed; //... } C++ MFC VARIANT GetPowerSpeed(LPCTSTR BridgeID, VARIANT* Power, VARIANT* Speed); VARIANT Power, Speed, r; VariantInit(&Power); VariantInit(&Speed); r = Bridge->GetPowerSpeed(L"86A4D2890E0B", &Power, &Speed); if (r.bVal == 34) // operation finished successfully { int iPower = Power.intVal; int iSpeed = Speed.intVal; //... } VariantClear(&Power); VariantClear(&Speed); SetPower(BridgeID,Power) – This function sets the power source to the target board given by Power parameter. The possible values of Power are similar to the ones listed in the GetPowerSpeed() function. It returns a status code based on the result of this transaction. Language Interface and Usage Example C# object SetPower(string BridgeID, int Power); object r; r = Bridge.SetPower("86A4D2890E0B", 0x01); //set +5V if ((int)r != 34) { MessageBox.Show(Bridge.GetStatusMsg((int)r), "Error!", 0, MessageBoxIcon.Error); } Visual Basic May 5, 2010 Function SetPower(ByVal BridgeID As String, ByVal Power As Integer) As Object Document No. 001-27079 Rev. *A - 18 - [+] Feedback AN27079 Language .NET Delphi Interface and Usage Example Dim r = Bridge.SetPower("86A4D2890E0B", &H1) 'set +5V If (r <> 34) Then MessageBox.Show(Bridge.GetStatusMsg(r), "Error!", 0, MessageBoxIcon.Error) End If Function SetPower(const BridgeID: WideString; Power: Integer): OleVariant; var r: byte; begin r := Bridge.SetPower('86A4D2890E0B', $01); //set +5V if (r <> 34) then MessageDlg(Bridge.GetStatusMsg(r),mtError,[mbOk],0); end; C++ Builder TVariant SetPower(BSTR BridgeID, long Power); WideString BridgeID = L"86A4D2890E0B"; Variant r; r = Bridge->SetPower(BridgeID, 0x01); //set +5V if (r != 34) { MessageDlg(Bridge->GetStatusMsg(r),mtError, TMsgDlgButtons() << mbOK,0); } C++ MFC VARIANT SetPower(LPCTSTR BridgeID, long Power); VARIANT r = Bridge->SetPower(L"86A4D2890E0B", 0x01); //set +5V if (r.bVal != 34) { AfxMessageBox(Bridge->GetStatusMsg(r.bVal),MB_ICONERROR | MB_OK); } SetSpeed(BridgeID,Speed) – sets I2C bus speed in the given bridge. The possible values of Speed is the similar to the corresponding parameter of GetPowerSpeed() function. It returns status code of last (this) transaction. Language Interface and Usage Example C# object SetSpeed(string BridgeID, int Speed); object r; r = Bridge.SetSpeed("86A4D2890E0B", 0x20); //set 100K Visual Basic .NET Delphi Function SetSpeed(ByVal BridgeID As String, ByVal Speed As Integer) As Object Dim r = Bridge.SetSpeed("86A4D2890E0B", &H20) 'set 100K Function SetSpeed(const BridgeID: WideString; Speed: Integer): OleVariant; var r: byte; begin r := Bridge.SetSpeed('86A4D2890E0B', $20); //set 100K end; C++ Builder TVariant SetSpeed(BSTR BridgeID, long Speed); WideString BridgeID = L"86A4D2890E0B"; Variant r = Bridge->SetSpeed(BridgeID, 0x20); //set 100K C++ MFC VARIANT SetSpeed(LPCTSTR BridgeID, long Speed); VARIANT r = Bridge->SetSpeed(L"86A4D2890E0B", 0x20); //set 100K May 5, 2010 Document No. 001-27079 Rev. *A - 19 - [+] Feedback AN27079 ResetBridge(BridgeID) – resets I2C bus of the given bridge. This is hardware reinitialization of I2C bus in case of bus hangup. It returns status code of last (this) transaction. Language Interface and Usage Example C# object ResetBridge(string BridgeID); object r =Bridge.ResetBridge("86A4D2890E0B"); if ((int)r == 34) MessageBox.Show("I2C bus Reset Successfully!"); else MessageBox.Show(Bridge.GetStatusMsg((int)r), "Error!", 0, MessageBoxIcon.Error); Visual Basic Function ResetBridge(ByVal BridgeID As String) As Object .NET Dim r = Bridge.ResetBridge("86A4D2890E0B") If (r = 34) Then MessageBox.Show("I2C bus Reset Successfully!") Else MessageBox.Show(Bridge.GetStatusMsg(r), "Error!", 0, MessageBoxIcon.Error) End If Delphi Function ResetBridge(const BridgeID: WideString): OleVariant; var r: byte; begin r := Bridge.ResetBridge('86A4D2890E0B'); if (r = 34) then MessageDlg('I2C bus Reset Successfully', mtInformation,[mbOk],0) else MessageDlg(Bridge.GetStatusMsg(r), mtError, [mbOk],0); end; C++ Builder TVariant ResetBridge(BSTR BridgeID); WideString BridgeID = L"86A4D2890E0B"; Variant r = Bridge->ResetBridge(BridgeID); if (r == 34) MessageDlg("I2C bus Reset Successfully!",mtInformation, TMsgDlgButtons() << mbOK,0); else MessageDlg(Bridge->GetStatusMsg(r),mtError, TMsgDlgButtons() << mbOK,0); C++ MFC VARIANT ResetBridge(LPCTSTR BridgeID); VARIANT r = Bridge->ResetBridge(L"86A4D2890E0B"); if (r.bVal == 34) AfxMessageBox(L"I2C bus Reset Successfully!", MB_ICONINFORMATION | MB_OK); else AfxMessageBox(Bridge->GetStatusMsg(r.bVal), MB_ICONERROR | MB_OK); May 5, 2010 Document No. 001-27079 Rev. *A - 20 - [+] Feedback AN27079 IsPowerDetected(BridgeID,PowerStatus) – This function returns whether target board connected to the bridge is powered or not in the PowerStatus parameter. It returns a status code indicating the results of the transaction. Possible values of PowerStatus: 0x00 – The target board is not powered. 0x01 – The target board is powered. Language Interface and Usage Example C# object IsPowerDetected(string BridgeID, out byte PowerStatus); object r; sbyte PowerStatus; r = Bridge.IsPowerDetected("86A4D2890E0B", out PowerStatus); if ((int)r == 34) { if (PowerStatus == 0) MessageBox.Show("No Power Detected"); else MessageBox.Show("POWERED"); } Visual Basic Function IsPowerDetected(ByVal BridgeID As String, ByRef PowerStatus As SByte) .NET As Object Dim r Dim PowerStatus As Byte r = Bridge.IsPowerDetected("86A4D2890E0B", PowerStatus) If (r = 34) Then If (PowerStatus = 0) Then MessageBox.Show("No Power Detected") Else MessageBox.Show("POWERED") End If End If Delphi Function IsPowerDetected(const BridgeID: WideString; out PowerStatus: ShortInt): OleVariant; var r: byte; PowerStatus: Shortint; begin r := Bridge.IsPowerDetected('86A4D2890E0B', PowerStatus); if (r = 34) then begin if (PowerStatus = 0) then MessageDlg('No Power Detected',mtInformation,[mbOk],0) else MessageDlg('POWERED',mtInformation,[mbOk],0); end; end; C++ Builder TVariant IsPowerDetected(BSTR BridgeID, signed char* PowerStatus); WideString BridgeID = L"86A4D2890E0B"; signed char PowerStatus; Variant r = Bridge->IsPowerDetected(BridgeID, &PowerStatus); if (r == 34) { if (PowerStatus == 0) MessageDlg("No Power Detected",mtInformation, TMsgDlgButtons() << mbOK,0); else MessageDlg("POWERED",mtInformation, TMsgDlgButtons() << mbOK,0); } C++ MFC May 5, 2010 VARIANT IsPowerDetected(LPCTSTR BridgeID, signed char* PowerStatus); Document No. 001-27079 Rev. *A - 21 - [+] Feedback AN27079 Language Interface and Usage Example signed char PowerStatus; VARIANT r = Bridge->IsPowerDetected(L"86A4D2890E0B", &PowerStatus); if (r.bVal == 34) { if (PowerStatus == 0) AfxMessageBox(L"No Power Detected",MB_ICONINFORMATION | MB_OK); else AfxMessageBox(L"POWERED",MB_ICONINFORMATION | MB_OK); } SetTimeoutPeriod(Timeout) – This function sets the timeout for the USB transactions. This timeout is the software timeout in the ActiveX control. It triggers if no reply was received during the last transaction (the Bridge failed to answer a PC software request). This timeout is measured in the milliseconds and by default it is 1000 ms. Language Interface and Usage Example C# object SetTimeoutPeriod(int Timeout); Bridge.SetTimeoutPeriod(2000); Visual Basic .NET Delphi Sub SetTimeoutPeriod(ByVal timeout As Integer) Bridge.SetTimeoutPeriod(2000) Procedure SetTimeoutPeriod(timeout: Integer); Bridge.SetTimeoutPeriod(2000); C++ Builder void SetTimeoutPeriod(long timeout); Bridge->SetTimeoutPeriod(2000); C++ MFC void SetTimeoutPeriod(long timeout); Bridge->SetTimeoutPeriod(2000); I2C Functions GetDeviceList(BridgeID) – This function scans the I2C bus of the given bridge and returns an array of I2C devices that respond. The element zero of the array is number (N) of devices present, and the elements one to N contain the addresses of those devices. Note that the function does not return a status code. Call the GetBridgeStatus() function to determine if it completed successfully. Language Interface and Usage Example C# object GetDeviceList(string BridgeID); object List = Bridge.GetDeviceList("86A4D2890E0B"); byte[] bl = List as byte[]; int lastError = Bridge.GetBridgeStatus(1); if (lastError != 34) // failure of bus scanning MessageBox.Show(Bridge.GetStatusMsg((int)lastError), "Error!", 0, MessageBoxIcon.Error); else // bus scanned successfully { int count = bl.GetLength(0); string s = "Devices Count: " + bl.GetValue(0) + '\n'; for (int i = 1; i < count; i++) s += ("0x"+bl[i].ToString("X2") + '\n'); MessageBox.Show(s); } Visual Basic May 5, 2010 Function GetDeviceList(ByVal BridgeID As String) As Object Document No. 001-27079 Rev. *A - 22 - [+] Feedback AN27079 Language .NET Delphi Interface and Usage Example Dim List = Bridge.GetDeviceList("86A4D2890E0B") Dim lastError = Bridge.GetBridgeStatus(1) If (lastError <> 34) Then 'failure of bus scanning MessageBox.Show(Bridge.GetStatusMsg(lastError), "Error!", 0, MessageBoxIcon.Error) Else 'bus scanned successfully Dim i As Integer Dim count = List.GetLength(0) Dim s = "Devices Count: " + List(0).ToString() + _ Chr(Keys.Return) For i = 1 To count - 1 Step 1 Dim Device As Byte = List(i) s += ("0x" + Device.ToString("X2") + Chr(Keys.Return)) Next MessageBox.Show(s) End If Function GetDeviceList(const BridgeID: WideString): OleVariant; var List: OleVariant; lastError: Shortint; highBound,lowBound,count,i: byte; s:string; begin List := Bridge.GetDeviceList('86A4D2890E0B'); lastError := Bridge.GetBridgeStatus(1); if (lastError <> 34) then // failure of bus scanning MessageDlg(Bridge.GetStatusMsg(lastError),mtError,[mbOk],0) else begin // bus scanned successfully highBound := VarArrayHighBound(List,1); lowBound := VarArrayLowBound(List,1); count := highBound - lowBound + 1; s := 'Devices Count: ' + IntToStr(List[0]) + #13#10; for i:=1 to count-1 do s := s+ '0x'+IntToHex(List[i],2) + #13#10; MessageDlg(s,mtInformation,[mbOk],0); end; end; C++ Builder TVariant GetDeviceList(BSTR BridgeID); WideString BridgeID = L"86A4D2890E0B"; Variant List = Bridge->GetDeviceList(BridgeID); int lastError = Bridge->GetBridgeStatus(1); if (lastError != 34) // failure of bus scanning MessageDlg(Bridge->GetStatusMsg(lastError),mtError, TMsgDlgButtons() << mbOK,0); else // bus scanned successfully { int highBound = List.ArrayHighBound(1); int lowBound = List.ArrayLowBound(1); int count = highBound - lowBound + 1; WideString s = "Devices Count: "+IntToStr(count-1)+"\n"; for (int i = 1; i < count; i++){ int device = List.GetElement(i); s += ("0x"+IntToHex(device,2)+"\n"); } MessageDlg(s,mtInformation,TMsgDlgButtons() << mbOK,0); } C++ MFC May 5, 2010 VARIANT GetDeviceList(LPCTSTR BridgeID); Document No. 001-27079 Rev. *A - 23 - [+] Feedback AN27079 Language Interface and Usage Example VARIANT data = Bridge->GetDeviceList(L"86A4D2890E0B"); int lastError = Bridge->GetBridgeStatus(1); if (lastError != 34) // failure of bus scanning AfxMessageBox(Bridge->GetStatusMsg(lastError), MB_ICONERROR | MB_OK); else // bus scanned successfully { SAFEARRAY FAR *List = data.parray; long highBound, lowBound, count; SafeArrayGetUBound(List, 1, &highBound); SafeArrayGetLBound(List, 1, &lowBound); count = highBound - lowBound + 1; BYTE HUGEP *pDevice; CString s,strDevice; s.Format(L"Devices Count: %d\n\r",count-1); SafeArrayAccessData(List, (void HUGEP* FAR*)&pDevice); for(int i = 1; i < count; i++){ int device = pDevice[i]; strDevice.Format(L"0x%02X\r\n",device); s += strDevice; } SafeArrayUnaccessData(List); AfxMessageBox(s,MB_ICONINFORMATION | MB_OK); } SendIICdata(BridgeID,DeviceAddress,Data) – This function sends an array of byte Data to the I2C device addressed by DeviceAddress connected to the bridge given by BridgeID. It returns a status code indicating the result of the transaction. It generates Start and Stop signals on I2C bus for each transaction. Language Interface and Usage Example C# object SendIICdata(string BridgeID, int DeviceAddress, object Data); object r; byte[] data = new byte[5]; for (byte i=0; i<5; i++) data[i]=i; r = Bridge.SendIICdata("86A4D2890E0B", 0x00, data); if ((int)r != 34) // Error occurred { MessageBox.Show(Bridge.GetStatusMsg((int)r)); } else // data sent successfully { ... } Visual Basic Function SendIICdata(ByVal BridgeID As String, ByVal DeviceAddress As Integer, .NET ByVal Data As Object) As Object Dim data() = {0, 1, 2, 3, 4, 5, 6, 7} 'data to send Dim r = Bridge.SendIICdata("86A4D2890E0B", &H0, data) If (r <> 34) Then 'Error occurred MessageBox.Show(Bridge.GetStatusMsg(r)) Else 'data sent successfully ... End If Delphi Function SendIICdata(const BridgeID: WideString; DeviceAddress: Integer; Data:OleVariant): OleVariant; var r,i: byte; data: OleVariant; begin data := VarArrayCreate([0,7],varByte); for i:=0 to 7 do data[i]:=i; r := Bridge.SendIICdata('86A4D2890E0B', $00, data); if (r <> 34) then // Error occurred MessageDlg(Bridge.GetStatusMsg(r),mtError,[mbOk],0) else begin // data sent successfully ... end; end; May 5, 2010 Document No. 001-27079 Rev. *A - 24 - [+] Feedback AN27079 Language Interface and Usage Example C++ Builder TVariant SendIICdata(BSTR BridgeID, long DeviceAddress; VARIANT Data); WideString BridgeID = L"86A4D2890E0B"; Variant data; int Bounds[2] = {0,7}; data = VarArrayCreate(Bounds,1,varByte); for (int i=0; i<=7; i++) data.PutElement(2*i,i); Variant r = Bridge->SendIICdata(BridgeID, 0x00, data); if (r != 34) // Error occurred { MessageDlg(Bridge->GetStatusMsg(r),mtError, TMsgDlgButtons() << mbOK,0); } else // data sent successfully { ... } C++ MFC VARIANT SendIICdata(LPCTSTR BridgeID, long DeviceAddress, VARIANT& Data); VARIANT FAR data; SAFEARRAYBOUND rgsabound[1]; rgsabound[0].lLbound = 0; // low bound is 0 rgsabound[0].cElements = 8; // number of elements is 8 data.vt = VT_ARRAY | VT_UI1; // array of bytes data.parray = SafeArrayCreate(VT_UI1,1,rgsabound); for (long i=0; i<8; i++) { BYTE byte = (BYTE)i; SafeArrayPutElement(data.parray, &i, &byte); } VARIANT r = Bridge->SendIICdata(L"86A4D2890E0B", 0x00, data); if (r.bVal != 34) // Error occurred { AfxMessageBox(Bridge->GetStatusMsg(r.bVal), MB_ICONERROR | MB_OK); } else // data sent successfully { ... } SafeArrayDestroy(data.parray); ReadIICdata(BridgeID,DeviceAddress,DataLen,DataIn) – This function reads DataLen bytes in the array DataIn from the I2C device addressed by DeviceAddress connected to the bridge given by BridgeID. It returns a status code indicating the result of the transaction. It generates Start and Stop signals on I2C bus for each transaction. Language Interface and Usage Example C# int ReadIICdata(string BridgeID, int DeviceAddress, int DataLen, out object DataIn); int r; object dataIn; r = Bridge.ReadIICdata("86A4D2890E0B", 0x00, 5, out dataIn); byte[] data = dataIn as byte[]; if (r == 34) // data read successfully { string s = ""; for (byte i = 0; i < 5; i++) s = s + data[i] + " "; MessageBox.Show("Read 5 bytes from Device 0x00: " + s); } Visual Basic .NET May 5, 2010 Function ReadIICdata(ByVal BridgeID As String, ByVal DeviceAddress As Integer, ByVal DataLen As Integer, ByRef DataIn As Object) As Integer Document No. 001-27079 Rev. *A - 25 - [+] Feedback AN27079 Language Interface and Usage Example Dim dataIn = Nothing Dim r = Bridge.ReadIICdata("86A4D2890E0B", &H0, 5, dataIn) If (r = 34) Then 'data read successfully Dim s = "" Dim i As Integer For i = 0 To 4 Step 1 Dim ReadByte As Byte = dataIn(i) s = s + ReadByte.ToString("X2") + " " Next MessageBox.Show("Read 5 bytes from Device 0x00: " + s) End If Delphi Function ReadIICdata(const BridgeID: WideString; DeviceAddress: Integer; DataLen: Integer; out DataIn: OleVariant): Integer; var r,i:byte; dataIn: OleVariant; s:string; begin r := Bridge.ReadIICdata('86A4D2890E0B', $00, 5, dataIn); if (r = 34) then begin // data read successfully s:=''; for i:=0 to 4 do s := s + IntToHex(dataIn[i],2) + ' '; MessageDlg('Read 5 bytes from Device 0x00: ' + s, mtInformation,[mbOk],0); end; end; C++ Builder long ReadIICdata(BSTR BridgeID, long DeviceAddress; long DataLen, VARIANT* DataIn); WideString BridgeID = L"86A4D2890E0B"; Variant dataIn; Variant r = Bridge->ReadIICdata(BridgeID, 0x00, 5, dataIn); if (r == 34) // data read successfully { AnsiString s = "Read 5 bytes from Device 0x00: "; for (int i = 0; i < 5; i++) { unsigned char ReadByte = dataIn.GetElement(i); s += (IntToHex(ReadByte,2) + " "); } MessageDlg(s,mtInformation,TMsgDlgButtons() << mbOK,0); } C++ MFC long ReadIICdata(LPCTSTR BridgeID, long DeviceAddress, long DataLen, VARIANT* DataIn); VARIANT dataIn; VariantInit(&dataIn); long r = Bridge->ReadIICdata(L"86A4D2890E0B", 0x00, 5, &dataIn); if (r == 34) // data read successfully { CString s = L"Read 5 bytes from Device 0x00: "; CString strByte; for (long i = 0; i < 5; i++) { BYTE ReadByte; SafeArrayGetElement(dataIn.parray, &i, &ReadByte); strByte.Format(L"%02X ",ReadByte); s += strByte; } AfxMessageBox(s,MB_ICONINFORMATION | MB_OK); } VariantClear(&dataIn); May 5, 2010 Document No. 001-27079 Rev. *A - 26 - [+] Feedback AN27079 ReadIICdataReg(BridgeID,DeviceAddress,ReadAddress,DataLen,DataIn) – This function reads DataLen bytes in the array DataIn from the register (memory address, offset) specified by ReadAddress of the I2C device addressed by DeviceAddress connected to the bridge given by BridgeID. This function is implemented to support the Cypress I2C Port Expander with EEPROM. It can also be used with I2C devices that have similar transaction sequences on the I2C bus during read-register operation. It assumes that the I2C device has an addressable memory organization. To learn more about this device refer to the CY8C95xx data sheet and AN2304. Note that the ReadAddress parameter is an array of bytes because the address can be 1 or 2 bytes wide. It returns a status code indicating the result of the transaction. This transaction consists of two steps: 1. Generate start condition, send “DeviceAddress” and then write “ReadAdress”, but do not generate Stop at the end of this sub-transaction. 2. Generate Restart condition, send “DeviceAddress” and then read “DataLen” bytes from Device. Put Stop at the end of this sub-transaction. Two other APIs, SendIICData() and ReadIICdata(), always generate Start and Stop for their transactions. Language Interface and Usage Example C# int ReadIICdataReg(string BridgeID, int DeviceAddress, object ReadAddress, int DataLen, out object DataIn); int r; object dataIn; byte[] ReadAddress = new byte[2] { 0x01, 0x00 }; // 0x0100 EEPROM address r = Bridge.ReadIICdataReg("86A4D2890E0B", 0x5B, ReadAddress, 3, out dataIn); byte[] data = dataIn as byte[]; if (r == 34) // data read successfully { string s = ""; for (byte i = 0; i < 3; i++) s = s + data[i].ToString("X2") + " "; MessageBox.Show("Read data from addr 0x0100 of EEPROM Device 0x5B: " + s); } Visual Basic .NET Function ReadIICdataReg(ByVal BridgeID As String, ByVal DeviceAddress As Integer, ByVal ReadAddr As Object, ByVal DataLen As Integer, ByRef DataIn As Object) As Integer Dim dataIn = Nothing Dim ReadAddress() = {&H1, &H0} ' 0x0100 EEPROM's address Dim r = Bridge.ReadIICdataReg("86A4D2890E0B", &H5B, ReadAddress, 3, dataIn) If (r = 34) Then 'data read successfully Dim s = "" Dim i As Byte For i = 0 To 2 Step 1 Dim ReadByte As Byte = dataIn(i) s = s + ReadByte.ToString("X2") + " " Next MessageBox.Show("Read data from addr 0x0100 of EEPROM Device 0x5B: " + s) End If Delphi Function ReadIICdataReg(const BridgeID: WideString; DeviceAddress: Integer; ReadAddr: OleVariant; DataLen: Integer; out DataIn: OleVariant): Integer; May 5, 2010 Document No. 001-27079 Rev. *A - 27 - [+] Feedback AN27079 Language Interface and Usage Example var r,i:byte; dataIn,ReadAddress: OleVariant; s:string; begin ReadAddress := VarArrayCreate([0,1],varByte); ReadAddress[0]:=$01; ReadAddress[1]:=$00; // 0x0100 address r := Bridge.ReadIICdataReg('86A4D2890E0B', $5B, ReadAddress, 3, dataIn); if (r = 34) then begin // data read successfully s:=''; for i:=0 to 2 do s := s + IntToHex(dataIn[i],2) + ' '; MessageDlg('Read data from addr 0x0100 of EEPROM Device 0x5B:'+ s, mtInformation,[mbOk],0); end; end; C++ Builder long ReadIICdataReg(BSTR BridgeID, long DeviceAddress; VARIANT ReadAddr, long DataLen, VARIANT* DataIn); WideString BridgeID = L"86A4D2890E0B"; Variant ReadAddress; int Bounds[2] = {0,1}; ReadAddress = VarArrayCreate(Bounds,1,varByte); ReadAddress.PutElement(0x01,0); // High of 0x0100 EEPROM address ReadAddress.PutElement(0x00,1); // Low of 0x0100 EEPROM address Variant dataIn; Variant r = Bridge->ReadIICdataReg(BridgeID, 0x5B, ReadAddress, 3, dataIn); if (r == 34) // data read successfully { AnsiString s = "Read data from addr 0x0100 of EEPROM Device 0x5B: "; for (int i = 0; i < 3; i++) { unsigned char ReadByte = dataIn.GetElement(i); s += (IntToHex(ReadByte,2) + " "); } MessageDlg(s,mtInformation,TMsgDlgButtons() << mbOK,0); } C++ MFC long ReadIICdata(LPCTSTR BridgeID, long DeviceAddress, VARIANT& ReadAddr, long DataLen, VARIANT* DataIn); CByteArray baAddr; baAddr.SetSize (2); // 2 byte Address of EEPROM storage cell baAddr.SetAt(0,0x01); // High of 0x0100 EEPROM address baAddr.SetAt(1,0x00); // Low of 0x0100 EEPROM address COleVariant ReadAddress(baAddr); // Create ReadAddress argument VARIANT dataIn; VariantInit(&dataIn); long r = Bridge->ReadIICdataReg(L"86A4D2890E0B", 0x5B, ReadAddress, 3, &dataIn); if (r == 34) // data read successfully { CString s = L"Read data from addr 0x0100 of EEPROM Device 0x5B: "; CString strByte; for (long i = 0; i < 3; i++) { BYTE ReadByte; SafeArrayGetElement(dataIn.parray, &i, &ReadByte); strByte.Format(L"%02X ",ReadByte); s += strByte; } AfxMessageBox(s,MB_ICONINFORMATION | MB_OK); } VariantClear(&dataIn); May 5, 2010 Document No. 001-27079 Rev. *A - 28 - [+] Feedback AN27079 AbortTransfer() – This function aborts transactions with a bridge during asynchronous operation. It reinitializes software transfer protocol and breaks all active transactions. It closes the active bridge handle. Call this function if your software needs to free the Windows file handle of the active bridge connection to enable other applications to communicate with it. The bridge becomes active (its file handle is opened and used by this application), when you communicate with it using its BridgeID in the any of previously described functions. Language Interface and Usage Example C# void AbortTransfer(); Bridge.AbortTransfer(); Visual Basic .NET Delphi Sub AbortTransfer() Bridge.AbortTransfer() Procedure AbortTransfer; Bridge.AbortTransfer() C++ Builder void AbortTransfer(void); Bridge->AbortTransfer(); C++ MFC void AbortTransfer(); Bridge->AbortTransfer(); Demonstration Software As part of the quick start guide, a special demo program is developed, which demonstrates the features of the ActiveX control in one application. They are the most commonly used functions of the bridge driver. This application is developed in multiple programming languages to help different users to start coding with the ActiveX control quickly. Figure 5 shows the interface of the C# application. Figure 5. Demo Application of Bridge ActiveX Control In the figure, the I2C communication section sends data to or reads data from the I2C device selected in the Devices Connected to Bridge box. Data is represented in HEX format. To start this demo: 1. Run the application. 2. Click Connect. Select the Bridge from the Connected USB <-> I2C Bridges list (or connect a Bridge to USB port and then select it). 3. Set the required Bridge Power and IIC Bus Speed. 4. Click the Device List button. 5. Select the I2C device from the list. You can then use the I2C communication section. May 5, 2010 Document No. 001-27079 Rev. *A - 29 - [+] Feedback AN27079 Example of a Real Application This section is useful for engineers who are not experts in Windows programming, but need to develop some GUI software to visualize data from their I2C devices. If you are comfortable with Windows application development, skip this section. It covers general questions and recommendations about different methods of communication implementation in the C# language. C# was selected due to its popularity. If you prefer another language, this section is still useful to help you understand the basic principles and procedures used by IDEs to organize communication processes with the bridge. Each of these ways has its advantages and drawbacks. The following discussion contains some recommendations about where each of them is preferred. Many PC applications that communicate with external devices require frequent or continuous data exchange with the real world (through sensors). The applications may monitor the actual sensor’s state, build signal graphs in quasi-real time mode, and provide feedback correlation. The application described here requires continuous sensor polling; at the same time it controls the state of the LEDs. This makes it a good example of a typical application with bidirectional communication. Task Definition The application uses the I2C slave demo board from I2CUSB bridge kit (CY3240). It has two LEDs, temperature and illumination sensors onboard. At the core of this board is a CY8C21123 PSoC device, which provides an I2C interface with the host. This example develops a C# application that continuously reads the latest state of both sensors, and allows you to manipulate the state of the two LEDs. For this example, the bridge is connected to the PC 2 and has an I C slave address of zero. Solution This example demonstrates how to implement a communication process with an I2C device. It explains how to do it in three different ways: Using the Application.DoEvents() method Create a WinForm application that demonstrates the use of each of these methods. The form is shown in Figure 6. Figure 6. Real Application View In the Method group, select the I2C communication algorithm. The I2C device group manipulates the LEDs of the target device and shows the latest measured temperature and illumination of the device’s sensors. The active Bridge and actual Polling Rate (speed) calculated during communication are shown in the status bar. The Result indicates the result of the last I2C transaction. Only successfully finished transactions are taken into account to calculate the polling rate. Select any method and click the Start button, then test the I2C device section. It takes several seconds for the polling rate to be measured. Changing the state of the LEDs during this time leads to inaccuracy. It is alright, even if you do not have an I2C device available for this test. It is more important to understand the source of these methods. Click Stop to terminate communication. Comparative Analysis of the Methods Table 1 lists the basic characteristics of the methods. Using a threading approach Using a Timer resource Table 1. Communication Methods Summary Method Execution Context Transaction Initiator Working Function Speed Range Measured Speed Threading Polling Thread Application Thread Function [Low ... Fast] 195 pkts/sec Timer Main Thread System Timer of Windows Timer Event Handler [Low ... Average] 65 pkts/sec Application.DoEvents() Main Thread Application User Function [Fast ... Fastest] 250 pkts/sec Select the method that best fits your application requirements. Note that values in the Measured Speed column are not absolute. They can vary depending on factors such as PC performance and load, packet length, and bus speed. Consider them as a quality estimation of the speed rather than quantity. The values in that column are close to the maximum speed that can be reached using the corresponding method. May 5, 2010 The derivation of the results in the Measured Speed column is described in the following section. Document No. 001-27079 Rev. *A - 30 - [+] Feedback AN27079 Threading The example has a main thread and a second thread intended for communication. All actions related to I2C bus data exchange are executed in the communication thread’s function (method): public void RunProc() { while (true) { OneCommIteration(); Thread.Sleep(0); } } Timer is a convenient function to use in low speed applications. The main advantage of this method is its simplicity because there are no synchronization problems and it uses a standard control. Application.DoEvents() Application is a class that encapsulates Windows Forms support necessary for each application. This procedure is run in parallel to the main thread, so time resources of the process are divided between them. For this reason, it cannot reach the high speed of the Application.DoEvents method. The transaction initiator according to the table is the application. It is the OneCommIteration() function, which is called continuously in the infinite loop. It implements all communication details, measures speed, and displays received data on the form. Using the Sleep(x) method between transactions regulates the polling speed. Therefore, the Speed Range characteristic of this method is very wide. This universal communication method can be used in a wide range of applications. The main advantage of threading is that I2C transactions are executed in background mode while the main thread carries out its direct functions (processing events). Multithreading helps to divide the load among a pool of threads. This method can cause problems related to access of common resources from different threads. To avoid this, some synchronization is necessary. Timer In this example, a standard Windows Forms’ Timer control is used. It polls the I2C device regularly. The timing intervals cannot be small enough to get as high a speed as the other methods. In this example, the timer interval property is set to 5 ms. Theoretically, the polling speed should be 1000/5 = 200 pkts/sec. But the speed here is 65 pkts/sec. Why the difference? The timer is a Windows system resource and sends events to application WM_TIMER at regular intervals. After WM_TIMER processes this message, it calls the timer event handler. In the example it is: private void timer_Tick(object sender, EventArgs e) { OneCommIteration(); } If you run the timer with a very short period, the system can get paralyzed, doing nothing but timer event handling. To avoid this, Windows admits only one WM_TIMER event placed in the message queue of every application at any moment of time. Also, the WM_TIMER event is generated by the system only if there are no unhandled messages in the queue (excepting WM_PAINT). Thus, all other messages have a higher priority than timer does. May 5, 2010 The applications waits until Windows allows it to call the OneCommIteration() function. The application does not influence the traffic directly. DoEvents() is a static method of the Application class, which provides the ability to process messages from a queue during execution of long operations. This is a tricky method and should be use with care. The communication procedure is as follows: private void AppCommunicate() { if (fIsStarted) return; fIsStarted = true; while (fIsStarted) { OneCommIteration(); Application.DoEvents(); } } This code is initiated when you click the Start button. It is executed in the main thread until you click the Stop button (sets the fIsStarted variable to false). How does it work? Using the Application.DoEvents() method between transactions enables the application to respond to user activity. This allows the Stop button to terminate communication. If you comment out the Application.DoEvents() call in the code, the application hangs (you get only infinite bridge polling, without updating the information on the form). Why is this method the fastest? Because, it works in the context of the main thread and initiates all transactions. Note that this method does not allow you to manipulate the communication speed as easily as the other two methods. It is intended for high speed applications only. This section should help you develop your own applications that require full-functional I2C communication. Summary The USB2IIC ActiveX component helps you write software to easily interface with the USB-I2C bridge. Use parts of this application in your designs to save time in total product development. This is not the final release of the bridge software documentation. The bridge is an evolving project. This document will be update if the hardware, firmware, or the corresponding software is modified. Document No. 001-27079 Rev. *A - 31 - [+] Feedback AN27079 About the Author Name: Andrew Smetana Title: Senior Software Engineer Background: Andrew Smetana received a Master of Science degree in 2004 from National University “Lvivska Polytechnika” (Ukraine). He has 7 years experience in software development and embedded designs. His interests involve different aspects of software development: SW architecture, Windows OS, computer graphics, math, investigating and developing algorithms, conundrums, and low level system programming. He also focuses on designs from embedded world and communication protocols. Contact: [email protected] Document History Document Title: Developing PC Applications for USB-I2C Bridge Document Number: 001-27079 Revision ECN Orig. of Change Submission Date Description of Change ** 1506205 Andrew Smetana 09/24/07 New Application Note *A 2918410 Andrew Smetana 05/05/10 Updated content to describe how the following APIs generate Start/Stop/Restart signals on the I2C-bus: 1. ReadIICdata(); 2. ReadIICdataReg(); 3. SendIICdata() PSoC is a registered trademark of Cypress Semiconductor Corp. "Programmable System-on-Chip" is a trademark of Cypress Semiconductor Corp. All other trademarks or registered trademarks referenced herein are the property of their respective owners. Cypress Semiconductor 198 Champion Court San Jose, CA 95134-1709 Phone: 408-943-2600 Fax: 408-943-4730 http://www.cypress.com/ © Cypress Semiconductor Corporation, 2007-2010. The information contained herein is subject to change without notice. Cypress Semiconductor Corporation assumes no responsibility for the use of any circuitry other than circuitry embodied in a Cypress product. Nor does it convey or imply any license under patent or other rights. Cypress products are not warranted nor intended to be used for medical, life support, life saving, critical control or safety applications, unless pursuant to an express written agreement with Cypress. Furthermore, Cypress does not authorize its products for use as critical components in life-support systems where a malfunction or failure may reasonably be expected to result in significant injury to the user. The inclusion of Cypress products in life-support systems application implies that the manufacturer assumes all risk of such use and in doing so indemnifies Cypress against all charges. This Source Code (software and/or firmware) is owned by Cypress Semiconductor Corporation (Cypress) and is protected by and subject to worldwide patent protection (United States and foreign), United States copyright laws and international treaty provisions. Cypress hereby grants to licensee a personal, non-exclusive, non-transferable license to copy, use, modify, create derivative works of, and compile the Cypress Source Code and derivative works for the sole purpose of creating custom software and or firmware in support of licensee product to be used only in conjunction with a Cypress integrated circuit as specified in the applicable agreement. Any reproduction, modification, translation, compilation, or representation of this Source Code except as specified above is prohibited without the express written permission of Cypress. Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Cypress reserves the right to make changes without further notice to the materials described herein. Cypress does not assume any liability arising out of the application or use of any product or circuit described herein. Cypress does not authorize its products for use as critical components in life-support systems where a malfunction or failure may reasonably be expected to result in significant injury to the user. The inclusion of Cypress’ product in a life-support systems application implies that the manufacturer assumes all risk of such use and in doing so indemnifies Cypress against all charges. Use may be limited by and subject to the applicable Cypress software license agreement. May 5, 2010 Document No. 001-27079 Rev. *A - 32 - [+] Feedback