Cupric Chloride is Green!

Wow – after an extra couple of days’ aeration (with extra acid during that time), the etch bath is beautiful light green in the drop-on-white test.  It’s ready to go!  I’m really curious whether the acid had any effect on how long it took to “green up”.  Guess I’ll never know.  Now I need some boards to etch!

Posted in Cupric Chloride Etchant | Leave a comment

Educube Performance Update

After digging into I²C protocol some more I felt armed to hack the MultiSerial library to do multi-byte reads and writes.  I added 2 user level functions – writeMulti() and readBuf().  I had to add 2 more internal functions – the ones that talk to the Wire lib.  But as I tried to write the internal msWriteRegisterMulti() and msReadRegisterBuf(), while Wire did seem to support multi-byte operations, the bits I needed weren’t exposed as public.

OK – if I have to I’ll make a private Wire.h with more things exposed.  But that wasn’t enough:  the code used by Wire isn’t in wire.cpp – it’s in the underlying twi.cpp!  I really didn’t want to make a private version of that, too!

Google and I could find little or nothing about heavy use of Wire (and twi) for making other libs like the one I needed.  But I finally figured out how it actually works – and by working with the system, everything I needed was there.  I put crude versions of all the routines in.  No sanity checking, no error returns.  Use it perfectly and it works.  Else – no promises.

Wrapping my application level routines – writeMsg() and rxpoll() in millis() timers, I got some numbers.  All are for sending/receiving a 27 byte message.

byte-at-a-time send: 330 ms       multi-byte send:  4 ms

byte-at-a-time read: 800 ms       multi-byte read:  7 ms

So how fast will it go end to end?  I got up to about 1300 B/sec, but if I went faster the receive routine locked up.  I suppose I should start handling some error conditions more gracefully 🙂

That’s plenty fast for the target applications, but not so much for bulk downloading of applications/problem sets/whatever via IR.

I sent a little update note to the original author of the lib and learned she was having performance problems with a VGA shield she was making and using I²C to talk to.  So my multi-byte efforts may be the starting point for a performance boost for Strich Labs as well!

Posted in W88 Educubes | 4 Comments

Cupric Chloride Etchant Getting Closer

When I looked at the jar on 4/17/11, it was just kind of ugly brown, even though it had been on the bubbler for days.  I started to look a little closer, making measurements and doing a little math.  So much for not wanting a chemistry project 🙂

I dug out an old automotive hydrometer and extrapolating a little beyond its 1.300 max reading, it looks like the bath’s specific gravity is ~1.33.  That’s comfortably in the normal working range.

OK – how much of the acid have I used up making CuCl2?  Taking the simplified equation 2 HCl + Cu + O -> CuCl2 +H2O and molecular weight of HCl as 36.5, and Cu at wt 63.5, that’s 73 g HCl for every 63.5 g of Cu.  I put 86 g of wire in and etched a couple of boards for maybe another gram.  So, (87/63.5) *73 = 100 g of HCl.

How much was in there?  The acid is just about 10M, so that’s 10*36.5 g HCl per liter.  The initial batch was 8 fl 0z of acid (238 ml) and I added another 130 ml later, for a total of 368 ml of acid.  That gives 0.368 l * 365g/l= 134 g HCl.  So I’ve used up most, but not all of it.  If I have 34 g left, my bath – which is now about 380 ml (using a duplicate of the jar, noting the level and measuring water from the 2nd jar filled to that level), that’s about 34/.38= 89 g/l.  Dividing by 36.5 g/mole, that should be about 2.45M – which again is comfortably in the usable range.

Looking at the stuff today, it looks greener – though still very dark.  Using the drop-on-a-white-surface test, it still looks like > 10g/l Cu+1.  Not sure why, unless the bubbler just isn’t done oxidizing the Cu+1 to Cu+2 yet.  Or I’ve made some other mistake 🙂

One sobering thing is the tank volume in Seychell’s chart:  It says you need about 0.016 l of fresh etchant per cm² of 1oz copper clad board at 50% etch before regeneration.  The latter  2 are just about what I do.  So a typical shield at 6cm x 8cm will use 0.76 l of etchant – and that’s more than I have!  Don’t know how much it will slow down, or how much  bubbling during etching would help.  Or whether I just need to strip a bunch more wire and make more etchant.  I guess this stuff isn’t quite as ideal as I’d hoped.  Or at least my expectations weren’t very appropriate.

Making 1M NaOH

Next up is titrating the stuff.  Since I happen to need 500ml of 1% NaOH for developer, I’ll start with the 5 g of NaOH that will take and make however much 1M titrant it makes.  That would be – at 40 g/l for 1M – 5/40 l, or 125 ml.  Since I only need a few ml of that, I’ll dilute whatever is left up to my 500 ml and call it developer.  Two birds.

It’ll end up here anyway

It’s all going into the developer bottle anyway, so I might as well mix it there.

Ready to go

I found a nice 1ml syringe and put just 1ml of etchant into ~25ml hot water.  Pretty blue, just like in Seychell’s pictures.  The water volume doesn’t matter too much – it’s just the absolute amount of etchant that we’re reacting with.

Near endpoint

The process was interesting.  The endpoint – slightly cloudy despite swirling the syringe around – was pretty obvious.  And the answer is: 1.45M.  So the math above was only in the ball park, but not very close.

So – what do I need to do?  1.45M is OK, but I’ll shoot for higher on the charts.  The higher I go the lower the Cu+2 concentration for whatever copper is there now, so let’s not overdo.  I’ll shoot for 3M.  From Seychell’s acid control section, starting with 0.38L, final concentration 3M, initial concentration 1.45M and using 10M acid, I get 0.38*(3-1.45)/(10-3)=0.084l.  So I’ve added 84 ml of fresh acid – and I’ll let it bubble on.  No, I’m not going to titrate it again.  But I did do the drop test again and it was more green and less brown – between 1 and 4 g/l –  but still far from the clear green we’re looking for.  I’ll check back in a couple of days.

