Archive for October, 2012
Success! I have managed to write and compile firmware for the FTDI Vinculum-II (VNC2) USB host IC so I can read HID reports from a Saitek Cyborg EVO joystick, parse the data into values for the X, Y, rotation and throttle axes and button states and transmit any change in values by UART which can be received by an MCU.
This is what I did:
First, I got a V2DIP1-32 development module. This is basically a VNC2 (the 32-pin version) on a PCB along with a 12 MHz crystal, a USB A socket, a 3.3 V voltage regulator, an LED and a couple of capacitors and resistors. In other words, only basic support components.
Next, I installed the Vinculum-II Toolchain (the development IDE) version 2.0.0 and then updated to SP1.
The IDE works ok. Especially the application wizard works well and gives you a good starting point for your own firmware by adding the necessary libraries, headers and scaffolding code based on your selection of IC, USB ports in use and required drivers.
But the IDE is Windows-only software… *sigh* I hate that. Fortunately I have my old MacBook Pro with Windows 7 on a Bootcamp partition.
Note: you don't need the VNC2 Debugger/Programmer Module to flash the VNC2 – the USB-to-UART cable is sufficient – even though the FTDI website states that the Debugger/Programmer module is required for initial programming.
On to the firmware itself. I did start by wasting a couple of hours by not reading the VNC2 dev board's datasheet closely enough to notice that the USB socket on the board is connected to USB port 2 and not – as I figured – port 1. After tweaking the supplied example project 'USBHostHID' and reading the documentation I pretty quickly had some firmware that did what I wanted: wait for a HID device with the specified VID/PID to be connected, read HID data, parse the data into corresponding X, Y, Rz, Z and button values and, if any values change, send the new values over the UART connection.
Here's the complete firmware project (including compiled .rom file).
And here is a sample dump of the UART output. If a line starts with a "S" it is a status message, if it starts with "E" it is an error message and otherwise it is a value update.
If you want to use this project to read data from your own joystick (and it's not a Saitek Cyborg EVO), you'll have to change:
- The VID/PID for the joystick:
// find VID/PID of Saitek Cyborg EVO device
hc_ioctVidPid.vid = 0x06a3;
hc_ioctVidPid.pid = 0x0464;
parse_hidmethod to match your own joystick's HID descriptor.
As part of using a USB joystick as input device to an MCU I needed to parse the raw HID data of the joystick into values on the various axes and button states.
This is the first time I have had to manually get from a HID descriptor and some raw data to something that makes sense.
As kind of a bigger, more long-term project I've been thinking about building a small ROV. This is in no way a novel idea – there are lots and lots og DIY ROV projects out there (Google: build your own ROV). I live by a canal in Copenhagen habour so it would be fun to have a small underwater robot to play with.
There is a lot of hardware going into a ROV project so there's lots of potential for learning new technologies. One of the components is, of course, the control input device. I figured I would forego the usual clunky four-way tact switches and use a decent USB joystick instead – a Saitek Cyborg EVO to be specific. It has pitch, roll, yaw and throttle axes as well as a thumb hat switch and about a million push buttons.
This is a USB joystick and it uses the USB HID protocol. So I need the MCU to work as a USB host. This either involves a big nasty pile of firmware code or a MCU with ROM-based USB host drivers.
My current MCU of choice, the LPC1347, does not have USB host capabilities, but its bigger (but older) brother, the LPC1768 (and other in the LPC17xx series) does have USB host drivers.
However, instead of switching to another MCU I've decided use a dedicated USB host IC. That being the FTDI Vinculum-II. This chip will handle all the USB stuff: enumerating, connecting and so on. And it will be programmed with firmware that simply echoes HID data from the joystick to the MCU using either UART or SPI.
So – off to the store to get myself a development board version of the VNC2 (this one) and we'll see if I can get it working with the joystick…
For the GPS Tracker project, I need to measure the battery voltage using the ADC but since the raw battery voltage is higher than the MCU's VCC of 3.3 V I need to use a voltage divider to get the maximum voltage below 3.3 V. (See this article on microBuilder.eu on how to do that properly.)
For the breadboard prototype I won't worry too much about power consumption but for the final version I probably should make the kind of controlled voltage divider mentioned in the microBuilder article.
When picking values for the voltage divider I want to use as much of the ADC's full range as possible to get the highest accuracy without exceeding the VDD level . If I just divided by 50% (e.g. two 10k resistors), the measured battery range would be about 0 to 2.1 V. Ideally the range should be 0 to VDD but even though the pins are 5 V tolerant in digital mode they may not exceed VDD in analog mode so I'll try with the 0 to 2.1 V range and see if that is accurate enough.
I also need to balance power consumption and accuracy. Higher value resistors pass less current through the voltage divider but lower current means lower accuracy in the ADC.
It helps to put a capacitor on the input pin so the ADC can pull current out of the capacitor if it needs more than voltage divider can provide. Like this:
E.g. 2 x 1 MΩ resistors and a 0.1 µF capacitor.
With those values, the capacitor will be charged to about ⅔ capacity in 0.2 seconds and that should be ample capacitance for the ADC to perform one measurement and since I'll be doing one-shot ADC conversions the 0.2 secs recharge time (less, actually since the capacitor will not be completely drained by a single conversion) is not a problem.
ADC conversions on LPC1347
This is what I need to do in order to perform a one-shot ADC conversion:
Initialize the ADC
- Configure pin TDI/PIO0_11 as AD0 input pin
LPC_IOCON->TDI_PIO0_11 = 0x02;
- Power up ADC analog block:
LPC_SYSCON->PDRUNCFG &= ~(1 << 4);
- Power up ADC clock:
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 13);
- Configure control register:
LPC_ADC->CR = b00000000010000000000010000000001; /* _or */ LPC_ADC->CR = (1<< 0) | (4<< 8) | (1<< 22);
The control registered is configured as follows:
|(0:7)||SEL = 1 to select AD0 pin (pin 32 on LQFP48)|
|(8:15)||CLKDIV=4 for 72MHz / 4+1 = 14.4 MHz ADC clock speed|
|(16)||BURST=0 for software-controlled conversions|
|(22)||LPWRMODE=1 to enable low-power mode that only powers up ADC circuitry when performing a conversion|
|(23)||MODE10BIT = 0 for 12 bit resolution|
|(24:26)||START = 000 – no conversion until I say so|
|(27)||EDGE – not relevant for software-controlled conversions|
Analog power and voltage reference pins are already connected on the LQFP48 package: VFREP is internally tied to VDD and VFREN is tied to VSS. Likewise for VDDa and VSSa.
Perform the conversion and read the value
LPC_ADC->CR |= (1 << 24); /* start A/D convert */ while( LPC_ADC->GDR & (1 << 31) == 0 ) /* wait until end of A/D convert */ ; LPC_ADC->CR &= 0xF8FFFFFF; /* stop ADC now (START = 000)*/ if( LPC_ADC->GDR & (1 << 30) ) /* if overrun, return zero */ return 0 ; ADC_Data = ( LPC_ADC->GDR >> 4 ) & 0xFFF; return ADC_Data; /* return A/D conversion value */
Yessiree, a MakerBot Replicator 2 3D printer. Unfortunately, there is 4-6 weeks lead time so I can't begin playing with it right away. Fortunately, that gives me time to brush up on my 3D modelling skills (this 3D printed enclosure came out pretty good though so I'm not starting from scratch).
And there's lots to learn: different types of filament, extruder settings, slicing profiles and whatnot.
Sure, I can wait. I'm not impatient for the Replicator 2 to arrive at all...
Since I had some problems gettings USB CDC working I decided to try using NXP's nxpUSBlib instead of the more simple examples that I only got almost working. But I ran into a couple of problems...
The first problem was getting the thing compiling for the LPC1347. The most recent version (0.97) does support the LPC1347 but not quite.
Having downloaded the archive and imported everything into Code Red LPCXpresso IDE as per the readme, I tried to configure the BSP (development board), CDL (CMSIS and device) and nxpUSBlib projects for the LPC1347 MCU. No problems.
But when I tried to select the LPC1347 for the Example_VirtualSerialDevice project it turned out that there was no such build configuration. There is a LPC13Uxx configuration for the Example_MassStorageDevice, however.
Success! More or less, anyway.
Using the nxpUSBlib (having made a few modifications – I'll do a post on that soon) I've managed to get USB CDC working and I got the GSM initialization and SMS receiving working.
At the moment, on receiving an SMS, the system will reply to the sender with the current GPS status regardless of the contents of the SMS.
(The GPS has no fix because it is on my workbench with no satellites in view.)
Power supply considerations
But: I need to do some careful design of the power supply. The GSM module is extremely power hungry. Especially when registering on the network or doing any other network related tasks – like sending or receiving SMSes. And the battery I'm currently using can not supply enough power for both the GSM module and (through a linear 3.3 V voltage regulator) the MCU and GPS module.
So I'll have to get a beefier battery (this 2000 mAh one) or this 6000 mAh one) and also add a low ESR capacitor (as recommended in the GSM module datasheet).
And I'll also add P-channel MOSFETs as high-side switches for the GSM and GPS modules in order to be able to switch power on and off to these modules.
At the moment I run the prototype off two separate power supplies: the 3.7 V LiPo battery directly connected to the GSM module and a 9 V battery supplying the MCU and GPS module through a 3.3 V LDO voltage regulator.