Thursday, 18 September 2014

Fun with Python SpiDev

I have been having a little fun trying to get a Raspberry Pi talking to a Winbond SPI W25Q80BV 1MB flash chip (PDF).   The Python SpiDev library is rather poorly documented and doesn't actually seem to do what it is supposed to do.

For starters, it offers two similar functions for transferring data over the SPI bus, called "xfer" and "xfer2".  Both take a single parameter which is a list of bytes to transfer.  According to the documentation, the difference is that for "xfer"...
"CS will be released and reactivated between blocks. delay specifies delay in ┬Ásec between blocks."
and for "xfer2"...
"Perform SPI transaction. CS will be held active between blocks."
Its not completely obvious what a "block" is in this context. I can only guess (and hope) that it might mean between two consecutive invocations of the "xfer2" function (I can't think of anything else useful that it could mean). Also, the reference to "delay" in the description of "xfer" is the only reference to a parameter, attribute or anything else called "delay" anywhere in the documentation.

Anyway, no matter how much I tried, I couldn't see any difference between the behaviour of "xfer" and "xfer2".  Time to break out the logic analyser.  Looking at two successive calls to "xfer"...

root@alarmpi:~# python
Python 2.7.3 (default, Mar 18 2014, 05:13:23) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import spidev
>>> 
>>> spi = spidev.SpiDev()
>>> spi.open(0,0)
>>> 
>>> spi.xfer([0x90,0,0,0,0])
[0, 0, 0, 0, 239]
>>> spi.xfer([0x90,0,0,0,0])
[0, 0, 0, 0, 239]

I pasted the commands in, so the two calls to "spi.xfer" happened very close together in time.


As you would expect, the ENABLE (a.k.a. /CS) line goes low at the beginning of each transfer and high again as soon as the transfer completes.  No problems there...that's what the documentation says is supposed to happen.  Here's what one of the transactions looks like close up:-


Now to try the same test using "xfer2" instead of "xfer".  As I interpret the documentation, the /CS line should stay low between transfers, so that two consecutive calls to "xfer2" would actually look like a single SPI bus transaction, albeit with a bit of a hiatus in the middle.  However, that is not what happens.


If there's a difference there, I'm not seeing it.


Apparently I'm not the first one to ponder this mystery: here and here.

Which brings me to the mysterious "delay" parameter.  It turns out that the "xfer" and "xfer2" functions both take three additional parameters (determined by studying the SpiDev source code).

spi.xfer([values], speed_hz, delay_usecs, bits_per_word)

You can set "speed_hz" to 0 and it will default to the maximum supported speed.  "delay_usecs" goes into a 16-bit unsigned integer, so it looks like the longest you can stretch the /CS hold delay by is 65.5ms.  Worth a shot:-

>>> spi.xfer2([0x90,0,0,0,0], 0, 65535)
spi.xfer2([0x90,0,0,0,0], 0, 65535)
[0, 0, 0, 0, 239]
>>> spi.xfer2([0x90,0,0,0,0], 0, 65535)
[0, 0, 0, 0, 239]


It definitely did something: /CS now stays low for 26ms after the transaction is complete.  Its not the 65.5ms we were expecting, though.  

I determined experimentally that the delay used is actually modulo 40,000us.  Any value up to 40,000 works as it should...any value higher than 40,000 has 40,000 subtracted from it.  This is true whether I use "xfer" or "xfer2": I still can't find any difference in behaviour between the two.  

Returning to the SpiDev module source code, the lack of any behavioural difference between "xfer" and "xfer2" isn't surprising: it turns out that both of them actually make exactly the same IOCTL call to the SPI kernel module with a spi_ioc_transfer structure populated in exactly the same way.  That structure does actually contain a member called "cs_change" which is described as:-

@cs_change: True to deselect device before starting the next transfer
...which sounds exactly like it should be the difference between "xfer" and "xfer2".  However, neither method actually sets this structure member either way.  So it looks like the value for this parameter that is passed to the kernel is what ever random value is in memory when the space for the structure is allocated. It seems like it should be easy to fix so I will try modifying the source code to correct this problem.  But not tonight...that's an update for another day.

What I really wanted to do but (apparently) can't is to read continuously from the SPI flash IC.  All I should have to do is send it a "read" command and a start address, and then just keep reading from it in one big, 1,048,576-byte long transaction and it should happily return the entire flash contents in sequence.  This works fine on an Arduino: I set up the "read" operation and then just keep feeding it values (it doesn't matter what I send...its the value that the flash IC returns that I'm interested in) with the /CS pin held low.  However, with "xfer2" not working as it should, there seems to be no way to spread a single SPI bus transaction among multiple method calls.  Even if "xfer2" did work its not ideal.  There is a "readbytes" function which would be more appropriate because it doesn't require me to send it in a list of values to transmit (which will all be ignored anyway).  However, there is no "readbytes2" (working or otherwise) which would allow the /CS to be held low between successive calls.


Friday, 12 September 2014

Hakko FX888D 110V to 220V conversion

For a while now, I have fancied a Hakko FX888D soldering station. However, for some reason they are difficult to get in 220V form and - when they can be found - are shockingly more expensive than the 110V.  There seems to be no good reason for this: the only difference between the two appears to be the mains transformer.  Inspired by a YouTube video posted by egressvk, I decided to risk $100 and order a 110V version with a view to doing my own conversion.

I already had a cheap (incredibly cheap, actually) Yihua 936 soldering station which I got from Hobby King for €14.


Dave Jones at EEVBlog reviews it in his usual entertaining style here.  Its actually not bad, especially for the price, but when you put it side-by-side with the Hakko the differences are apparent.



The Hakko is heavier and feels more robust.  The heat-resistant collar is also of much higher quality. Its not apparent from just looking at a picture, but the cable on the Hakko is made from silicone rather than PVC and is much more flexible (and longer).  The stand that comes with the Hakko is also in a completely different league to the Yihua.  But so is the price and the Yihua works perfectly well so I'm not complaining.

Anyway, despite its virtues, I resolved that the Yihua was going to make the ultimate sacrifice and become a transformer donor for the FX888D conversion.  This is where I got a very pleasant surprise: it turns out that the transformer in the Yihua is a perfect fit for the Hakko.  The transformer has the same dimensions and even the mounting holes line up perfectly with the pillars in the FX888D body.  This was shaping up to be the easiest hack of all time !

Here is the Hakko with the transformer from the Yihua already fitted (but with the secondary side not wired in yet).  The original Hakko transformer is just below for comparison

 

I even took the original switch+fuse+mains-cable assembly from the Yihua, slotted the switch into the switch cutout in the Hakko body and secured the mains cable into the cable clamp. One minor problem with this approach is that the back of that mains switch+fuse assembly was awfully close to the body of the transformer.  To make sure they didn't touch, I slipped a bit of blank (no copper) perfboard in between the two and hot-glued it to the plastic pillars:


This is probably a little bit dodgy, if I'm honest: I may yet go back and use the power switch and fuse assembly from the Hakko transformer.  Assuming that I'm not electrocuted first, that is.

I had a little debate with myself about the best way to connect the secondary from the new transformer to the controller board.  Strip connector?   Solder+heatshrink the wires together? In the end, I desoldered the original wires (the red ones, visible in the top right-hand corner), cleaned out the holes (the most difficult part of the entire conversion !) and soldered the outputs from the new transformer directly to the board.

When I first powered up the unit after the conversion, the temperature on the display quickly shot up to 750F (just under 400C).  It seemed to me that the iron was running hotter than this and - sure enough - when I checked with a thermocouple the tip was closer to 900F.  I could compensate for this by just reducing the setpoint and the controller would hold the temperature steady, but it was a bit of a bummer to have the displayed temperature completely wrong.  I suppose I could have a faulty unit, but it was too late to submit a warranty claim now :-).  Anyway, I came across this YouTube describing how to reset the controller to its factory defaults. Without much optimism, I followed these instructions and it worked !!  The tip temperature measured with a thermocouple now (broadly) matches the temperature shown on the controller's LED display.