freshdevcleanbottle-4128Update 8/9/16: Not that this is the best place for it, but…  I needed to make some more developer today.  The quantities indicated on the label were most welcome.   Unfortunately, the bottle had some significant white deposits inside that didn’t rinse out.  I tried some boric acid and that helped, but didn’t do the whole job.  Then I used maybe 25ml of very approximately 3M HCl.  (A few pipette tips from the 30M jug into some water in the bottle – very much seat of the pants.)  Sorry for no pics of the bottle.  With a few tens of minutes, that worked quite well.  Bottle is full again and looks nice again.

Posted in Cupric Chloride Etchant | Leave a comment

Cupric Chloride update

I had to do the last 4  IR boards for the Educubes last night, and hoped the CuCl2 etchant might be ready.  It wasn’t – so I used ammonium persulfate again.

Most of the 80g of wire dissolved over the course of a couple days with the bubbler running.  But the solution changed from clear very dark green to milky green, with a layer of brown at the bottom.  (Sorry, no pic.)  The Adam Seychell page indicated that this is probably cuprous chloride precipitating out of the solution.  Since the comment was that such precipitation occurs with dilute solutions, I tried adding acid.  I added about 130 ml of the commercial 31% HCl, and the solution immediately became clear (well, not cloudy) again.

There was still some of the wire at the bottom of the jar, so I left it bubbling.  But even after several hours, the “drop on a white surface test” showed 10+ g/l of Cu+1.  I don’t know whether I’m just still not at equilibrium – more copper coming into solution from the wire that the bubbler hasn’t been able to keep up with by oxidizing to Cu+2 yet – or I’m stuck for some other reason.  I’ll let it run and see what happens.

I have mixed feelings about adding acid.  It obviously increases acid concentration – which is probably good.  But it decreases the copper concentration – which in my case is bad.  My acid is just about 10M (from a chart in the Seychell page).  His graph of etch rate v HCl concentration goes from well less than 1M to 4M.  So maybe adding acid would make the concentration inappropriately high.  Rats – I really didn’t want this to turn into a chemistry project.

A little later:  The wire is all gone, but the solution is much more brown than green (see funnel pic below).  In a test tube I tried adding acid and separately, adding water.  Both gave a clear green solution.  I guess I need to resurrect enough chemistry to do what probably amounts to a high school chemistry homework assignment.  But at least I kept notes what what all has gone into that jar, so I can make a fair quantitative assessment.

An interesting possible two-birds-with-one-stone came up with the 1M NaOH titrant Seychell suggests using in a titration test of the etchant.  I use NaOH as positive developer in my PCB making process.  It’s cheap to make and doesn’t take much to develop a board, so I make a bunch and throw out the small amount I use each time.  Do you suppose the concentrations of the developer and the titrant might be the same so I could just stock one solution?  <checks out developer recipe>  Nope.  He wants 1M, and my developer is 0.25M.  Yeah, I could stock 1M and dilute it 3:1 with water for developer, but that’s a bit of a hassle.  I happen to just be out of developer, so maybe I’ll make up just enough 1M so when diluted it will refill my developer bottle.  I’ll use a little for the dumb titration I’m probably going to have to do, and hope to not have to do that again.

Funnel defeats splash

On the mechanical side, the half-full quart jar of wanna-be etchant with wire and the bubbler looked awful after a couple of days of running with no top on the jar.  To my surprise, there was a thick crust of light green crud on the outside of the jar, and the bubbler hose was wet with spray.  (Sorry again – no pic.)  If I’m going to need to bubble this stuff frequently, I need a better way to manage the spray/splashing.

I think a plastic funnel will do the trick.  It just fits over the bubbler tube, provides a loose cover, and whatever collects on it a) is contained within the jar, and b) basically dribbles back into the jar.

I’m sure there will be more…

Posted in Cupric Chloride Etchant | Leave a comment

A Rude Awakening on Educube Comms Performance

I was frustrated because message transport between cube bases was slow/erratic.  At 115200 b/sec, the best case is ~11KB/sec.  For a 22 byte message, that’s 2 ms best case.  That’s a pretty short in timelines measured in 10s of ms.  But I’d see a successful message every few seconds.  Huh?

I put a hook in to use the new button to toggle between the current send+receive and receive-only behaviors.  It was still slow, but more reliable when transmit was turned off on the receiving box.  Maybe that had to do with not throwing away messages in the flush() call.  The flush() call also flushes both transmit and receive fifos.  Since we flush immediately after sending, there was the possibility that it would truncate the send buffer, so I tried clearing only the receive buffer.  It didn’t seem to make any difference.  That makes sense in the light of later observations.

Let’s measure something

A quick check with a one char print every time a message was transmitted showed maybe one message going out per second!  The example app does 10 reads with 10ms delay between and then one write (to both sides).  Assuming the programmed 10 ms delay is the main delay, it should transmit about every 100ms.  Where’s the time going?  About the only thing in the loop 9 times out of 10 is a call to rxpoll().  Bracketing that call with calls to millis(), it turns out rxpoll() takes ~72 ms to read both channels with no data coming in!

When receiving actual messages, rxpoll() took 4 reads for a total of 1220 ms to receive a 55 B message, and 523 ms in 2 reads for a 13 B message.  That’s 20-40 ms/byte in receive time.

How about the send side?  Bracketing just the new writeMsg() call, that took 186 ms to write a 13 B message (including sync, len, cksum) and 610 ms for 55 B.  That’s ~12 ms/byte.  Hmm – that’s still noticeably less than the time it takes to receive, so the analysis isn’t very complete.

What can be done?

Since the I²C lib calls are obviously expensive, how can we reduce that time?  I noticed when I was looking into the lib that the transmit and receive functions transfer a single byte at a time.  The I²C bus supports multi-byte reads and writes.  If we could use those, it could help a lot.  I don’t know how directly that’s supported by the Wire lib, but it looks like the primitives Wire exposes are extremely low level – like “send a START condition”.  With a little digging into the I²C protocol, we might be able to build up appropriate commands to do multi-byte sends and receives.

The Hackstrich MultiSerial lib only provides one-byte reads and writes, so we’d have to add new lib calls for the efficient stuff.  That shouldn’t be very difficult (if we knew how to do it).

