The Attack Of The Warriors, Part 2: IO-Warrior24 - 16 Bit Multipurpose I/O Ports

Article contributed by admin on Fri, 2006-01-27 21:00

The code discussed in this article can be found here.

The IO-Warrior24 device from Code Mercenaries is equipped with 16 general purpose I/O (input/output) pins. When enabling the so-called special mode functions, more or less pins are reassigned to serve a special purpose. You can select between:

  • I2C, IIC: a two-wire serial Inter-IC-Bus allowing connection to RAMs, EEPROMs, ADCs,DACs and a lot more.
  • LCD: parallel communication with alphanumerics Liquid-Christal-Display units
  • SPI: a four-wire serial Serial-Peripheral-Interface-Bus similar to I2C
  • LED-Matrix: a serial communication bus to control LEDs in a multiplexed matrix configuration
  • RC5IR: Infrared Remote control according to the RC5 code

We'll now examine this impressive manifold of functions step-by-step. To make life a little bit easier, Code Mercenaries is offering an "IO-Warrior24 Starter Kit" providing a LED controlled by an I/O-pin, an IR receiver, and the circuit and a 16-pin connector to directly connect a LCD module. A wrap-field can be found, too - you can add your own electronic components. Below you find the assembled starter kit and wiring diagram.

Figure 1: Starter KitFigure 1: Starter Kit

Figure 2: IO-Warrior24 Wiring DiagramFigure 2: IO-Warrior24 Wiring Diagram

If everything is prepared, then connect your warrior to the USB hub and launch USBCommander. Starting with release V1.0.1.0 all IO-Warrior chips do have unique serial numbers. If multiple IO-Warriors are connected to your hub you can easily distinguish them.

Figure 3: USB Device InfoFigure 3: USB Device Info

"USB Device Info" is delivering the following information. A single configuration is present, but -- in contrast to the simple JoyWarrior -- the IO-Warrior uses two interfaces: interface 0 and interface 1. Endpoint 0 from the first interface uses two bytes for interrupt-transfer. Data is always written via a two byte control-transfer to this endpoint. All special-mode functions are managed by endpoint 0 of interface 1, but now eight bytes of data are used for control- and interrupt-transfer. Control transfer is done via SetReport requests which can be distinguished by different ReportIDs.

Writing Data to Port 0 and Port 1

Configuration 0, interface 0, and endpoint 0 is the minimal configuration for all USB devices. BeOS doesn't need the ReportID to perform a control transfer concerning this configuration. The MaxPacketSize is two bytes representing the two ports. You are able to send a report every 10 ms (i.e., Interval = 10).

Control Transfer - Interface 0
ReportID = 0x00Write Data To Port 0,1
reportPort 0Port 1
Figure 4: Control Transfer Structure

Sending data to the both ports is very easy. You create a two-byte report-field and set the individual bits to high or low level for the appropriate pins.

USBDevice dev("/dev/bus/usb/0/1/3");	// USB device
uchar report[2];

report[0] = ~(0x08); // switch on the red LED1 -> Port 0, Bit 3, on-> force pin to ground
report[1] = 0xFF; // Port 1 all pins high

ssize_t size = 0;
size = dev.ControlTransfer( USB_REQTYPE_CLASS |USB_REQTYPE_INTERFACE_OUT, // request type
0, // value
0, // index : Interface 0 (IF0)
sizeof(report), // length: 2 bytes->IF0
report); // report

