jenswilly.dk


ROV power board

24. May 2013 15:12 by Jens Willy Johannsen
Categories: Projects

Here are Eagle schematic and board files as well as BOM for the ROV power board.
I moved all the high voltage/current stuff to a separate PCB and separated the control connections by using optocouplers.

That should help avoiding the electrical noise from the power MOSFETs switching at 20 kHz for the thruster motors.

BOM

Amount Item Spec RS no. Comment
1 TE Micro-MaTch 12 pos female 6804978 Or just solder wires directly to the board
1 TE Micro-MaTch 12 pos male 6804993
1 12 lead ribbon cable 2899852 This is actually 14 leads. Peel off two or use separate wires.
6 IRLS3034-7 MOSFET 6887257
6 FOD3180 optocoupler DIP-SMD 6712706
7 Screw terminals BLK 4813989
7 Screw terminals RED 4813973
6 SMD diode S5BC 7514821
6 SMD capacitor 100 µF 7472871
6 Ceramic bypass cap. 0805 0.1 µF 6480979 Or any other 0.1 µF 0805 ceramic cap.

Files

Eagle schematic and board files

Comments 2 comments »

3D printed camera holder

9. March 2013 19:43 by Jens Willy Johannsen
Categories: 3D printing

Here's another 3D printed component: a tiltable camera holder. It consists of two parts: the base and the front plate. The front plate has four standoffs with 2 mm holes for mounting the camera PCB with M2 machine screws. It also has a small bracket with a 1 mm hole for the rod that connects to the servo.

The front plate is attached to the base by M2 machine screws. The holes in the base are larger than the screws so they can rotate freely and a washer between the screw head prevents the screw head from digging into the plastic.

Here is a model of the front plate (modelled in ViaCAD 2D/3D) and the front plate and base assembled and checked for clearance when rotating in Autodesk Inventor Fusion (click for full-size):

cam_holder_model
cam_assembly

And there is the finished and assembled piece:

3D printed camera holder (click for full-size image)

3D printed camera holder (click for full-size image)

CAD files

Comments 2 comments »

Repetitive Interrupt Timer on LPC1347

9. March 2013 19:30 by Jens Willy Johannsen
Categories: ARM

For my ROV project I need to control an RC servo to tilt the camera up and down. I've gotten that working nicely using a 16-bit timer to generate an appropriate PWM waveform.

But when I change the the position by a lot – for example, going from one endpoint to the middle position – the servo moves too fast. (Which, incidentally, draws a huge current which makes my 5 V rail drop enough to reset the MAX7456 – but that is fixable.) So I need to slow the movement down by gradually changing the position instead of jumping straight from one position to another.

The full servo movement corresponds to a change in timer match value by 1000 (the PWM timer is set up so the match values correspond to PWM pulse on-time in microseconds so minimum is 1000 and maximum is 2000). I would like the full range of movement to take one second so I thought that changing the position in increments of 10 at a frequency of 100 sounds about right.

Unfortunately, I'm fresh out of timers: CT32B0 and -1 are used for motor control PWM, CT16B0 is used for periodic analog-to-digital conversions (for the pressure sensor used as depth gauge) and CT16B1 is used for servo PWM. Yeah, sure, I guess I could use a timer for more than one purpose but since the LPC1347 actually has one more timer, I might as well use that: the Repetitive Interrupt Timer.

The Repetitive Interrupt Timer (RIT for short) generates interrupts every X clock cycles and if I configure the timer to fire an interrupt every 720,000 clock cycles I get a 100 Hz interrupt (on a 72 HMz PCLK) in which I can move the servo if necessary. Nice.

This is the code I came up with:

Repetitive Interrupt Timer on LPC1347

// MIN and MAX macros
#ifndef MIN
#define MAX(a,b) (((a)>(b))?(a):(b))
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif

// Servo position variables
volatile uint16_t servo_position;
volatile uint16_t servo_target;

// Stop RI timer – otherwise we can't reset the counter
LPC_RITIMER->CTRL = 0;

// Init RI timer (we don't need to enable timer – it is always running as per the updated User Manual UM10524)
LPC_RITIMER->COMPVAL = 720000;
LPC_RITIMER->COMPVAL_H = 0;

// Reset counter (otherwise it might already be above the compare value and then it would take a loong time to overflow to zero)
LPC_RITIMER->COUNTER = 0;
LPC_RITIMER->COUNTER_H = 0;

// Set RITENCLR (clear on match), RITENBR (halt timer on debug) and RITEN (start timer)
LPC_RITIMER->CTRL = (1<< 1) | (1<< 2) | (1<< 3);

// Enable RIT interrupt
NVIC_EnableIRQ( RIT_IRQn ); 

// Interrupt routine 
// (Yes, it's a little weird that the interrupt routine is called OSTIMER but the NVIC interrupt is called RIT_IRQn)
void OSTIMER_IRQHandler()
{
    // Clear interrupt
    LPC_RITIMER->CTRL |= (1<< 0);   // Write RITINT to clear

    // If we're at target, do nothing
    if( servo_position == servo_target )
        return;

    if( servo_target > servo_position )
        servo_position += MIN( servo_target - servo_position, 10 );
    else // Not equal and not greater than, so it's less than – we don't need to check
        servo_position -= MIN( servo_position - servo_target, 10 );
}
Comments 4 comments »

SPI on LPC1347 vs capacitance

5. February 2013 22:07 by Jens Willy Johannsen
Categories: ARM

Or "Capacitance matters – who'd've thunk it"

I am using SPI to talk to a MAX7456 video overlay IC from an LPC1347 MCU in my ROV project.

That should be easy enough since the LPC1347 contains twp SPI compatible synchronous serial ports ("SSP" for short). Perusing the manual and some code examples I came up with code to initialize the SSP for SPI comms and to send SPI data.