The good news is that if slow, the current implementation essentially works.  We can tweak with different transmit/receive ratios for R and L channels based on how we need apps to behave and improve performance some.  And if/when we add more efficient multi-byte reads/writes to the lib it will be just a few-line change to the app and perhaps an order of magnitude performance improvement.

Posted in W88 Educubes | 2 Comments

Educube IR Board update

Testing the last board

I’m almost done with what I’d hoped to do!  I just finished soldering up the last of the five boards.  I only have four Diavolinos, so I tested the last one by hooking it up to a regular Arduino.  All it takes is two wires for clock and data for the I2C plus ground and 5V.  OK – the button is another digital pin to the Arduino.  I didn’t bother to hook that one up.

You can see the others in the background.

The other thing I wanted to contribute to the platform was a working library to talk to the UARTs and some simple example code showing how to use the library.  I also wanted at least a basic UDP-like datagram protocol with checksum.  I got most of that.

There were really only two routines I had to write.  There’s a writeMsg() function that takes a buffer of payload bytes and packages up a message – sync byte, length, payload, checksum and sends that to the UART.  And a poll received data function.  I hoped to have that one run by a timer interrupt, but couldn’t get that to work.  The application now has to call that routine frequently.  The example program does it every 10ms.  That routine reads bytes coming in and assembles and check messages.  When it’s got a good one, it sets a flag so the main app can grab the message.

I also put a simple app together that loops reading both channels and periodically writing a random message (one of 7 canned strings) out both sides, and loaded on all the Diavolino/IR board combos.  If you point either end of one at another which is connected serial to the IDE, it displays the message,  who sent it, which side they sent it from, and which side it was received on.  And if you push the button on the IR board it lights the Arduino standard LED.  But its main claim to fame is showing how to use the send and receive routines.  It’s far from perfect, and needs tuning (Tx vs Rx), but it’s a good start.

The biggest disappointment (besides not being able to get the time interrupt to work with the receive poll routine) is that I couldn’t get the two routines into the library and have them still work.  It was just dumb C++ problems, and I wasn’t good enough to over come them.  The example program has both routine in the main source file.  Ugh.  I hope somebody else can figure out how to put them in the lib.

I even wrote up a readme with most of the relevant info – see it below.

It’s great to be about done.  I’ve been off for two weeks, but have done almost nothing but work on the boards and the software.  Done is good.

W88MultiSerial library README  ver 0.9  4/15/11 jw
---------------------------------------------------


BACKGROUND
----------
This code is to allow an Arduino (or clone) to talk to the custom IR comms
board used in the Workshop 88 Educube project.

The comms board uses an NXP SC16IS752 chip with the following relevant
features:
- 2 independent UARTs
- talks I2C to the host Arduino
- UARTs have appropriate pulse shaping hardware to be used with IrDA IR
transceivers such as the Vishay TFDU4101 on the board
- UARTs each have a 64-byte receive and a 64 byte transmit FIFO
- chip has 8 bits of General Purpose IO
- the chip is capable of generating Tx and Rx interrupts, but we don't have
interrupt lines available

Hackstrich Labs is in the process of producing an Arduino shield which
implements 2 serial ports using the SC16IS752.  They have graciously made
their code open-source, and that code has provided an excellent starting
point for the W88 code.  This includes initialization, register access,
single-byte read and write functions, and a non-blocking "is anything
available on receive" function.


OVERVIEW
--------
The example program IrBoard3.pde works with the W88 IR comms boards attached
to Diavolino Arduino clone hosts.  It's a suitable starting point for
developing real applications, providing:
- initialization of the UARTs for IrDA
- a higher level function to write a message
- a poll function that reads from both channels, assembles and checks
messages, and provides notification when a valid message is available
- access to a GPIO pin with an LED on the IR comms board
- an application level read, write, and message handling loop structure

The initial message structure provided is as follows:
sync byte | length byte | variable number of data bytes | 2 byte checksum

The sync byte is 0x88 (ooow!).  Length is limited by a #defined buffer size
of 70 bytes.  The current checksum is the most basic
sum-of-all-bytes-truncated-to-16-bits.  Checksum includes the length byte,
but not the sync byte.  Zero length messages may not work.


Timing is critical, particularly in light of the facts that the IR channels
are necessarily half-duplex, and transmitted characters reliably appear in
the receive buffer.  This means the receive buffer on each UART MUST be
flushed immediately after transmitting a message.  If this is not done, the
transmitted characters will be comingled with the received characters,
invalidating the message checksum.

The example program transmits once for every 10 reads.  This timing tuning
may not be optimal.

There's also a hardware button on the IR board, connected to D10 on the
Diavolino.  Very basic, but works.

I also wrote a unique identifier into EEPROM of each Diavolino.  They somehow
have to know who they are, and this one-byte value, 0-6 does that.  It may
also be useful for randomizing delays so the cubes don't end in a
pathological lockstep mode not able to communicate.


FUNCTIONS
---------
The init is just begin() call for each channel, and a call to set one GPIO
pin as output (for the LED).

void writeMsg(byte chan, char len, unsigned char* buf)
	chan is 0 or 1
	len is number of data bytes to send
	buf is a pointer to a buffer containing the data payload

The function prepends the sync and length bytes, and computes and appends the
2 checksum bytes.  It writes the message to the specified UART's transmit
FIFO.


void rxpoll()

Call this often - the example program does it every 10 ms.  It takes care of
reading to exhaustion, resyncing using the sync byte, doing sanity check on
length, and verifying the checksum.  When a valid message has been received,
it copies the data payload to msgbuf[channel].  To tell the main application
when a message is available, it puts the length in msglen[channel].

To allow the main program to deal with the message before it gets overwritten
by the next message, rxpoll will not construct a new message until it sees
that the main program has set msglen[channel] back to zero.  It is the
obligation of the main program to do this.


SAMPLE OUTPUT
-------------
Output of example program
   - R|L msg means message received on right|left channel
   - B|b= means sent from the right|left side of device 2 (B)
   - . means chars were available
   - x means bad checksum
   - digit at end of message is a sequence number (0-9) to check for lost
msgs

I took a device on the battery pack and pointed each end of it at each end of
the receiver.  Output is from receiver to IDE serial monitor.