printf("size written = %d

The greatest problem is to find the correct parameters concerning the control transfer - USBCommander and the header file USB_spec.h are very helpful to perform this task. Don't forget to check the returned number of bytes: It must fit the transmitted report size, otherwise something went wrong.

Reading Data from Port 0 and Port 1

This is arranged by a two-byte interrupt transfer:

Interrupt Transfer - Interface 0
ReportID = 0x00Read Data From Port 0,1
replyPort 0Port 1
Figure 5: Interrupt Transfer Structure

uchar reply[2];
const USBEndpoint *ept = dev.ActiveConfiguration()->InterfaceAt(0)->EndpointAt(0);
size = ept -> InterruptTransfer(reply,sizeof(reply)); // last pin status
size = ept -> InterruptTransfer(reply,sizeof(reply)); // actual pin status
if (size == sizeof(reply))
printf("Port 0, Port 1: 0x%02X 0x%02X
", reply[0], reply[1]);
printf("Wrong size read = %d

The terminal output from the above looks like:

Port 0, Port 1:  0xF7 0xFF  (1111 0111   1111 1111)

The small code fragment shows how to read the status of the red LED1 we switched on in the last example. First we must get access to the endpoint in order to perform an interrupt transfer. This transfer must be called twice--this seems to be a peculiarity concerning the interrupt handling of the Warrior device--an input pin status change is needed, and with Be's USB Kit, the last status is held. Normally you will not be affected by this issue when you have a thread periodically reading the status of the device.

It's possible to avoid this (mis)behavior when setting a "Special Mode Function" to get the current pin status - please have a look at chapter 5.10.4 of the data sheet.

Control Transfer - Interface 1
ReportID = 0xFFGet Current Pin Status
Figure 6: Control Transfer Structure

After sending the special report to Interface 1, the data is delivered by an eight-byte interrupt transfer.

Interrupt Transfer - Interface 1
ReportID = 0xFFStatus Of Ports P0,...,P3
reportReportIDPort 0Port 1Port 2Port 30x000x000x00
Figure 7: Interrupt Transfer Structure

uchar report2[8] = {0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
size = dev.ControlTransfer(USB_REQTYPE_CLASS |USB_REQTYPE_INTERFACE_OUT, // request type
0, // value
1, // index : Interface 1 (IF1)
sizeof(report2), // length: 8 bytes->IF1
report2); // report2
printf("size = %d
uchar reply[8];
const USBEndpoint *ept = dev.ActiveConfiguration()->InterfaceAt(1)->EndpointAt(0);
if ( (ept ->InterruptTransfer(reply,8) ) == 8)
printf(" ReportID, Port0...Port3, ...: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",

// avoid odd/even problem of USB bus manager
USB_REQUEST_SET_CONFIGURATION, 0, 1, sizeof(report2), report2);


The terminal output from that would be:

ReportID, Port0...Port3, ...:  0xFF  0xF7  0xFF  0x00  0x00  0x00  0x00 0x00

Again we are trying to get the status of the red LED1. The transfer is done by Interface 1 - keep in mind we are using a special mode. Byte number 1 and 2 of the reply-field are containing the expected result. Because the BeOS USB bus manager is suffering from the famous odd/even problem described by ITO, Takayuki we had to repeat the action twice to simulate an even number of accesses. Otherwise the program will freeze and you have to reboot. Zeta's USB stack is properly working, so you can remove the extra lines of code in your Zeta app.

After removing all pitfalls it's time to introduce IOW24_IO16, an application equipped with a nice GUI constructed with InterfaceElements.

Figure 8: IOW24_IO16 InputFigure 8: IOW24_IO16 Input Figure 9: IOW24_IO16 OutputFigure 9: IOW24_IO16 Output

Launch the application and type in the "VendorID", "ProductID" and the unique "Serial Number". Press the button "Search USB Device", and if the dedicated device is connected, the related "Product" string (see USBCommander's USB Device Info) will appear. Normally all port pins are high, but with the help of sixteen checkboxes the pins can be set individually to low level. If LEDs are connected, they will be switched on. Without additional hardware -- I added eight LEDs to Port 1 -- you can only watch our famous red LED1, Port 0, bit 3.

Now press "Start Reading" - both ports will periodically be scanned and the results will be displayed in the "Read Port" boxes. The most interesting part, however, is to stimulate the pins externally. Please press the "Output" button - the device will be switched to input mode, where all ports are set to high level and can then be pulled down to ground to indicate low level. The left image is showing the input mode and bit 7 and 6 of port 1 forced externally to ground.

The "Read Immediate" checkbox is reserved for the special mode "Get Current Pin Status". You will find out that reading is now instantaneous and the small delay of the normal reading mode has vanished. What about hot-plugging? No problem, as long as the "Read Immediate" mode isn't used. Next time we'll talk about the other special modes - stay tuned.

The Attack Of The Warriors, Part 1

Article contributed by admin on Sat, 2005-05-21 04:00

The code discussed in this article can be found here.

The warrior family MouseWarrior, KeyWarrior, JoyWarrior and IO-Warrior of the German company Code Mercenaries (www.codemercs.com) enables you to communicate with your PC via USB in a manifold way to various external devices. All members of the family are full USB V1.1/2.0 compliant, low speed devices using the HID 1.1 (Human Interface Device) device class. If you are missing the GeekPort - it's back again.

Let's start with a really simple device, the JoyWarrior24 A8-8 USB joystick controller.

Figure 1: JoyWarrior24 A8-8 USB Joystick Controller SchematicFigure 1: JoyWarrior24 A8-8 USB Joystick Controller Schematic

JoyWarrior24 A8-8 can manage three analog potentiometer axes with 8-bit resolution each. Furthermore up to eight buttons can be connected directly to the chip. But how can the joystick be controlled by BeOS? Where is the hardware driver? Don't panic--no dedicated driver is necessary for our purpose--you only need Be's USB bus manager, the raw driver, and the USB kit. However, if you really want to play "Flight" (located inside the Demos folder), then use USB Joystick Driver. So, don't hesitate, get the hardware, do some soldering and make the connection to your PC running BeOS (Code Mercenaries supports Windows, MacOS and Linux). Wait a moment - it's better to use a cost-effective 4-port USB-Hub to connect to the computer. You then will be well-prepared for the following newsletters where more USB-circuits will be introduced. The hub serves two purposes: Four USB devices can be connected simultaneously and the hub will disconnect from the PC in case of a short circuit. All connections done? Well, first launch USBCommander v0.2 - I debugged version 0.1 to enhance stability.

Figure 2: JoyWarrior24 A8-8 USB Joystick ControllerFigure 2: JoyWarrior24 A8-8 USB Joystick Controller

You see the Standard USB Hub at /0/1 and two CodeMercenaries devices. The JoyWarrior A8-8 at /0/1/2 is connected to port number 2 of the hub (ports are counted from 0 to 3, the physical port in this case is 3). Let's have a look at the USB Device Info window. We find a single configuration using a single interface and an endpoint receiving data via Interrupt-Transfer. The data size is 4 bytes and every 10 ms data can be accepted. Getting this data is done using only a few lines of code.

Figure 3: USB Device InfoFigure 3: USB Device Info

The essential lines of code of the command-line version of JoyWarrior are the followings:

  • USBDevice dev(argv[1]): the USBDevice class is initialized from a path to the raw USB device at /dev/bus/usb/0/1/2.
  • dev.SetConfiguration(dev.ConfigurationAt(0)): configure device using configuration 0.
  • const USBEndpoint *ept = dev.ActiveConfiguration()-> . . .: get access to the endpoint where all transfers are performed.
  • ept->InterruptTransfer(data,4): get 4 bytes of data via Interrupt-Transfer.

Now quit the USBCommander application and start JoyWarrior. Use the Tracker add-on "Summon" to launch a terminal related to the current directory where JoyWarrior is located, type JoyWarrior, add the path, and press Return. Then you can add or remove the jumpers or manipulate the potentiometers and observe how data is changing. You can cancel all action by typing Ctrl + C or closing the terminal.

Figure 4: JoyWarriorFigure 4: JoyWarrior

If you like it more comfortable then try StickIt, written by Be Inc. to demonstrate the new BJoystick class. The JoyWarrior device is recognized as a "Generic USB Joystick". Of course you must have installed the above mentioned driver.

Figure 5: StickItFigure 5: StickIt Figure 6: Joystick PrefletFigure 6: Joystick Preflet

If you don't like the driver then launch the GUI version of "JoyWarrior" . Don't forget to insert the proper vendor ID, product ID, and serial number. USBCommander will deliver you this information. Finally, press "Search USB Device", and if the dedicated device is present the product string will be displayed. The "Start/Stop Receiving" button is now enabled to start the communication between the joystick and your PC.

Last but not least, you can hot-plug the device. When the JoyWarrior is removed from the bus, the communication is cancelled, and after reconnecting, the device will be recognized again.

A joystick isn't an overwhelming piece of hardware and is shown here only for demonstrating purpose. The next article will deal with IO-Warrior24 and IO-Warrior40, two generic universal I/O controllers for USB... and for BeOS.

Figure 7: Hot-pluggedFigure 7: Hot-plugged Figure 8: Not-pluggedFigure 8: Not-plugged
Syndicate content