But, alas, it didn't work :(

Connecting my trusty Saleae Logic analyzer I saw that the CS line was toggled low and then high again for every byte. Which the MAX7456 apparently doesn't like – it wants the CS line to be low for the entire command (which consists of several bytes) – just as described in the datasheet.

So I switched to manually toggling a GPIO line low before transmitting SPI data and then high again when transmission is done. Like this:

#define MAX7456_CS_ON LPC_GPIO->CLR[ 1 ] = (1<< 13)
#define MAX7456_CS_OFF LPC_GPIO->SET[ 1 ] = (1<< 13)

MAX7456_CS_ON;

spi_transfer(VM0_reg);
spi_transfer(MAX7456_reset);

MAX7456_CS_OFF;

And, for reference, the spi_transfer() function looks like this:

void spi_transfer( uint8_t data )
{
    // Wait until SSP is not busy and TX FIFO is not full
    while ( (LPC_SSP0->SR & (SSPSR_TNF|SSPSR_BSY)) != SSPSR_TNF )
        ;

    // Send data
    LPC_SSP0->DR = data;
}

But that didn't work either. Looking at the logic analyzer it turned out that CS came low several microseconds after the SPI transmission started. Weird, since the the GPIO pin is set low before I start the SPI. I also tried using the byte pin and word pin registers but the result was the same.

So it just looks like the GPIO is just really, really slow. What I finally came up with that works was this:

#define MAX7456_CS_ON { uint8_t i; LPC_GPIO->CLR[ 1 ] = (1<< 13); for( i=0; i<48; i++ ) __NOP(); }
#define MAX7456_CS_OFF LPC_GPIO->SET[ 1 ] = (1<< 13)

In other words: let the CPU wait for 48 clock cycles after setting the pin low before trying to do something else.

On the logic analyzer, it looks like this:

Logic analyzer capture. With delay.

Logic analyzer capture. With delay.

Still weird though. Until I connected a scope instead of a logic analyzer. Then it looked like this without the delay:

Scope capture. Without delay.

Scope capture. Without delay.

And this with the delay:

Scope capture. With delay.

Scope capture. With delay.

So it looks like the delay is, in fact, not the MCU's GPIO that is slow but rather capacitance. So even though the pin was toggled low the capacitance caused the voltage to decay slowly (relatively speaking) instead of instantly. So without the delay, the voltage never dropped low enough for the MAX7456 to consider the CS low. Now bear in mind that the pin is connected to the MAX7456 though the LPCXpresso board, the LPCXpresso Base Board, a jumper wire and then the MAX7456 breakout board. All of which have non-zero capacitance.

In other words: when working with high-speed (in this case 4 MHz) signals, make sure you design the board with that in mind and minimize capacitance (and inductance).

Unfortunately, I have no experience with that kind of semi-advanced PCB layout. Fortunately I can fix it in software and the delay I introduce will not pose a problem in this case.

Comments 2 comments »

Calculating stress for an acrylic disk at depth

2. February 2013 16:20 by Jens Willy Johannsen
Categories: Projects

For my ROV project, I am considering using a flat acrylic disk instead of a dome for the front "window".
So I needed to calculate if a disk of a certain diameter and thickness would hold up to the pressure exterted at a specific depth.

A couple of hours of Googling led me to these calculations and constants:

The maximum stress a uniformly supported disk is subjected to (of a given material and of a given thickness and radius) is calculated as follows (from here):

σ = 3(3 + ν)pr²
——————
8t²

Where

σ   is the maximum stress in Pa
ν   is Poisson's ratio for the material (0.37 for acrylic from here)
p   is the pressure the disk is subjected to in Pa
r   is the disk's radius in meters
t   is the thickness in meters

If the maximum stress exceeds the material's flexural strength, the disk will break.
For acrylic the flexural strength is 100 MPa (from here).

I entered the values for a 6 mm thick 110 mm diameter disk at a pressure equal to 25 meters depth and the result is that the max stress on the disk is 37 MPa. So it will hold.

You can enter your own values in the InstaCalc formula I made here: http://instacalc.com/9335.

No comments No comments »

Soft UART on LPC13xx

23. January 2013 11:32 by Jens Willy Johannsen
Categories: ARM | Projects

For the ROV project I need two UART connections (one for RS485 to the onboard controller and one for receiving input from the VNC2 USB host controller).

And since the LPC1347 only has one UART I needed a soft UART for one of the connections. Fortunately for me, NXP provides an implementation in AN10955. There was only one problem with it: it doesn't work. Or rather, it works for a while and then stops receiving anything (scoping the UART line confirmed that the VNC2 chip continued to send data so the problem had to be in the soft UART code).

Yea, intermittent errors – what's not to like… (Read on for the problem and the solution.)

Read the entire post »

Comments 2 comments »

Reading USB joystick data from Vinculum-II

30. October 2012 10:52 by Jens Willy Johannsen
Categories: General

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.

To flash the compiled firmware onto the chip I used FT-Prog
and a FTDI TTL-232R-3V3 cable connected to the VNC2 as described in this application note.

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:

  1. The VID/PID for the joystick:
    // find VID/PID of Saitek Cyborg EVO device
    hc_ioctVidPid.vid = 0x06a3;
    hc_ioctVidPid.pid = 0x0464;
  2. The parse_hid method to match your own joystick's HID descriptor.
Comments 3 comments »

Parsing USB joystick HID data

25. October 2012 23:02 by Jens Willy Johannsen
Categories: General

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.

Read the entire post »

No comments No comments »

USB joystick as input to MCU

25. October 2012 14:03 by Jens Willy Johannsen
Categories: Projects

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…

No comments No comments »