IR Board Test
I am device 4
...R msg of len 14 b=Hello mom!0
...R msg of len 27 b=Arduino clone Diavolino2
...R msg of len 54 b=The quick brown fox jumps over the lazy dog's back3
...R msg of len 14 B=Hello mom!7
.....L msg of len 15 b=hackerspace0
....x.....L msg of len 13 B=Educubes!8
...R msg of len 27 B=Arduino clone Diavolino9
....L msg of len 15 hackerspapace0


STATE OF THE CODE
-----------------
It all works, but isn't optimal yet.

- both rxpoll() and writeMsg() should be in the library, but I couldn't get
them to work when I put them there.  Some programmer more facile with C++
should figure out how to put them in the lib.  For now, you must include
those functions in the file with loop().  Sorry about that.

- It would be very nice if rxpoll could be hooked to a timer interrupt so the
main line didn't have to mess with it.  Using MsTimer2 I could call rxpoll,
but it didn't work when called that way.  I hope somebody smarter than me can
fix that.

- The reported length on received messages isn't always right, although
there's never garbage at the end or anything.

- rxpoll() could reassemble the next message in its private buffer and just
not write to the public buffer until msglen was reset.  This might throw away
fewer messages.

- There are functions like word length that are stubbed out in the lib that
should be populated.  But I hacked the begin() function so it does exactly
the inits we need for IrDA, so that's a lower priority.

- There should be some versioning of the lib .cpp and .h.

- It should be put in github or some such.

- Fixes for known problems should be reported to the original author.

- The original code from Hackstrich Labs is in the "original" directory.

- All remain bugs should be removed :)

		...end...
W88MultiSerial library README  ver 0.9  4/15/11 jw
—————————————————

BACKGROUND
———-
This code is to allow an Arduino (or clone) to talk to the custom IR comms board used in the Workshop 88 Educube project.

The comms board uses an NXP SC16IS752 chip with the following relevant features:
– 2 independent UARTs
– talks I2C to the host Arduino
– UARTs have appropriate pulse shaping hardware to be used with IrDA IR transceivers such as the Vishay TFDU4101 on the board
– UARTs each have a 64-byte receive and a 64 byte transmit FIFO
– chip has 8 bits of General Purpose IO
– the chip is capable of generating Tx and Rx interrupts, but we don’t have interrupt lines available

Hackstrich Labs is in the process of producing an Arduino shield which implements 2 serial ports using the SC16IS752.  They have graciously made their code open-source, and that code has provided an excellent starting point for the W88 code.  This includes initialization, register access, single-byte read and write functions, and a non-blocking “is anything available on receive” function.

OVERVIEW
——–
The example program IrBoard3.pde works with the W88 IR comms boards attached to Diavolino Arduino clone hosts.  It’s a suitable starting point for developing real applications, providing:
– initialization of the UARTs for IrDA
– a higher level function to write a message
– a poll function that reads from both channels, assembles and checks messages, and provides notification when a valid message is available
– access to a GPIO pin with an LED on the IR comms board
– an application level read, write, and message handling loop structure

The initial message structure provided is as follows:
sync byte | length byte | variable number of data bytes | 2 byte checksum

The sync byte is 0x88 (ooow!).  Length is limited by a #defined buffer size of 70 bytes.  The current checksum is the most basic sum-of-all-bytes-truncated-to-16-bits.  Checksum includes the length byte, but not the sync byte.  Zero length messages may not work.

Timing is critical, particularly in light of the facts that the IR channels are necessarily half-duplex, and transmitted characters reliably appear in the receive buffer.  This means the receive buffer on each UART MUST be flushed immediately after transmitting a message.  If this is not done, the transmitted characters will be comingled with the received characters, invalidating the message checksum.

The example program transmits once for every 10 reads.  This timing tuning may not be optimal.

FUNCTIONS
———
The init is just begin() call for each channel, and a call to set one GPIO pin as output (for the LED).

void writeMsg(byte chan, char len, unsigned char* buf)
chan is 0 or 1
len is number of data bytes to send
buf is a pointer to a buffer containing the data payload

The function prepends the sync and length bytes, and computes and appends the 2 checksum bytes.  It writes the message to the specified UART’s transmit FIFO.

void rxpoll()

Call this often – the example program does it every 10 ms.  It takes care of reading to exhaustion, resyncing using the sync byte, doing sanity check on length, and verifying the checksum.  When a valid message has been received, it copies the data payload to msgbuf[channel].  To tell the main application when a message is available, it puts the length in msglen[channel].

To allow the main program to deal with the message before it gets overwritten by the next message, rxpoll will not construct a new message until it sees that the main program has set msglen[channel] back to zero.  It is the obligation of the main program to do this.

SAMPLE OUTPUT
————-
Output of example program
– R|L msg means message received on right|left channel
– B|b= means sent from the right|left side of device 2 (B)
– . means chars were available
– x means bad checksum
– digit at end of message is a sequence number (0-9) to check for lost msgs

I took a device on the battery pack and pointed each end of it at each end of the receiver.  Output is from receiver to IDE serial monitor.

IR Board Test
I am device 4
…R msg of len 14 b=Hello mom!0
…R msg of len 27 b=Arduino clone Diavolino2
…R msg of len 54 b=The quick brown fox jumps over the lazy dog’s back3
…R msg of len 14 B=Hello mom!7
…..L msg of len 15 b=hackerspace0
….x…..L msg of len 13 B=Educubes!8
…R msg of len 27 B=Arduino clone Diavolino9
….L msg of len 15 hackerspapace0

STATE OF THE CODE
—————–
It all works, but isn’t optimal yet.

– both rxpoll() and writeMsg() should be in the library, but I couldn’t get them to work when I put them there.  Some programmer more facile with C++ should figure out how to put them in the lib.  For now, you must include those functions in the file with loop().  Sorry about that.

– It would be very nice if rxpoll could be hooked to a timer interrupt so the main line didn’t have to mess with it.  Using MsTimer2 I could call rxpoll, but it didn’t work when called that way.  I hope somebody smarter than me can fix that.

– The reported length on received messages isn’t always right, although there’s never garbage at the end or anything.