I'm used to thinking in degrees Celsius/Centigrade rather than in Fahrenheit which is the out-of-the-box default on the FX888D.  Thankfully, changing the display units is easy.


(these were real "wish I had a third hand" photos to take !)

This is a fantastic result: the conversion couldn't be any neater and I couldn't buy a transformer any cheaper than I got the Yihua 936 for.  As a bonus, I will reuse the (rather nice) enclosure that the Yihua controller came in for something else.

Tuesday, 26 August 2014

Can buying a new Hoover really save the planet?

banned_vacuum

The EU have been busying themselves with the important issues again.  According to regulations, the maximum power of a domestic vacuum cleaner will be capped at 1600W from September 2014 and 900W from 2017 (http://eur-lex.europa.eu/LexUriServ/LexUriServ.do?uri=OJ:L:2013:192:0024:0034:EN:PDF).  We're told that this will save 19TWh (that's 19,000,000,000,000 units of electricity) by 2020.  That's an awful lot: so much, in fact, that it sounds a little fishy to me.  Let's check their maths.

First, a few assumptions:-

  • There are 213,839,200 households in the EU (this isn't really an assumption...I looked it up: http://appsso.eurostat.ec.europa.eu/nui/show.do?dataset=lfst_hhnhtych&lang=en)

  • Each of these households spends an hour a week vacuuming, on average (don't we all ?!).  This figure isn't pulled completely out of the air: the 2014-2017 part of the new regulation states that the total annual power consumption of a new vacuum cleaner should be no more than 62.5KWh and that the rated input power should be no more than 1600W.  Divide the first by the second and you find that our EU masters expect us to spend 39 hours per year - equivalent to 0.75 hours per week.  vacuuming.  Interestingly, after 2017 the total annual consumption cap drops to 43KWh and the maximum rated input power drops to 900W.  Do the same maths and you'll find that we will be vacuuming for 47.7 hours per year (almost an hour a week) from 2017.  That's progress, I guess.  Anyway, an hour per week per household is a nice conservative figure for our purposes here.

  • The average vacuum cleaner currently in use uses 1800W of power.  Again, I didn't make this figure up: it is taken from a post on the European Commission blog

  • The expected life of a vacuum cleaner is 10 years.  Once again, I didn't pull this figure out of thin-air.  The regulation states "operational motor lifetime shall be greater than or equal to 500 hours".  At an hour a week (see earlier assumption), that's about 10 years.  That feels about right to me.  So we can expect that 10% of the households in Europe will purchase a new vacuum cleaner each year, swapping their power-hungry 1800W unit for a more eco-friendly 1600W unit up until 2017 and for a positively tree-hugging 900W unit thereafter

So how much power will all these neat-freaks with their vacuum cleaners wind up using and how much will be saved with the new regulations ?


2015

2016

2017

2018

2019

2020
With No Change (MW)
20,015,349

20,015,349

20,015,349

20,015,349

20,015,349

20,015,349
Under New Regulations (MW)
19,792,956

19,570,564

19,348,171

18,347,403

17,346,636

15,345,101
Saving (MW)
222,393

444,786

667,178

1,667,946

2,668,713

4,670,248


So by my calculations, by 2020 the new regulations will result in a saving 4.7TWh per year (at most).  That's an awful lot less than the claimed figure of 19TWh.  Actually, 19TWh is only slightly less than the total power that we use vacuuming each year using our current cleaners, so its difficult to see how any change to regulations - short of banning vacuum cleaners completely - could result in a 19TWh saving.

Am I missing something?  If I am, I just can't see it.

Tuesday, 9 October 2012

Relay Bounce

I was using an oscilloscope to do a little troubleshooting on a project that involved having a microcontroller flip a relay and I stumbled across something interesting.  I was graphing the voltage across the relay contacts (there was a good reason for this !) and I spotted this:-



When the relay snaps shut the voltage is supposed to suddenly drop to 0 as the contacts short.  As you can see that's not exactly what happened.  Instead it bounces between open and shut 4 times before finally settling on closed.  This all happens over 16ms so you might never know about it if you weren't looking at it on an oscilloscope.  I figure what is happening here is that the moving relay contact is quite literally bouncing off the fixed one.  Note how the closed period (0v) of each successive bounce becomes longer until it finally settles.

Monday, 6 August 2012

Arduino-based Audio Cable Tester

I love the Arduino platform - it makes it so quick and easy to get things done.

The local music school had a need to test a bunch of audio cables (1/4" and XLR) in a hurry in preparation for the annual students' concert.  Yes, it can be done with a multimeter but if you have lots of them to do this becomes very tedious very quickly.  Sounds like a job for an Arduino





It does XLRs also...



The work is all done by an Atmel Atmega mircocontroller



All of the development work is done in the Arduino environment.  Once it was all working I just transferred the microcontroller onto a piece of perfboard (so that I could reuse the Arduino board for my next project).  The connectors on the far-left of the board (connected to pins 1,2,3,7 and 8 ) allow the Arduino board to be used as a programmer (see http://arduino.cc/en/Tutorial/ArduinoToBreadboard). That link explains how to configure the Arduino to use the built-in 8MHz RC clock in the Atmega so no external crystal is required (neither accuracy nor flat-out CPU speed are remotely important in this application).

I also stuck a normal ICSP connector on it so that it can be programmed using a normal programmer (bottom-left corner).  This is handy:  once the code was complete I was able to blow the Arduino boot-loader away so that the sketch starts immediately rather than after a pause.  The downside is that if I want to use an Arduino to program it again I need to reinstall the boot-loader (for which that ICSP header will be very useful !)

The source-code is posted here.  The comments in the code list the required connections.  I haven't bothered to draw a circuit-diagram but if anyone wants one just leave a note in the comments below and I will post it here.

 

 

 

Laptop Transport

I needed a better way to carry my laptop on my folding bike.  I used a backpack for a long time which works fine except on hot days (sweaty-back syndrome !).  I tried a handlebar mount (the excellent but expensive  Klickfix system) which also works well but it adversely affects the stability of a bike which is already a little on the twitchy side.  The bike has a carrier but it is so low down that my heel clips anything that overhangs its perimeter.  There had to be a better way.

My simple solution is to make an attachment for the carrier which will allow the laptop case to be mounted vertically without moving around.



The band around the laptop back is a strip of 40mm x 2mm aluminium which is attached to carrier





It works so well I did the same thing for the folding bike's big brother...





I worry a little about the laptop having the guts shaken out of it (its a very nice laptop !) so I use a folded-up and partially inflated tube to give it a little "suspension":



I hope someone finds this useful.  If you have thought of a better way to solve the same problem I'd love to hear from you.

 

Wednesday, 25 April 2012

The Sound of Music

Oscilloscopes and guitars are a wonderful combination :-)

This is what an open-E played on the 6th string of my Stratocaster knock-off looks like:-



The two vertical dashed lines measure that time between two consecutive peaks (12.19ms) and from this we can work out that the fundamental frequency is 82Hz (as it should be...E on the 6th string is supposed to be 82.4Hz).

The scope can also do spectrum analysis (showing the harmonic content).  Here's the same open-6th string:-



Unsurprisingly, you see a strong peak at 82.4Hz (the fundamental) with 1st harmonic (164Hz, one octave above), 2nd (247Hz, which is B on the 2nd string, nicely illustrating the relationship to the 5th note in a chord) and 3rd (329Hz, which is the E on the 1st string, two octaves above the fundamental) all strongly present.  Although there isn't much of it, 4th harmonic occurs at 412Hz (you can just barely see it).  This is G# played on the 1st string which illustrates the role of the major 3rd note in a chord.  I think its interesting to see how the notes of a major chord all occur as harmonics of the fundamental.

Another interesting thing to look at is how tuning using harmonics works.  This is the 6th string with me barely touching the string just above the 12th fret to damp the first harmonic:-



Two interesting things:  the strongest peak is at 164Hz (one octave above that open E, just as you would expect).  The fundamental frequency of that string is almost completely gone (because my finger prevents the string from moving at its centre point).  Also, there is very little other harmonic content.  Sure enough, if I graph the signal it is much closer to being a pure sine wave at 164Hz:-



If you play that with another (nearly) pure sine wave which is only slightly different (i.e. fractionally out of tune) they will interfere with each other, creating that "fading in and out" effect that we listen for when tuning using harmonics.  They will fade in and out at a rate equal to the frequency difference (which is why you can only hear it when you are very close...tuned to within a few Hz)

These graphs illustrate this pretty well.  Here are harmonics on two strings (6th string 5th fret and 5th string 7th fret) which are slightly out of tune:-



The "waviness" in the signal shows the interference between the two (at ~3Hz, measured with the vertical dashed lines) which I can hear as the characteristic fading in and out.  When I correct the tuning and repeat the test...



...the "waviness" is gone.  This video illustrates what is going on:-

 

Finally, it is interesting to see the harmonic content of the same note played on two different strings.  Here's the open 5th:-



And here's the same A played on the 5th fret of the 6th string:-



Note the much stronger fundamental (110Hz) compared to the 1st harmonic.