– rxpoll() could reassemble the next message in its private buffer and just not write to the public buffer until msglen was reset.  This might throw away fewer messages.

– There are functions like word length that are stubbed out in the lib that should be populated.  But I hacked the begin() function so it does exactly the inits we need for IrDA, so that’s a lower priority.

– There should be some versioning of the lib .cpp and .h.

– It should be put in github or some such.

– Fixes for known problems should be reported to the original author.

– The original code from Hackstrich Labs is in the “original” directory.

– All remain bugs should be removed 🙂

…end…

Posted in W88 Educubes | Leave a comment

Cupric Chloride Etchant – Update

Adding copper

I had to go back to Ammonium Persulfate for the last of the Educube IR boards.  Etching was slow to very slow with the CuCl2 and results were poor.  There was substantial undercutting of traces around the edges.  That was at least in part due to the slow etching.  The first board – with H2O2 as the oxidizer – came out fine.

But I haven’t quite given up.  I’ve put some stranded copper wire in the jar and just left the air pump bubbling.  So far I’ve added about 86g of wire (cleverly weighing it before I put it in so I’d have some clue what the copper concentration was).  With optimum Cu++ concentration of 120-170g/l, with the maybe 0.6 liters I have, I should be in good shape if/when the wire all dissolves.

This etchant is very dark now.  The nice light green from the beginning was nothing like what the ‘real’ stuff looks like.

I’m really disappointed – mostly in myself, I guess – for not reading enough about this etchant.  Proponents start users down the garden path with HCl and H2O2 and deliver a nice fast initial etch, and pretty green etchant.  But when you read the details, there’s no way you’re going to get real CuCl2 etchant by etching the onesy-twosey boards most hobbyists do.  Sure, you can add H2O2 as oxidizer, but it’s very short-lived and it just waters the solution down.  If I were going to do that, I’d certainly for go for the 30% stuff (which I haven’t found yet) to reduce the watering-down.

Sitting in a corner

But I have some hopes for my batch.  It’s just sitting in a corner, bubbling away, hopefully eating all the wire I’ve put in.  When it does, I’ll certainly give it another try.  There are always more boards to etch 🙂

Posted in Cupric Chloride Etchant | Leave a comment

Cheapie USB-TTL Adapters

Thinking there might be need for some more “FDTI cables” – USB-TTL serial adapters with a 6 pin 0.1″ female header to plug into USB-less Arduino clones (like our Diavolinos), and being offended at the pretty standard $15 pricetag of “real” FTDI cables, I found some cheapies – $6 each on Ebay.  From China, of course.  I bought two, at least to test out.

Cheapie with DTR hack

The obvious drawback was that they didn’t have the universally known FTDI chip.  The CP2102 provided about the same functionality, but drivers might be a little less common.  Haven’t checked Linux yet, but my Win 7 box found the drivers with no problem.

One of the less obvious drawbacks is that the connector pinout is different from “standard”.  Of course it’s male instead of female, but they’re in the wrong order as well.  Fortunately, that can be worked around.

Another less obvious drawback is that they didn’t choose to bring DTR out.  (They did bring the chip’s Reset line out – why??)  The impact of no DTR has to do with the fact that the Arduino IDE/FTDI cable system is cleverly arranged so when the IDE pulses DTR, it bounces the ATMega RST line and resets the processor – invoking the bootloader.  This is important when downloading a sketch to the Arduino.  If the cable system doesn’t do the reset, you have to be watching and reset the Arduino manually immediately after the compile is done or it won’t start downloading.

I looked at the datasheet, and sure enough the chip does support DTR.  Maybe I can just connect to that pin and bring it out on the header.  Unfortunately, the pin it comes out on goes nowhere, so I couldn’t pick up the trace on the board.  But with some careful soldering, I got a very thin wire soldered to the pin itself.   And after tracing the board out a bit, I found I could reuse the dumb Reset pin on the header by just cutting 2 traces and soldering the other end of my wire to a comfortably large pad (the end of the old Reset pullup resistor).  You can see the wire in the picture above.

Cheapie with custom cable

Of course the connector gender and pinout are still wrong.  But a custom cable fixed that.  I tried it out and Arduino downloads work exactly as they should.  The labeling is a coat of white-out (correction fluid) on the connector and extra-fine point Sharpie.

A much less obvious very positive feature of the CP2102 is that it has an on-board 3.3V regulator.  This really saved me for a while and let me do some testing of the Educube IR boards until a supply of real regulators came in.  You can see the long flying lead with 3.3V taped back down to the cable.  That wire was soldered on to an IR board to power it for a while.  Very helpful.

Second adapter

Now until the displays come in and boards get made, the Educubes only output is via serial to the IDE serial monitor.  Figuring we’d need more cables, I took my DTR hack to the second adapter, and this time removed the header and attached a new cable directly.  Looks good and works well and is a little more user-friendly.

Overall, I’m pleased with these (as I have been with almost all my cheap Chinese electronics purchases).  And the price was certainly right.  Unless you count the cost of my labor figuring out the DTR hack, modifying the boards, and making the custom cables.  I don’t want to figure that one out.

Update 1/3/12:  I bought some more similar adapters, this time for ~$3 each.  These have LEDs for data as well as power.  I’m completely comfortable with CP2102-based adapters, as the drivers are very available.  I’m disappointed that they don’t bring DTR out, but floored that they felt the need to bring the chip’s reset line out!  This version was even stranger on the reset:  the external pin goes thru a 2K resistor to the chip’s reset line.  No pullup.  Huh?  Anyway, that made the DTR hack even easier:  remove the resistor to get a nice pad to solder to, and no traces to cut.  I found some nice blue wire wrap wire whose insulation doesn’t melt as you solder to it.

I had to remove the male header on these, too.  This time I used a short piece of #12 solid wire and a bunch of solder to melt all the pins at the same time.  (See pic in 2/2/12 update.)  Worked out quite well.  The cable I used on the first one was too fat and stiff.  I went back to ribbon cable for the other two.  I did bring the 3.3V output out as a flying lead just in case I ever need it.

One thing I didn’t realize about 2102s until now:  That 3.3V regulator is not just for powering external stuff – it’s used internally, so the external logic levels it uses are 3.3V.  And the max input voltage looks like it can handle 5V TTL inputs as well.  So as I read it, it should talk to either 5V or 3.3V devices.  Cool.

I did get slightly burned on this one, though.  They reversed the TX and RX labels on the silk screen!  It took a little while and chasing traces on the board to troubleshoot that and convince myself they’d screwed up.  But after the first one, it’s easy to get the cable right the first time.  Looking at the original Ebay post, there’s an extra pinout diagram – but it’s even more wrong than the silk screen.  I was sufficiently offended that I even sent a note to the Ebay vendor.  I almost wonder if these were the result of some board layout student’s first attempt.  At least the price was great!

Update 2/2/12:  Here’s some exciting news in the exciting USB-TTL adapter scene:  There’s a better CP2102 adapter available!  Until now there hasn’t been much reason to choose one adapter over another – and there are lots of these Chinese cheapies to choose from.  But this one is a little different:  The extra holes along the edges break out many other signal lines – including DTR!  No more soldering to a tiny pin on the chip!

I just received this one – for $2.88/free shipping.  They didn’t include a picture of the back in the Ebay ad, so finding DTR broken out  was a pleasant surprise.  My hack to this one was a little different, too:  I put a switch on to select sourcing 5V or 3.3V to the connected device.

The first step was to remove the male header.  I used my “chunk of #12 solid and extra solder” technique to heat all the pins at once.  A temperature controlled iron provided plenty of heat for the job.  The header pulled out intact in a few seconds, and a solder sucker cleared the holes one at a time.

The next decision was how to use the holes from the old header to provide the usual Gnd, Tx, Rx, DTR and power to my ribbon cable.  I also needed to pick up both 3.3V and 5V for the switch.  Both voltages appeared on the original header, with 5V going thru what I assume is a fuse (marked F1, near the 5V pin).  Unsoldering the fuse provides two nice pads – one connected to the old 5V header pin, the other actually providing 5V.  I used the former to connect the output of my switch to the cable and the latter as the 5V source for the switch.  I took 3.3V from the original header hole – and didn’t connect that one to the ribbon cable.

The useless original RST header hole will be repurposed for DTR, but first needs to be isolated from the CP2102’s Reset line.  A quick inspection of the traces showed a single cut on the back of the board would do that.  I considered just running that last line from the ribbon directly to the DTR hole, saving  the trace cut and one extra wire on top of the board.  That would have worked fine, but using the RST hole seemed slightly more mechanically robust.

Spooked by incorrect silk screen legends on other cheapies, I checked this time by both following the traces and a quick test with a terminal emulator and a logic probe.  Sure enough, the legend is backwards on this device.  Fine – that’s easy enough to fix when I terminate the other end of the cable.  I’m guessing whatever amateurs lay these things out (students?)  just don’t know that the convention is to label lines like Tx and Rx from the point of view of the device they’re on rather than what they connect to on some other device.

I slobbered hot melt on the adapter and plunked the roughed-up side of the switch into it.  A little careful soldering of the nice wire wrap wire I found whose insulation doesn’t melt much and it was about done.  You can see where the fuse I removed was.  I’ll probably cover all the wires with some more hot-melt to keep them from getting caught on things.

If you just wanted a simple USB-TTL adapter with a single supply voltage (pick either one), the only hack you’d need with this one is unsoldering the header and soldering in your cable.  That’s about as clean as it gets.

Update 1/2/18: I just got 3 of a new version ($1.50 each), probably motivated to make a dedicated cable/adapter for the Drawbot.  Pinout is almost standard, but the end pin – marked 3V3 – should have ground.

A potential hack to somehow use the existing pins would be to cut the trace to 3.3V and solder bridge that pin to its neighbor Gnd.  Looks like cutting the diagonal trace on the top surface of the board should work, and a quick test seems to confirm that.  Jumpered end (old 3.3V) and Gnd, made up a F-F header and plugged it into a Pro Mini.  It worked – at least in that board.

 

 

 

 

Update 4-10-20 New red boards

I just got 5 new red counterfeit FTDI boards.  The two I checked both had serial # A50285BI, a known common fake number.  The chips are clearly illegally marked to look like real FTDI.

The good news is that they have a 6 pin header that’s actually in the same order as Pro Mini or Diavolinos.  It still comes with a male header, but adding solder with a piece of #14 wire the width of the pins allowed me to unsolder the header very easily.  It now has a female header, with the DTR end marked green.

The board also has a 5V/3.3V jumper – nice!  And yes, it shifts both Vcc provided to the Arduino (or whatever) and the logic levels.  All the pins of interest are broken out along the sides, and there are LEDs for TX and RX.  So it’s about the nicest board I’ve come across.  (Assuming you can accept the counterfeit chip and don’t have the 2.12 FTDI driver that bricks chips.)

The driver for getting a few more of these was to have a module I could add to convert an onboard serial to USB.  Don’t remember which one. 🙂

Posted in USB_TTL Adapters | Tagged , , , , , , | 18 Comments

My Cupric Chloride Etchant Experiment

Encouraged by promise of not having to dispose of etchant bearing environmentally harmful copper salts, I decided to try the great green cupric chloride etchant.  I started my batch with 8 oz 31% HCl and 4 oz of 3% H2O2.  It etched the first board very cleanly in roughly the same time as my usual heated ammonium persulfate.  The solution was a light green after that first 3″x3″ 40% etched board.  There were lots of bubbles in the jar when I put it away – presumably H2O2 decomposing.  I left the lid loose.  I etched that first board completely outdoors.  When the wind blew toward me, the fumes were unpleasant unto choking.

When I tried another board a day or two later, it didn’t do much.  I was using a bent up piece of (insulated!) copper wire that hooked around the corners as a handle so I could agitate the board easily.  I heated the etchant up, and still not much.  (Some color change of the copper, but with continuous agitation, it didn’t feel like much was happening.  I added ~2.5 oz H2O2 – and got lots of action.  Immediate bubbles on the board, and more color change.  I started outdoors, but it was kind of cold and I ended up back in the kitchen.

Resisting the urge to only change one variable at a time, I also put an aquarium air stone in the etch pan (connected to a small aquarium pump).  I tried holding the board (which was copper side down – not my usual, but probably a good idea) horizontal, barely out of the etchant, directly above the stream of bubbles.  That looked like it would be a pretty effective technique, with continuous wash of bubbles across the board.  By centering the stream on the board and adjusting the tilt of the board carefully, I could get bubbles about uniformly escaping around all 4 sides of the board.  I did heat it some, too.  Surprisingly, fumes didn’t seem to be much of a problem.

The bubbles might have been too aggressive, as the resist seemed worn away at the edges of some traces.  The board came out pretty good, but with edges not as crisp as the first board or as with my usual AP.

The next board was bad.  I used the bubble technique quite a bit (at least at first).  It didn’t seem to be doing as much, and I heated it more.  It took a long time, and by the time it was done, the resist was completely gone!  I’m sure the traces were at least slightly compromised, though they looked at least acceptable.  The etchant has been getting darker and darker green.  I’m afraid at least some of the color is from the green resist that’s now part of the soup.  I was watching for signs of blue rather than green – indication of significant (undesirable) Cu+1, but the solution remained green.  The aeration might have been part of that.

It felt like the etchant wasn’t working by itself – presumably not enough Cu+2.  Adding more oxidizer helped a lot, but I’m afraid of diluting the batch with too much H2O2.

I left the aeration running overnight, and wound about 6g of stranded copper wire around the air hose so it was in the stream of bubbles.  The goal was to get more copper in solution, with the hope that then the Cu+2 will be enough of an oxidizer that the etchant will start working as steady state.

Amount of copper in the soup:  I’ve now done 4 boards 2.3″x2.9″ with about 40% of the copper removed.  With the 1 oz copper board I’m using, that’s an ounce of copper per square foot.  So my boards were 4×2.3×2.9 => 27 in².  At 40%, that’s 10.6 in², or 10.6/144=>0.074 oz, or ~2g.  If the wire all dissolves, that will increase the Cu concentration by about 4 times.

In both the reference article on this etchant, and this Chemcut paper there is indication that optimum etch times are with ~120-170 g Cu per liter!  I have less than a liter, but even when the wire all dissolves I’ll be more than a factor of 10 down from that!  Reading replies to articles about CuCl2 etchant, many comment that it was great initially, but then didn’t work.  I can believe there’s this significant barrier of getting enough copper into solution that people doing one or two boards will run into.  I guess if I hope to have something that works, I’d better put a LOT more wire into it!

I’m really starting to wonder whether this stuff is appropriate for hobbyist use.  If I etch 20 boards per year – say 2×3″ and 50% etch, that’s only about 10g of copper per year.  But I have to start with more than 10 times that for the etchant to work well!  I think my expectations were set inappropriately by the lure of starting with H2O2 as the oxidizer.  For onesy-twosy etching, it’s going to take a LONG time before you can etch without adding oxidizer.  And by that time the etchant will be so dilute with the water from the H2O2 that it still won’t work.  Maybe ammonium persulfate isn’t so bad after all…

I guess the good news is that if I could ever get a batch that worked, the chemistry shouldn’t drift very much with the amount of etching I do.  Aerating it to keep the Cu+1 concentration down (that concentration has significant effect on etch speed) is probably all I’d need to do, at least for several years.

Update 5/27/12:  After discovering that the original host of Adam Seychelle’s paper on “Etching with Air Regenerated Acid Cupric Chloride” was no longer available on its original host (at http://members.optusnet.com.au/%7Eeseychell/PCB/etching_CuCl/index.html), I put a copy of the paper here.  I think I’ve updated all the links in this thread to point to my local copy.  Many thanks to Jim Harvey for noticing that the original was gone and especially for finding a copy elsewhere!

Posted in Cupric Chloride Etchant | 2 Comments

W88 Educube IR board

IR board

I’m well into the prototype stage of 2-channel IrDA IR comms Arduino shield for the Workshop 88 Educubes GGHC project.

Very efficiently, IrDA uses very short (~10μs) IR pulses, which must be delivered by the UART driving the IR transmitter.  This really requires a special pulse generator on the send side, and a pulse stretcher on the receive side – a special hardware driver.

The first chip I found with IrDA drivers, the MCP2120, took TTL levels in and did the pulse shaping to talk to an IrDA transceiver like the Vishay TFDU4101s we have.  Unfortunately, the ATMega 328 only has one UART, and usually uses it to talk to the console in its IDE.  It does, however support I²C and SPI, so I next looked for a dual UART chip I could talk to with I²C/SPI and had built-in IrDA drivers.  I settled on the NXP SC16IS752.

We were obviously going to need a board to host the UART and the IR transceivers.  Since the main brain of the Educube is a Diavolino (Arduino clone), a shield was appropriate.  Since the LCD display is hosted on another shield, there were shield-stacking considerations, too.  Fortunately, the crystals I’d already bought for the unused MCP2120s would also work with the ‘752.

After a round of stupidity about which side the foil was on for the shield pins to line up, I had a board layout with the ‘752, its crystal and caps, Arduino shield pins, an LED on one of the ‘752’s GPIO lines for ‘hello world’ or whatever, the IR transceivers, easily replaceable transmit current limiting resistors and a local cap for nice sharp rising edges on the IR pulses, a button on one of the unused Arduino pins (D10) possibly for a ‘debug’ mode, pads for receptacles for the pins on the battery packs we had, a diode in series with the battery (since the 4×1.6V from new cells is easily beyond the absolute max voltage of 5.5V on some of the chips), an on-off switch, and a layout for a 3.3V low-dropout regulator (which is ordered but not in).

New "green" etchant

Since I was working on a part that is in the critical path for a project with a short deadline, it seemed like a good time to try out a new PCB etching technology I had never used and was completely unfamiliar with (rather than my always-works ammonium persulfate).  But I read about the cupric chloride etchant someplace on the Internet, so it must work 🙂  I don’t know why they never laugh when I say things like that at work.

The board came out just about perfect, and the new etchant is a pretty green.  I don’t know if it has enough Cu++ in it yet to work next time I use it, when the H2O2 initial oxidizer is gone.  That’s for another time.

IR board on Diavolino

I didn’t have much trouble soldering the fine-pitch 28-pin chip (bless you, solder wick!), and the rest of the board was very straight forward.  Since I didn’t have the stackable headers yet, I just soldered the shield to a few pins on the still-headerless Diavolino.  I needed 7 pins and added 2 more for more mechanical strength.  The extras were overkill – it’s mechanically very solid.  An interesting part was the dire warnings

IR Transceiver packaging

on the outside of the package about the IR transceivers being moisture sensitive.  Huh?  But a read of the Jedec standard explained it.  Who knew?  I was very careful to seal the package up as soon as I’d removed the two transceivers I needed.

After I figured out the ATMega on the Diavolino didn’t have a bootloader, I followed a cookbook page and used my Duemilanove as an ISP to burn a bootloader into the Diavolino.  Worked fine.  The picture below still has the connections I used to burn it.

Cheap USB-TTL adapter

The one missing piece was 3.3V for the UART.  Fortunately, I’d bought a couple of $6 USB-TTL adapters (from China via Ebay) which used a CP2102 rather than the standard FTDI chip.  (And cheaper than the $15 FTDI cables!)  But it’s just a serial port, so I figured it would work.  The adapter has a 6-pin 0.1″ male header, with a different pinout than the standard FTDI cables (and the header on non-USB Arduinos, like our Diavolinos).  I made up a dual female cable that got the right signals to the right places.  The bad part was that they didn’t bring DTR out on the cheapie adapter.  I think the Arduino IDE bounces DTR to reset the processor before (and after?) a download, so I have to watch and push the Diavolino’s reset button after the compile is complete each time I download code to it.  (The 2102 does have DTR, and a hack with some very fine soldering to bring it out may be possible.)  But the good news is that the CP2102 has a 3.3V regulator on the chip – and it’s brought out to the header!  So I left one flying lead from the cable carrying 3.3V and soldered it on to where the missing 3.3V regulator on the shield would go.

OK – board is populated, I can talk to the Diavolino, and I have 3.3V.  How do I talk to it?

A Google search for things like “arduino sc16si752” got 2 hits.  One was a woman who was searching, precisely as I was, for an Arduino library for this chip.  (It claims to be register-compatible with the good old 16C450 UART, so that was what we were actually looking for.)  She didn’t find anything.  The other was from Sarah Nordstrom, apparently a founder of StrichLabs, which is about to produce a MultiSerial Arduino shield – using a ‘752!  She pointed me at her github repo with code for her almost-complete board.  I was in luck!

So after studying some I²C tutorials so I could figure out how she would be talking to the chip, and studying the ‘752 datasheet and the 40+ registers it contains (and which ones must contain what magic bit patterns to allow writing to other registers – like the Modem Control Register, which contains the bit to enable the IrDA driver) so I could figure out what registers she was talking to and why, and studying her code so I’d know what objects and methods were available, I started with one of her test programs and hacked it down to a ‘hello world’ to blink the LED on the GPIO pin.

It worked!  (Well, after I fixed a couple of basic syntax errors so her lib would compile (!?), and made public the private register read/write methods so I could talk to registers, along with a couple more stumbles.)  The I²C connection was up, my stolen 3.3V worked, I had the right chip address, and I could write to a couple of registers!

Could I talk to the IrDA transceivers?  I added a one-byte serial write to my LED blink loop and looked at the transceivers with a digital camera.  Blinking!  Can’t tell if it’s intelligible, but the UART is putting something out when told to, and the transceivers are working well enough to light their LEDs!

But the two transceivers behave differently.  When sent two bytes 200ms apart, one channel blinks as expected.  But the other blinks a lot more randomly.  There is one difference in the board:  the transceiver has separate Vcc inputs for the electronics and current for the LED.  The datasheet suggests a series resistor to current-limit the LED, at least for short range and for power saving.  I’d put large pads for those resistors on the foil side of the shield – which faces away from the Diavolino, so it’s accessible.  I didn’t know what values to use, so I put 100Ω on one transceiver and 330 on the other.  The one with the 330Ω blinked more sensibly.  Maybe the 100Ω was too small and the chip was doing some protective thing.  I tried a 470 and the blinks looked a little different, but still not right.  Hmm.

How about receiving?  I added a while loop for received chars on each channel, printing whatever it got.  I tried holding a mirror up to the transceivers, hoping to hear their “L” and “R” data bytes coming back.  Nothing.  But the ‘good blinking’ channel reliably reported receiving an “R” for each blink – even with no mirror.  The IR transceiver data sheet says something about the receiver working in ‘echo mode’ while transmitting.  I wonder if that’s what’s happening.  Also – I think it’s half duplex at best, so a transceiver can’t listen to its own IR.  Maybe I can set up three mirrors and have them hear each other.  Ugh.

Lots of debug prints later… The chip has duplicates of the first 10 or so registers – one for each channel.  Part of the I²C protocol is a sub-address mechanism which the ‘752 uses to specify which channel is being addressed with those duplicate registers.  I tried to read back values from some of the registers, but despite identical channel initializations, got different values for the 2 channels.  Only the second channel I initted (using MultiSerial::begin()) had the right values.  Some digging later, I found that the lib used a UART reset flag to ensure it was starting from a known condition.  That’s fine, but unfortunately there’s only one of those – not one per UART – so the second init would unset whatever we’d set with the first begin().  This is a real bug in the library.  I put a static state flag in so it would only do the reset the first time begin() was called.

After that worked, I told each side to ignore its own transmissions (easy, because one side only transmitted ‘R’, the other only ‘L’) and print anything else it heard.  Then I arranged three mirrors so each transceiver should see the other – and they saw each other’s transmissions!

OK, but that won’t work well in the real world.  I need to flush received data very immediately after sending.  There is a flush() method, and it seems to work.  My main loop is now:

read & print R chan
send R chan
flush R recv
delay 2 ms
read & print L chan
send L chan
flush L chan
delay 2 ms
goto top

I think I’m now confident enough that the board works that I can make another!

I really also need to pack up the hacks and fixes to Sarah’s lib and send them to her.  That’s what open source is all about.

Posted in W88 Educubes | Leave a comment