It's getting to the pointy end of my prostate cancer and this blog becomes what it is titled: Evanescent coder = fading programmer.
I don't expect to see Christmas this year. There's no more treatments available, only spot measures like radiotherapy and even that is close to its limits.
I don't have any "words of wisdom" to impart to you. If I ever had any, you would have heard me spouting them over the years.
I want you to know how much I love you but I hope you know this. When I held you in my arms the day you were born I remember being surprised that I could feel so much love for someone. And my love for you has grown over the years.
I've watched you struggle with your Aspergers' and felt desperate that I couldn't help and yet you have learned to live with the panic and isolation it brings and despite it you have grown into a strong but gentle man, capable and reliable in everything.
Monday, February 22, 2016
Sunday, September 27, 2015
Stamp sorter part 2
I spoke with friend about whether he'd be willing to purchase the hardware for himself and I would program it. My payment would be keeping ownership of the software. He thinks it's a good idea.
However he suggested that I get the image recognition software working first before purchasing the robot arm. No unnecessary expense if software is not feasible. I think that's a good idea.
So I'll order a BeagleBone Green and camera module and see what we can do.
Interestingly for me this device is just what I want for my Threesus robot.
However he suggested that I get the image recognition software working first before purchasing the robot arm. No unnecessary expense if software is not feasible. I think that's a good idea.
So I'll order a BeagleBone Green and camera module and see what we can do.
Interestingly for me this device is just what I want for my Threesus robot.
Saturday, September 26, 2015
Another possible gadget to make some money.
A friend makes a few dollars by buying large quantities of stamped envelopes, soaking the stamps off and selling the used stamps to stamp collectors for various prices depending on the quality of the stamps.
However, before selling the used stamps, he culls through the batch, looking for uncancelled stamps which can be used as mint originals. He is able to sell bundles of these uncancelled stamps for half their face value to small businesses wishing to save money on their mailing costs. Small businesses, small batches, small numbers all round.
So we need a (one-off!) device to do the following:
However, before selling the used stamps, he culls through the batch, looking for uncancelled stamps which can be used as mint originals. He is able to sell bundles of these uncancelled stamps for half their face value to small businesses wishing to save money on their mailing costs. Small businesses, small batches, small numbers all round.
So we need a (one-off!) device to do the following:
- Scan the stamp
- Identify which stamp it is by comparison with a catalog of current issues
- Compare how close the image is to a mint image
- Put the stamp in some sort of "uncancelled" bin, ready for re-use.
- Raspberry Pi 2 (or BeagleBoneGreen) with camera module
- A pick and place arm with vacuum head to
- lift a stamp from an unordered pile
- rotate the stamp to a normalised position
- hold stamp in front of camera
- place stamp in "used" or "unused" bin depending on id
Friday, September 25, 2015
Making a gadget factory.
I've been overwhelmed by illness for the past few months. Nausea, fatigue, confuddled thoughts. Basically a write-off.
My friend Marty has been in a similar situation after coming off his motor bike. He however seems to be healing much faster than I and is madly thinking up gadgets he and I can design and assemble.
I've wanted to put together a gadget factory for a while now. It's hard to justify the cost of some of the tools you need to assemble gadgets these days. They're heaps cheaper than when I was starting out as a gadget maker in the '70s but it's still a lot of money for me now that I'm attempting to live on my pension. So it occurred to me that if we could actually sell some of these gadgets it might make the factory a bit better than a sinkhole into which I pour my dollars.
To add to the impetus to start a business is the weakening Australian dollar. Makes the gadgets even cheaper to US and EU customers. And I also discovered another effect of the weak dollar. Some Australian Ebay sellers have purchased stock from China in USD. It literally halves the price of one expensive tool I was looking at.
So some gadgets we've been toying with.
My friend Marty has been in a similar situation after coming off his motor bike. He however seems to be healing much faster than I and is madly thinking up gadgets he and I can design and assemble.
I've wanted to put together a gadget factory for a while now. It's hard to justify the cost of some of the tools you need to assemble gadgets these days. They're heaps cheaper than when I was starting out as a gadget maker in the '70s but it's still a lot of money for me now that I'm attempting to live on my pension. So it occurred to me that if we could actually sell some of these gadgets it might make the factory a bit better than a sinkhole into which I pour my dollars.
To add to the impetus to start a business is the weakening Australian dollar. Makes the gadgets even cheaper to US and EU customers. And I also discovered another effect of the weak dollar. Some Australian Ebay sellers have purchased stock from China in USD. It literally halves the price of one expensive tool I was looking at.
So some gadgets we've been toying with.
- Marty thinks an automatic "fall over" light for bikes would be useful. Simple, easy to design and build, a ready market among his bikie friends.
- Elevator music player + WiFi repeater. Repeaters are dirt cheap but if you could add a web site to the repeater which replays non-repeating, synthesised guitar music, every office can plug one in and switch people to the music site when they are on hold. No music royalties, no maintenance to change DVDs etc
- Credit-card-sized tin with accelerometers to act as an effect pedal. Ultra-low powered circuit (3xAAAs for a year). Basic effects by default, programmable over WiFi and/or BLE (use Apple Watch as control unit).
- Simplified iPhone and/or AW app to control RGB LED strips.
Perl Threesus works but not well enough.
As expected I've not been able to speed up my Perl5(or 6) version of Threesus AI to compete with the C# version. It's possible I could attempt to optimise every line of code but I really don't want to waste the time.
I think I will wait for a more usable version of RPerl.org.
I think I will wait for a more usable version of RPerl.org.
Tuesday, July 14, 2015
Coding a C# version of Threesus AI into Perl5
I mentioned back in March one of my "big" projects was to convert the Threesus AI from C# to Perl5. Many reasons for this other than sheer stupidity :). I know Perl5 well and can think in Perl. I don't know C# and I have no idea if some C# code is brilliant or simply a mistake.
Another reason is that Perl5 is much more portable than C#, which is largely Win-based. Another reason is that RPerl is starting to be usable but requires that I use 'vanilla' Perl. (Actually my code tends to be pretty plain. perltidy doesn't complain much :)
Another reason is that Perl5 is much more portable than C#, which is largely Win-based. Another reason is that RPerl is starting to be usable but requires that I use 'vanilla' Perl. (Actually my code tends to be pretty plain. perltidy doesn't complain much :)
Moo
So my first attempt involved modelling all the C# classes with roughly equivalent Moo classes. I'm keeping the code in a Github repo, Games-Threesus.
vec vs bits
I quickly decided that all the C# bit-wrangling was not for me so I started using an unknown (to me) Perl operator called vec. It allows me to code a 4x4 Threes! board into an 8-byte string (16 cells requiring 4 bits to encode its value = 64 bits) but each nibble is individually addressable. Turns out we only need 16 values to describe each card/cell which fits into 4 bits nicely.
Slowwwww
Well I knew it was going to be slow. The C# code compiles down to very efficient binary code and also takes advantage of multi-CPUs if they are present. The Perl code is big and slow. The recursive calling of the major methods adds hugely to the memory consumption.
First move!
Despite all the huge overhead involved it actually gave me a move command ('SWIPE Up') in a reasonable time. But at this stage there are so many warnings and error messages that I don't know if it worked or not. Single-stepping through the code allowed me to verify that the game simulation is accurate.
Time to rip out the plumbing
I used Moo to model the C# classes because I have a basic knowledge of its use. However it became apparent while single-stepping the code that I don't have enough knowledge of Moo's internals and I wasn't able to follow large swathes of Moo utility code.
However when I stand back a bit and look at what I'm using Moo classes and methods for, it's not actually very much and the down side is a lot of overhead code which I don't understand. With an eye to RPerl, replacing Moo with 'bless'ed objects will allow me to pinpoint bottlenecks quicker.
Also, I realised I've been using 'constant' for no good reason. Simply using upper-case names is all I really need for the constants in this code.
Wednesday, April 1, 2015
Practically everything that could go wrong with my RigidBot 3D printer went wrong.
After replacing the main circuit board with a RUMBA to no effect, replacing the extruder motor to no effect, replacing the extruder flat cable to no effect and burning filament dregs out of the extruder nozzle to no effect, I happened to notice a small electrical flash in the connector from the extruder motor to the circuit board socket.
So I chopped off the extruder motor socket and soldered on individual sockets for each of the four wires. Finally, at last, I got a proper response out of the extruder motor. So I ran tests for a few hours and it all seemed to be OK and then the extruder stopped for no obvious reason.
Well the only piece in the whole extrusion chain that I hadn't replaced or repaired was the teflon tube in the filament pre-heater. And sure enough when I extracted it I found it had partially melted to partially fill the filament hole, making proper extrusion impossible. A bit of creative gouging with a small drill bit restored the hole sufficiently to allow filament to pass through.
And finally, after more hours of testing, I have a working 3D printer. I put all the original parts back in and it still worked :).
So I've started trying to catch up on my backlog of needed enclosures. Obviously I don't need a special enclosure for a RUMBA board because I've put the original board back into the enclosure already supplied.
I tried making an enclosure for my Parallella. This required me to re-construct the SolidWorks example on Thingiverse here into a parametric model I could change to suit my requirements, specifically I only had a 40mm x 40mm fan and I wanted to continue using the existing 5V power socket.
So I chopped off the extruder motor socket and soldered on individual sockets for each of the four wires. Finally, at last, I got a proper response out of the extruder motor. So I ran tests for a few hours and it all seemed to be OK and then the extruder stopped for no obvious reason.
Well the only piece in the whole extrusion chain that I hadn't replaced or repaired was the teflon tube in the filament pre-heater. And sure enough when I extracted it I found it had partially melted to partially fill the filament hole, making proper extrusion impossible. A bit of creative gouging with a small drill bit restored the hole sufficiently to allow filament to pass through.
And finally, after more hours of testing, I have a working 3D printer. I put all the original parts back in and it still worked :).
So I've started trying to catch up on my backlog of needed enclosures. Obviously I don't need a special enclosure for a RUMBA board because I've put the original board back into the enclosure already supplied.
I tried making an enclosure for my Parallella. This required me to re-construct the SolidWorks example on Thingiverse here into a parametric model I could change to suit my requirements, specifically I only had a 40mm x 40mm fan and I wanted to continue using the existing 5V power socket.
Yak-shaving to make a 3D model
I wondered if OpenSCAD was the quickest and easiest open source 3D modelling program. I wasn't prepared to pay the SolidWorks licence fee considering how infrequently I would be likely to use it. I looked at FreeCAD and it seems an interesting parametric design program. Then quite fortuitously I found SolveSpace which has only recently been made open-source but seems much more powerful and capable than FreeCAD. And there is a Mac OS X version as well. The trouble was, for the simple box enclosures I want to make OpenSCAD simply makes better sense to me. I suppose it appeals to my programmer background.
Plan B
In the meantime, I ordered an enclosure and cooling fan for the Parallella from Ground Electronics just in case I found making a usable enclosure too tedious or too difficult. The Plan B case arrived today and although I was very close to a working enclosure, I couldn't get the correct screws so it seemed easier to use this enclosure and get on with other things.
Tuesday, March 3, 2015
RigidBot projects
The list of 3D printed artefacts I need is growing longer each week. In no particular order:
- If I decide to continue with the RUMBA controller board, I will need an enclosure for it.
- I need an enclosure for the Parallella which will hold the fan over the Zynq chip.
- I want a translucent enclosure for the CharlieCube I made late last year.
- My "grand project" is a Perl 6 implementation of the Threesus project. The original project has a video camera watching an iPad screen, OCRing the image it sees, deciding the best next move then activating one of two stepper motors to swipe the iPad screen up or down, left or right. Not sure if I want to get to the stage of using the stepper motors (although I have a couple in my spares box). I want to use my Raspberry Pi with camera module for the video processing, so I would like to build an enclosure to hold the RPi and camera in a config which makes it usable for OCRing an iPad (or iPhone).
- An enclosure for a reflow oven controller.
- An enclosure for a coffee bean roaster controller I am designing for an Elektor competition.
RigidBot repairs
The sharp-witted amongst us will have noted in my previous blog that I had found the cause of all the problems with the RigidBot, but I didn't recognise it even while I was writing about it.
The open-circuit on pin 1 of the extruder flat cable is a sufficient explanation of all the problems the printer showed. I simply didn't follow an orderly chain of testing the components and cables to isolate the cable.
Anyway I've ordered some replacement cable and connectors and I will now have to wait the three or four weeks it takes will they arrive.
My hypothesis is that I will be able to return the original main board to the printer, replace the faulty cable and everything will work correctly. And if it doesn't, I now have so many replacement parts that I can replace nearly all of the fragile parts of the printer to keep it running.
The open-circuit on pin 1 of the extruder flat cable is a sufficient explanation of all the problems the printer showed. I simply didn't follow an orderly chain of testing the components and cables to isolate the cable.
Anyway I've ordered some replacement cable and connectors and I will now have to wait the three or four weeks it takes will they arrive.
My hypothesis is that I will be able to return the original main board to the printer, replace the faulty cable and everything will work correctly. And if it doesn't, I now have so many replacement parts that I can replace nearly all of the fragile parts of the printer to keep it running.
Monday, March 2, 2015
RigidBot tale of woe
My pretty RigidBot(RB) was churning out pretty and occasionally useful things for a few weeks after it arrived in October. I made every mistake there is to make with the RB until I finally got it printing reasonably accurate and repeatable things. I even ordered some "crystal" ABS filament with the intention of putting a translucent cover over the CharlieCube.
Then last December the extruder died. I'm not sure if I was the cause. I had accidentally put a knot in the filament and left the printer running overnight. So it spent about 12 hours pulling the same section of filament.
Initially I thought one of the coils in the stepper motor had burnt out or partially degraded. So I ordered a replacement motor and went on to other things. But the motor I'd ordered was the wrong one and it required a higher current. So I ordered another one. But this one didn't have the flat on the shaft. D'oh!
In the meantime I tried swapping motors around and eventually realised it was the driver that was faulty, not the motor.
Pity that the RB main board is an all-in-one board. Apparently it was done to "save money". But according to the RB wiki, Invent-A-Part (IAP) had to re-work every single board because the Chinese supplier had cheated on a whole swag of parts (without mentioning it to IAP of course) and the boards were dying all over the place. So much for saving money.
A few hundred RB owners quickly realised that the RB main board was simply a RUMBA board with stepper driver modules built onto the PCB instead of being pluggable (and hence replaceable). There was sufficient demand that one enterprising chap built a (BYEBYE) breakout board for the RB extruder cable so it wasn't necessary to completely re-wire the RB to replace the main board.
So I ordered a Geeetech RUMBA board + 5 x A4988 modules (+ heatsinks) and a BYEBYE board and forgot about the RB for six weeks and worked on other stuff.
The RUMBA and BYEBYE boards arrived last week a day apart and so began my tale of woe (not actually woe, just a huge exercise in yak-shaving).
All the RUMBA connections are screw terminals. I feel happier with these. No stuffing around with crimping tools etc. First I had to unsolder the thick power cable from the power supply board and replace it with bare wires I could put in the screw terminals. I don't have a soldering iron with sufficient wattage to melt the thick layers of solder holding the wires to the PS PCB. Luckily I do have a hot air gun for SMD soldering and when I cranked it up, I was able to melt the solder enough to extract the wires.
The next task was making connections from the BYEBYE board to the RUMBA board. Last year I had purchased a 'Make your own cable' kit from SeeedStudio which proved really helpful for keeping wires in some sort of order otherwise it would have been an even bigger rat's nest. (In retrospect, I should also have purchased the 'Make your own keyed cable' kit as many of the connections would have been cleaner with a keyed plug. No harm done though.)
So after a couple of days wiring and checking and checking again, I turned on the power and waited for puffs of smoke or flames or whatever. Nothing. Just some lights which should have been on.
Then began the task of programming the RUMBA. I was following Jonathan Roscoe's excellent blog on just this exercise. I've had to learn heaps of details about the RB (and 3D printers in general).
First I had to learn how to flash the Marlin firmware into the RUMBA. Took me a while to realise the RUMBA is simply an Arduino with some pre-wired peripherals (e.g. stepper motors, thermistors, heaters etc. etc.). Once that got through my thick skull, I was able to use all I had learned playing with Arduinos.
I've been using Repetier-Host(RH) to drive the RB and the Panel tab is particularly useful for testing individual parts of the RB. Using RH I was able to work out that the wiring for the motors on the RUMBA is different from the RB main board. The X, Y and Z motors were going in reverse. Simply required swapping the Blue and Red wires. The Z-steppers weren't responding correctly and I had to tear the RB almost completely apart before I was able to isolate each Z-stepper and verify that the A4988 module was faulty. Luckily when the Geeetech package arrived, they'd included 6 x A4988 instead of the 5 which I thought I was ordering. So after swapping in one of the spares the Z-axis worked correctly. I then had to put the RB back together again.
So finally I was ready to test the extruder motor, the original cause of all this hoohah. And it didn't work. Maybe a connection wasn't working. I traced the wires and discovered the BYEBYE board is missing a trace altogether. [Ed: no it was my faulty circuit tester; the board is fine.] So I tried plugging the extruder motor directly into the RUMBA and it sat there buzzing. We've heard that before, it means a faulty A4988. Luckily I had one more spare. I swapped it in and the extruder motor now turned correctly. Two faulty A4988s! I wonder if I accidentally damaged them when I put the heat sinks on.
So back to the wiring harness. Discovered that pin 1 in flat cable is not connected. Was it always open-circuit? Presumably not, otherwise motor would never have worked.
Anyway this gives me an excuse to take the whole extruder apart and put back the original stepper motor with the flattened shaft. Talk about an exercise in futility aka yak-shaving. And now I have to find where to get a replacement flat cable.
Then last December the extruder died. I'm not sure if I was the cause. I had accidentally put a knot in the filament and left the printer running overnight. So it spent about 12 hours pulling the same section of filament.
Initially I thought one of the coils in the stepper motor had burnt out or partially degraded. So I ordered a replacement motor and went on to other things. But the motor I'd ordered was the wrong one and it required a higher current. So I ordered another one. But this one didn't have the flat on the shaft. D'oh!
In the meantime I tried swapping motors around and eventually realised it was the driver that was faulty, not the motor.
Pity that the RB main board is an all-in-one board. Apparently it was done to "save money". But according to the RB wiki, Invent-A-Part (IAP) had to re-work every single board because the Chinese supplier had cheated on a whole swag of parts (without mentioning it to IAP of course) and the boards were dying all over the place. So much for saving money.
A few hundred RB owners quickly realised that the RB main board was simply a RUMBA board with stepper driver modules built onto the PCB instead of being pluggable (and hence replaceable). There was sufficient demand that one enterprising chap built a (BYEBYE) breakout board for the RB extruder cable so it wasn't necessary to completely re-wire the RB to replace the main board.
So I ordered a Geeetech RUMBA board + 5 x A4988 modules (+ heatsinks) and a BYEBYE board and forgot about the RB for six weeks and worked on other stuff.
The RUMBA and BYEBYE boards arrived last week a day apart and so began my tale of woe (not actually woe, just a huge exercise in yak-shaving).
All the RUMBA connections are screw terminals. I feel happier with these. No stuffing around with crimping tools etc. First I had to unsolder the thick power cable from the power supply board and replace it with bare wires I could put in the screw terminals. I don't have a soldering iron with sufficient wattage to melt the thick layers of solder holding the wires to the PS PCB. Luckily I do have a hot air gun for SMD soldering and when I cranked it up, I was able to melt the solder enough to extract the wires.
The next task was making connections from the BYEBYE board to the RUMBA board. Last year I had purchased a 'Make your own cable' kit from SeeedStudio which proved really helpful for keeping wires in some sort of order otherwise it would have been an even bigger rat's nest. (In retrospect, I should also have purchased the 'Make your own keyed cable' kit as many of the connections would have been cleaner with a keyed plug. No harm done though.)
So after a couple of days wiring and checking and checking again, I turned on the power and waited for puffs of smoke or flames or whatever. Nothing. Just some lights which should have been on.
Then began the task of programming the RUMBA. I was following Jonathan Roscoe's excellent blog on just this exercise. I've had to learn heaps of details about the RB (and 3D printers in general).
First I had to learn how to flash the Marlin firmware into the RUMBA. Took me a while to realise the RUMBA is simply an Arduino with some pre-wired peripherals (e.g. stepper motors, thermistors, heaters etc. etc.). Once that got through my thick skull, I was able to use all I had learned playing with Arduinos.
I've been using Repetier-Host(RH) to drive the RB and the Panel tab is particularly useful for testing individual parts of the RB. Using RH I was able to work out that the wiring for the motors on the RUMBA is different from the RB main board. The X, Y and Z motors were going in reverse. Simply required swapping the Blue and Red wires. The Z-steppers weren't responding correctly and I had to tear the RB almost completely apart before I was able to isolate each Z-stepper and verify that the A4988 module was faulty. Luckily when the Geeetech package arrived, they'd included 6 x A4988 instead of the 5 which I thought I was ordering. So after swapping in one of the spares the Z-axis worked correctly. I then had to put the RB back together again.
So finally I was ready to test the extruder motor, the original cause of all this hoohah. And it didn't work. Maybe a connection wasn't working. I traced the wires and discovered the BYEBYE board is missing a trace altogether. [Ed: no it was my faulty circuit tester; the board is fine.] So I tried plugging the extruder motor directly into the RUMBA and it sat there buzzing. We've heard that before, it means a faulty A4988. Luckily I had one more spare. I swapped it in and the extruder motor now turned correctly. Two faulty A4988s! I wonder if I accidentally damaged them when I put the heat sinks on.
So back to the wiring harness. Discovered that pin 1 in flat cable is not connected. Was it always open-circuit? Presumably not, otherwise motor would never have worked.
Anyway this gives me an excuse to take the whole extruder apart and put back the original stepper motor with the flattened shaft. Talk about an exercise in futility aka yak-shaving. And now I have to find where to get a replacement flat cable.
Friday, October 10, 2014
May your antiquated book publishing models die, die, die!
Read an interesting review of what appears to be an interesting book, Hieroglyph.
I read the sample chapter and was ready to buy it. Book was "released" 14 Sep 2014. Clicked on the ebook button so I could read it straight away. "This publication is not available in your area" (Australia). Huh?
Oh well, maybe Amazon.com could help. Nope: "we do not have pricing for the Kindle version yet". Paperback? "Not available till 2015".
So here is a book publisher which will not sell me a book I would like to buy right now.
I can guess why of course. They want to sell hardcover versions for a few months, then paperback versions, then ebooks but only in USA. Then sometime in the middle of next year they'll get around to making ebook version available to Oz.
So of course I will wait till it's available as a Torrent, download it and pay nothing. Or simply forget about it. There are some people who like to buy hard copies of books. I'm not one of them. I don't have the room any more. I only buy electronic versions. (Yes, I do buy (some) ebooks, usually on the spur of the moment of course.)
And the final irony is that the book is about optimistic techno futures. Hah! hah!
I read the sample chapter and was ready to buy it. Book was "released" 14 Sep 2014. Clicked on the ebook button so I could read it straight away. "This publication is not available in your area" (Australia). Huh?
Oh well, maybe Amazon.com could help. Nope: "we do not have pricing for the Kindle version yet". Paperback? "Not available till 2015".
So here is a book publisher which will not sell me a book I would like to buy right now.
I can guess why of course. They want to sell hardcover versions for a few months, then paperback versions, then ebooks but only in USA. Then sometime in the middle of next year they'll get around to making ebook version available to Oz.
So of course I will wait till it's available as a Torrent, download it and pay nothing. Or simply forget about it. There are some people who like to buy hard copies of books. I'm not one of them. I don't have the room any more. I only buy electronic versions. (Yes, I do buy (some) ebooks, usually on the spur of the moment of course.)
And the final irony is that the book is about optimistic techno futures. Hah! hah!
Rigidbot arrived!
Last week my almost despaired of Rigidbot 3D printer kit arrived. Project was successfully funded in May 2013 and here it is October 2014. Incredible tale of what can go wrong when you're trying to start a startup. All the usual suspects: dodgy suppliers substituting cheaper, lower quality parts; huge blowout in shipping costs; China Post doing it's best to completely destroy itself by never actually shipping what they said they did.
Anyway here's my baby:
Here's some of my first experiments in extruding:
Here's why I have a lot to learn (that box corner is not meant to lift up):
And here's why the Rigidbot is an incredible kit. It can basically be assembled with one Allen key (supplied), but there's a couple of parts need smaller keys (also supplied). However, it also needs a mallet (not supplied) because some of the tubes/rods simply do not fit easily inside some of the plastic fittings.
Anyway here's my baby:
Here's some of my first experiments in extruding:
Here's why I have a lot to learn (that box corner is not meant to lift up):
And here's why the Rigidbot is an incredible kit. It can basically be assembled with one Allen key (supplied), but there's a couple of parts need smaller keys (also supplied). However, it also needs a mallet (not supplied) because some of the tubes/rods simply do not fit easily inside some of the plastic fittings.
Now I have to learn how to design parts from scratch as well as re-use existing designs. Thingiverse.com has a huge number of designs to start with. But I've also had to learn to use OpenSCAD to design the box. (I tried simply using a Gcode file offered here but the differences between Felix printers and Rigidbots are too great. And I also discovered there are no usable Gcode to STL converters any more. There might have been a couple of years ago but not maintained now.)
Then I had to learn about various slicers and dicers to generate Gcode from the design and upload the print task to the Rigidbot. Eventually settled on Repetier-Host for Mac for initial prototyping but also installed Octoprint on my RPi so I can offload print tasks to RPi while I continue with MacBook.
Friday, July 11, 2014
A DHCP client (fail?)
I was hoping to implement a DHCP client in the GA144 as mentioned in a previous blog. I'm more familiar with Perl than C these days so I downloaded the Net::DHCP::Packet module from CPAN and proceeded to use some of the examples to test out the DHCP server on my router. It's a lot easier to single-step through Perl code (for me at least) than using GDB on a compiled C program.
The sample dhcp daemon and test scripts work well. But when I tried talking to my router I was able to get a DHCPOFFER but was unable to get a DHCPACK reply. And even that would only work when I used the MAC address of my Mac(!). I couldn't use any other MAC address. I just don't know enough about DHCP to know if the router is acting correctly or not. The router's log says it receives the DHCP request and that it sends an OFFER and an ACK but the ACK packet doesn't seem to arrive. Possibly issues with firewalls etc.
There's a lot of code in Net::DHCP::Packet and it occurred to me that a DHCP client is not really necessary for this project. Nice to have but maybe not this iteration. I can load the IP address I've assigned to it using the code in the previous blog so there will be no conflict with my network devices.
So I'll proceed to step 2: a 'Hello world' server which simply sends the same reply to whatever inquiry it receives.
The sample dhcp daemon and test scripts work well. But when I tried talking to my router I was able to get a DHCPOFFER but was unable to get a DHCPACK reply. And even that would only work when I used the MAC address of my Mac(!). I couldn't use any other MAC address. I just don't know enough about DHCP to know if the router is acting correctly or not. The router's log says it receives the DHCP request and that it sends an OFFER and an ACK but the ACK packet doesn't seem to arrive. Possibly issues with firewalls etc.
There's a lot of code in Net::DHCP::Packet and it occurred to me that a DHCP client is not really necessary for this project. Nice to have but maybe not this iteration. I can load the IP address I've assigned to it using the code in the previous blog so there will be no conflict with my network devices.
So I'll proceed to step 2: a 'Hello world' server which simply sends the same reply to whatever inquiry it receives.
Tuesday, July 1, 2014
Make a PCB pt2
I received the parts for the GettingToBlinky PCB I talked about in a previous blog. And they sat there for over a week while I caught up with a few other tasks I had.
Today I felt like whiling away a couple of hours without straining my brain too much and building a Blinky device seemed like the perfect task. I love the smell of burning flux in the morning.
Despite all my mutterings about using solder paste, a pick and place tool and a heat gun, I realised the parts in this project are quite large. Certainly easy enough to see under a magnifying lamp to hand solder. So with help of some Blu-Tack to hold the board still and a bit more Blu-Tack on the end of a screwdriver to lift the components out of their containers and place them on the board I soldered it all together.
I started with the 7555 because it has the smallest pads and is in the centre of the board so I didn't want other components getting in the way. Then I added the diode, resistors and capacitor in that order. The LDR is actually a big large for the thru-holes I placed for it but long leads made it easy to get it into place.
So then it was time to solder the battery holder in place and finally we were ready to roll!
I inserted the battery after checking and re-checking the polarity and...
Nothing. No blinky!
I pulled out the battery just in case something was cooking and proceeded to measure every component and trace I could. Everything checked out.
So I re-inserted the battery and measured the voltage across pin 8 (Vdd) and pin 1 (GND) of the 7555. Nothing!
A bit closer inspection of the battery holder made me suspect that I might have some sort of short. So I partially inserted the battery and yay! blinky! But if I pushed the battery fully into the clip it stopped. But nothing was shorting. I looked at the battery and I looked at the board where it connects and it looks like the solder pad is too flat or the battery flexes slightly concavely at that point. Anyway the solution was obvious. I unsoldered the battery clip, added a large drop of solder to the GND pad on the board, resoldered the clip and reinserted the battery and yay! blinky! And I could push the battery fully into the clip now and it continues working.
Here's the "offending" centre GND pad:
Today I felt like whiling away a couple of hours without straining my brain too much and building a Blinky device seemed like the perfect task. I love the smell of burning flux in the morning.
Despite all my mutterings about using solder paste, a pick and place tool and a heat gun, I realised the parts in this project are quite large. Certainly easy enough to see under a magnifying lamp to hand solder. So with help of some Blu-Tack to hold the board still and a bit more Blu-Tack on the end of a screwdriver to lift the components out of their containers and place them on the board I soldered it all together.
I started with the 7555 because it has the smallest pads and is in the centre of the board so I didn't want other components getting in the way. Then I added the diode, resistors and capacitor in that order. The LDR is actually a big large for the thru-holes I placed for it but long leads made it easy to get it into place.
So then it was time to solder the battery holder in place and finally we were ready to roll!
I inserted the battery after checking and re-checking the polarity and...
Nothing. No blinky!
I pulled out the battery just in case something was cooking and proceeded to measure every component and trace I could. Everything checked out.
So I re-inserted the battery and measured the voltage across pin 8 (Vdd) and pin 1 (GND) of the 7555. Nothing!
A bit closer inspection of the battery holder made me suspect that I might have some sort of short. So I partially inserted the battery and yay! blinky! But if I pushed the battery fully into the clip it stopped. But nothing was shorting. I looked at the battery and I looked at the board where it connects and it looks like the solder pad is too flat or the battery flexes slightly concavely at that point. Anyway the solution was obvious. I unsoldered the battery clip, added a large drop of solder to the GND pad on the board, resoldered the clip and reinserted the battery and yay! blinky! And I could push the battery fully into the clip now and it continues working.
Here's the "offending" centre GND pad:
I had to add a blob of solder to it to raise it's height enough to contact the battery negative. Here's the clip and battery in place:
And finally, Blinky!
Some lessons for the future
The blink rate is supposed to vary depending on how much light falls on the LDR. The GettingToBlinky tutorial left the actual value or even the range undisclosed. I picked a value at random from Digi-Key (16-33K) but this is probably way too low considering it's connected to a 470K resistor. Probably should have been 160-330K. No harm done but unless I knew the blink rate is supposed to vary, I probably wouldn't notice the slight change that does occur as I move the LDR from bright light to darkness.
The second lesson is far more serious, and potentially dangerous. The battery clip touches one of the LDR leads:
Fortuitously, this LDR lead actually does connect to the positive terminal of the battery and so no harm done. However the potential for disaster is quite obvious. And again the solution is so simple. I had plenty of room on the board to move the thru holes for the LDR away from the battery clip but I had left the outline of the original SMD version and not updated it to that of the thru hole version. As a result I didn't see the potential conflict.
Which brings me to the third lesson. I made the mistake with the LDR and battery clip placement because I purchased these components blind, relying on diagrams and data sheets. In all my years as an electrical engineer, I never did that. I always insisted on having the actual components in my hands so I could measure them myself and see how they all fitted together. Digi-Key and similar suppliers are wonders compared to the old days but the potential for mistakes seems to rise when one is relying solely on data sheets.
On the other hand, in this brave new world where I can design and have these boards built for AU$1.40 plus AU$3.00 for components each, I think I can live with the cost of ordering sight unseen. The savings in time and money is enormous.
So tomorrow I will try out reflow soldering with solder paste and a heat gun.
Sunday, June 29, 2014
Interfacing Wiz550io to GA144
(aka: An Internet music player pt4)
Spent a week writing some low-level Forth words (subroutines) to drive the SPI interface on the wiz550io. Then realised that most of them already exist in the ROMs included with nodes 705 and 008 on the GA144.
Most of my time was spent trying to understand the heaps of C code out there for Arduinos and other microcontrollers. Wiznet has released source code for its drivers and, because it has to cover all usage cases, it is incredibly detailed and wordy. I quickly decided that for the music player I would only ever be reading and writing multiple bytes so there is no need to handle the Fixed Data Modes. Likewise I will only be supplying a single response to any client request: a stream of HTTP packets containing MP3 data. (Although I will also add code to query the DHCP server and obtain an IP address.)
I'm slowly starting to appreciate how good ArrayForth is.
To put things in perspective, the C source code from Wiznet for use with Arduino comes to 2711 lines. Admittedly much of this is comments. The code below for the same basic functions comes to 78 lines of which about 50% is comments.
I had a couple of actual hardware issues. When I plugged in the Wiz550io, the 3.3v rail sank to 2.9v. I quickly realised that it isn't properly regulated. So I wired an el-cheapo buck regulator board into the 5v rail to supply 3.3v and it's rock solid now.
Another issue was that (I think) I was clocking the Wiz too fast. I copied an SPI routine in the ArrayForth example code for reading and writing flash RAM and it was written to maximize data transfer speeds. I changed the delay factor from 20 to 1000 and transfers seem very stable now.
Another issue was that I wasn't watching very carefully when I wrote the routine to write to the IO pins on the GA144 and wasn't giving it enough settling time. As a result I was getting occasional glitches on the chip select line. There are lots of warnings in the user guide and I fell straight into the trap. Simple solution is to add a couple of no-ops after the write.
The code below uses two GA144 nodes: node 705 because it and node 008 are the only nodes with all the i/o pins needed for SPI interfacing and node 706 because I didn't want to burden 705 with time-wasting code which varies the clock speed plus it makes it easier to separate the work load. Node 706 pre-shifts the write bytes before sending them to node 705. Meanwhile 705 can be getting on with the task of changing i/o pins levels and pausing to allow them to settle without holding up node 706.
Eventually I will need to rewrite code in 706 to read and write bytes from other nodes via 'wires' (same as used in musicbox).
Open Workbench Logic Sniffer
I used this US$50 16-channel logic analyser (and software) to follow the SPI bus exchanges and it has got to be the best value for money in the electronics world. Not only does it capture logic levels upto 50Mhz but the software also includes protocol analysers, including an SPI analyser.
The screenshot (click image to enlarge) shows node 705 sending a 4-byte IP address (192.168.1.228) to the wiz for loading into the device's Source IP Address registers (0x0f-0x12). It then reads the registers back and stores them in the data stack of node 706.
Pinging the Wiz550io
As luck would have it, my home LAN uses 192.168.1.xxx subnet and the default startup IP for the Wiz is 192.168.1.2 and it's otherwise unused on my LAN. So I plugged the Wiz into it's socket on the EVB001, turned on the 3.3v supply and plugged an Ethernet cable into it from the router. Then I ping'ed the IP address and the Wiz responded. I unplugged the Wiz and pinged again and nothing answered (so I knew there wasn't another device on the LAN with the same IP :). Similarly after running the code below to change the IP address of the Wiz I was again able to ping it at 192.168.1.228 confirming the SPI upload of the IP address.
Next tasks
So now I need to add the DHCP client and a simple HTTP 'Hello World' server before tackling the huge task of writing an MP3 encoder.
The code
1018 list
spi interface to wiz550io705 node 0 orgstart 00 left a! io b!2 20 1000 dup -++ halfnxt @ push ex . nxt ;
done 09 -++ !b . . ;!8 8obits drop ;!24 @ 8obits 0f !8 @ !8 ;
addsel 11 dup select !24 ;
bytout 13 @ for @ !8 next done ;
byte 17 dup dup or 7 push ibits ;bytin 1a @ for byte ! next done ; 1e
start init regs a and b. Load stack with delay factor. Set pins 1(CLK) and 3(CS) high and 5(MOSI) low
nxt read address of next word to run from left port, push into return stack and ex to jump to word.
done set cs and clk high.
!8 use rom word 8obits to clock out 8 bits in reg t.
!24 clock out 16 bits in t, drop t then clock 8 bits out of next stack word.
addsel enable cs pin 3 then clock out 24 bits to select address in wiz. Also set r/w bit.
bytout read num of bytes to output from left port, then clock each set of bits out.
byte clock 8 bits into reg t.
bytin read num of bytes to input from left port, input each byte then send it to left port.
1020 list
nxt read address of next word to run from left port, push into return stack and ex to jump to word.
done set cs and clk high.
!8 use rom word 8obits to clock out 8 bits in reg t.
!24 clock out 16 bits in t, drop t then clock 8 bits out of next stack word.
addsel enable cs pin 3 then clock out 24 bits to select address in wiz. Also set r/w bit.
bytout read num of bytes to output from left port, then clock each set of bits out.
byte clock 8 bits into reg t.
bytin read num of bytes to input from left port, input each byte then send it to left port.
1020 list
drive spi 705 iface706 node 0 orglsh for 2* unext ;cmd push 9 lsh pop 1 lsh06 @p ! . ' addsel ' ! ! ;wbyt 09 @p ! ' bytout '
dup ! for 9 lsh ! next ;rbyt 10 @p ! ' bytin '
dup ! for @ unext ;start 14 left a!begin
4 f cmd
228 1 168 192 3 wbyt
0 f cmd
3 rbyt
warmend 28
lsh left shift
cmd left shift block select byte 10 bits, left shift address offset word 2 bits then pass s and t to node 705 to clock the 24 bits out to wiz.
wbyt write n bytes out using node 705 bytout word. shift each byte left by 10 bits prior to passing to bytout.
rbyt read n bytes into data stack.
start set a to left port, write IP address to wiz register then read IP address back in to leave it on stack.
1428 list ROM code
1014 list
1016 list
cmd left shift block select byte 10 bits, left shift address offset word 2 bits then pass s and t to node 705 to clock the 24 bits out to wiz.
wbyt write n bytes out using node 705 bytout word. shift each byte left by 10 bits prior to passing to bytout.
rbyt read n bytes into data stack.
start set a to left port, write IP address to wiz register then read IP address back in to leave it on stack.
1428 list ROM code
spi boot top/bot4 kind aa reset host
--- 2a lit ; do, ce-, clk
--+ 2b lit ;
+-- 3a lit ;
+-+ 3b lit ;
-++ 2f lit ; target
a1 org 1388 load relay
c2 org
8obits dw-dw' 7 for leap obit 2* *next ;
ibit c7 dw-dw'
@b . -if drop - 2* ; then drop 2* - ;
half ca dwc-dw !b over for . . unext ;
select cc dw-dw -++ half --+ half ;
obit d0 dw-dw then
-if +-- half +-+ half ; then
rbit d5 dw-dw --- half --+ half ;
18ibits d9 d-dw dup 17 for push
ibits begin rbit ibit - next ;
u2/ 2/ 1ffff and ; e1
a9 org
a9 warm await ;
aa 1430 load the rest
c1install via async bootstreamempty compilestreamer load framer loadasync frame ae fram ;wizspi align create708 705 to-1 ,
wizspi course2 fh load frame stream
serial load -canona-com sport ! a-bps bps ! !namtalk send2 706 hook panel705 +node 705 /ram 0 /p706 +node 706 /ram 14 /p2 0 705 hook Saturday, June 28, 2014
An Internet music player pt3
The three subprojects mentioned in previous posting can in fact be regarded as one project, viz., connect the Wiz550io to the GA144 and output the stream of PCM codes as a webserver response. Conversion to streamed MP3 is icing on the cake. Booting from Flash is additional icing. Designing and building a PCB to hold the circuit will be the icing, cream and two cherries on top.
I've added two headers to the EVB001 prototyping area and wired them to the SPI connections of node 705. Thankfully realised that Wiz550io uses 3.3v levels but node 705 pins are at 1.8v levels. So I wired one of the spare level converters into the path.
Running Wiz550io from 3.3v required me to add a 3.3v source. Using my Dangerous Prototypes ATX Breakout Board to supply the 3.3v, I also realised I could add a jumper to the 5v supply connection and remove the 5v wall wart I had been using.
So now, using the examples in Ch 9 of ArrayForth Users' Guide, I can switch on the SPI pins DO, CLK and CS and see 3.3v levels on the corresponding pins of the socket for the Wiz (MOSI, SCLK and SCSn). On the EVB001 these pins are hidden behind some selection logic but there are some test points on the board to verify the correct responses.
Next step is to write some code to run the Wiz550io from node 705. Need word to get an IP address from DHCP server on network (overriding default IP). Need word to echo text back to client.
I've added two headers to the EVB001 prototyping area and wired them to the SPI connections of node 705. Thankfully realised that Wiz550io uses 3.3v levels but node 705 pins are at 1.8v levels. So I wired one of the spare level converters into the path.
Running Wiz550io from 3.3v required me to add a 3.3v source. Using my Dangerous Prototypes ATX Breakout Board to supply the 3.3v, I also realised I could add a jumper to the 5v supply connection and remove the 5v wall wart I had been using.
So now, using the examples in Ch 9 of ArrayForth Users' Guide, I can switch on the SPI pins DO, CLK and CS and see 3.3v levels on the corresponding pins of the socket for the Wiz (MOSI, SCLK and SCSn). On the EVB001 these pins are hidden behind some selection logic but there are some test points on the board to verify the correct responses.
Next step is to write some code to run the Wiz550io from node 705. Need word to get an IP address from DHCP server on network (overriding default IP). Need word to echo text back to client.
Sunday, June 15, 2014
Make a PCB
As I noted in a previous blog I followed a YouTube tutorial on how to create a PCB with KiCAD. Having got that far I decided to order the boards from DirtyPCBs. AU$14 for 10 boards including postage is hard to beat.
The boards arrived last Thursday and they are beautiful! And red! (I had expected green.)
So I figured that having come this far I might as well complete the exercise.
Being too lazy to shop around I decided to use DigiKey to fulfill the Bill of Materials (BOM). For 10 boards the total came to AU$52 (plus $16 for solder paste).
The whole point of the PCB design was to use SMD components so I've also ordered various tools to assist SMD soldering. On ebay I bought a pick and place tool, hot air gun and USB microscope.
I'm not sure whether a stencil is needed but I want to try this. For the size of the board in this instance and the size of the components I suspect squeezing the solder paste from the tube will be sufficient.
I've been contemplating a toaster oven converted to reflow oven but it doesn't make much sense at this stage.
The boards arrived last Thursday and they are beautiful! And red! (I had expected green.)
So I figured that having come this far I might as well complete the exercise.
Being too lazy to shop around I decided to use DigiKey to fulfill the Bill of Materials (BOM). For 10 boards the total came to AU$52 (plus $16 for solder paste).
The whole point of the PCB design was to use SMD components so I've also ordered various tools to assist SMD soldering. On ebay I bought a pick and place tool, hot air gun and USB microscope.
I'm not sure whether a stencil is needed but I want to try this. For the size of the board in this instance and the size of the components I suspect squeezing the solder paste from the tube will be sufficient.
I've been contemplating a toaster oven converted to reflow oven but it doesn't make much sense at this stage.
An Internet music player pt 2
Although I only published pt 1 today, I actually wrote it a couple of weeks ago. In the meantime I have been attempting to move the music player app into the top right hand of the GA144 chip. Nothing I tried would make it work and when I took the app back to the original layout it wouldn't work either! Eventually I found my typing error. The good news is that I learned how to use the async loader so now can update apps in nodes almost instantaneously.
A couple of sub-projects have arisen. One is to down-sample the audio stream generated by the app. At the moment it is generating 18-bit PCM samples but for CD-quality sound I only need 16-bit samples. Down-sampling will also save in processing time.
Another sub-project is to output the PCM stream to a file on my laptop to verify the format. It should be a WAV-format stream but there will be some mystic hand-waving (pun!) to modify the stream into Wav format.
Another sub-project is the work out how to use the SPI Flash RAM to load the app code at startup and then get the Flash RAM out of the way so Wiz550io can use SPI bus.
Another sub-project is to write code to control Wiz550io from GA144 SPI node (node 705). As usual, C-code for Arduino seems incredibly verbose for what it has to do.
A couple of sub-projects have arisen. One is to down-sample the audio stream generated by the app. At the moment it is generating 18-bit PCM samples but for CD-quality sound I only need 16-bit samples. Down-sampling will also save in processing time.
Another sub-project is to output the PCM stream to a file on my laptop to verify the format. It should be a WAV-format stream but there will be some mystic hand-waving (pun!) to modify the stream into Wav format.
Another sub-project is the work out how to use the SPI Flash RAM to load the app code at startup and then get the Flash RAM out of the way so Wiz550io can use SPI bus.
Another sub-project is to write code to control Wiz550io from GA144 SPI node (node 705). As usual, C-code for Arduino seems incredibly verbose for what it has to do.
An Internet music player
Circuit Cellar is running a design challenge using the Wiz5500io module. I applied mainly to see if I could get one of the modules to try out. Deadline is 3rd August. I really haven't left enough time but I am trying to enhance a plucked string synthesiser app I wrote for the GA144 to output streamed MP3. This stream is then fed to the Wiz550io and voila! I have an Internet music player streaming beautiful meditation music.
It seemed quite simple at first. Then I looked at how one encodes MP3 frames and I'm starting to baulk.
The idea is to read 1152 16-bit, 44.1KHz PCM samples, split the samples into 32 frequency bands, run an FFT over the samples to work out which bands are dominant and use a psycho-acoustic model to select how much of each band to put into the output frame. Add in a Huffman encoder and we are left with a lot of code and a lot of RAM usage.
The question I can't answer yet is whether it is possible to fit it all into a GA144 alongside the synthesiser.
So far I've worked out that I need two set of samples, 1152 for the current frame and 1152 for the previous frame. This allows better prediction of band energies. As it happens 1152 is 18 * 64 which fits precisely into one row of the GA144.
So I have the synth taking 18 nodes (2 x 1/2 rows), and the samples taking 2 rows leaving 5 rows of nodes to encode the huge number of calculation constants and transforms. I need the SPI interface in node 705 to initially load the code from flash RAM and then to output the generated MP3 frames to the W5500. At this stage I don't need any additional RAM/ROM but I could throw the samples and the constants into external RAM if necessary.
I think the F18 nodes will be fast enough. This is only for audio, not video or radio.
I am attempting to port the LAME encoder, which is written in C, to ArrayForth.
Some subprojects I will need to implement on the GA144:
It seemed quite simple at first. Then I looked at how one encodes MP3 frames and I'm starting to baulk.
The idea is to read 1152 16-bit, 44.1KHz PCM samples, split the samples into 32 frequency bands, run an FFT over the samples to work out which bands are dominant and use a psycho-acoustic model to select how much of each band to put into the output frame. Add in a Huffman encoder and we are left with a lot of code and a lot of RAM usage.
The question I can't answer yet is whether it is possible to fit it all into a GA144 alongside the synthesiser.
So far I've worked out that I need two set of samples, 1152 for the current frame and 1152 for the previous frame. This allows better prediction of band energies. As it happens 1152 is 18 * 64 which fits precisely into one row of the GA144.
So I have the synth taking 18 nodes (2 x 1/2 rows), and the samples taking 2 rows leaving 5 rows of nodes to encode the huge number of calculation constants and transforms. I need the SPI interface in node 705 to initially load the code from flash RAM and then to output the generated MP3 frames to the W5500. At this stage I don't need any additional RAM/ROM but I could throw the samples and the constants into external RAM if necessary.
I think the F18 nodes will be fast enough. This is only for audio, not video or radio.
I am attempting to port the LAME encoder, which is written in C, to ArrayForth.
Some subprojects I will need to implement on the GA144:
- Move synth nodes to top of chip (609-617, 709-717) and verify it works.
- Load 1152 samples out of synth into RAM of 18 nodes. Easy enough to verify in Sim. Model transport from MD5 hash encoder example.
- Translate all the required constants in LAME code into floating point equivalents and load them into nodes (how many?). Easy enough to use Perl for the calcs.
- Implement fft_long and fft_short and test. Will need to also tool up LAME code for single step debugging so can verify results
- Implement window type selection based on FFT analysis.
- Implement mdct*. This might need cosine calc/lookup as used in (co)sine synth from previous project.
- Implement Huffman encoder. Needs a table of lookup vals.
- Create output frame from encode data plus side info.
- Output frame to W5500 and verify Internet transmission. A stand-alone test could be to output the same frame which presumably would play the same note(s) repeatedly. Each frame represents 38ms of sound so it would be very short.
Porting the MusicBox app to GA144
Introduction
The pre-cursor to the GreenArrays GA144 was the SeaForth S40C18. The SeaForth had 40 nodes whereas the GA144 has 144 but they have the same instruction set. Chuck Moore parted ways with Intellasys, the company which produced the SeaForth, a couple of years ago and the acrimonious lawsuit which resulted was settled last year.One of the demo apps which was included in the VentureForth compiler kit was a musicbox app. It uses a synthesised plucked string algorithm to generate random but quite pleasant 'plucked string' music.
I've always liked the app so I decided for my own education to port it to the GA144 using ArrayForth.
The first thing I discovered was how great the divergence there has been between VentureForth, the version of Forth used on the SeaForth chip and ArrayForth, as used on the GA144. In addition ArrayForth is a closed universe. It's almost impossible to import any program files into aF. They have to be hand-typed, whereas vF is ANSI text based and I could use standard text editors such as Vim to manipulate the program code. However the need to understand each instruction meant hand-typing was a relatively small hurdle. The bigger task was to understand what the instruction meant in vF and replace it with the equivalent aF instruction. While the instruction set is one-to-one compatible, the compiler directives in vF are completely different and in some cases there is no equivalent. This caused me a few headaches.
The other handicap I faced is my lack of knowledge of Forth. In the end this wasn't a big problem because the code for MusicBox is designed for Forth chips like the SeaForth and GA144 and doesn't rely on a lot of standard Forth familiarity.
Overview of code
The code uses the best feature of the GA144, namely the ability to offload work onto adjacent nodes while continuing with another task. The "central" node, called the composer, decides which note to play next. It then relays this choice to one of six "plucked string" synthesis nodes which generate code using the Karplus-Strong algorithm. The resulting streams of note-generation code are fed to a moving average filter node which feeds the result to a 'pre-dac' node which converts the PCM music code to PWM code which is in turn fed to a node which controls one of the digital-analog converters (dac). The output of the dac is fed to headphones or a speaker.Eighteen nodes are used. The composer node uses "random" input from an ADC to select the next note to play from a list of harmonically related notes. There are no "discordant" notes.
The output of composer is sent to a router node which keeps track of which nodes are busy synthesising notes and channels the next note to the next free node.
There are six "pluck" nodes. The KS algorithm uses a one-sample delay and so there are six "delay" nodes, one for each "pluck" node. Similarly the MA filter node requires a one-sample delay node.
The output of the MA filter node is passed to a "pre-dac" node which calculates the three parameters needed to drive the dac node. The calculations are time-expensive and are thus off-loaded to a separate node rather than attempting to run them in the 'dac' node.
Thus 1 composer, 1 router, 6 pluck, 1 filter, 7 delay, 1 predac, 1 dac = 18 nodes. Composer node has to be a node with analog input and obviously the dac node must have analog output. This constrains where in the GA144 the nodes can be. Thus I chose the following path:
717 (composer), 617 (router), 616, 615, 614, 613, 612, 611 (pluck), 610 (filter), 609 (predac), 709 (dac). Delay nodes are: 710, 711, 712, 713, 714, 715 and 716.
Composer
bc (bit count, by Michael Montvelishsky) The note to be played is chosen by counting bits in the number on top of the stack. That bitcount is used to index the table of frequencies at the beginning of the code, and that frequency is passed on to the router node, to be given to one of the voice nodes.note Use note number to lookup frequency then send it on to the router. 400 is a constant used to determine the length of a rest, and therefore the tempo. Decrease constant to play faster.
play The actual note to play is derived by counting the bits in the number on top of the stack. If the new note, determined by counting the bits in 'new' is the same as the old then play a rest i.e. be quiet. Otherwise give the< new note number to 'note'. The note played is also left on the top of the stack to be compared with the next note.
piece Read a random number from the adc counter at 'data', "and" it with 511 to keep it reasonable (dac has only 512 levels). Store number in A register to be used as an increment to find the next note in the "piece".
compose Play 127 notes, beginning with 0 and incrementing the "note" number by the amount stored in the A register by piece. The actual note is determined by counting the bits in the number fed to play.
1204 list
musicbox - plucked string synthesis713 node 0 orglookup table of frequency data27400 , 27400 , 24500 , 21800 ,19400 , 18300 , 16300 , 14500 ,13700 , 12200 , 10900 , 9700 ,9100 , 8100 , 7200 , 6800 ,6100 , 5400 ,bc 12 bitcount dup dup or - for
dup push zif drop pop - ;
then pop and next
note 17 a push a! . 18 @ !b pop a!
rest 400 ;
delay 1b dup for
dup for unext dup or -
next
1f drop ;
play 20 bc over over or if
drop dup push note drop pop ;
then rest drop drop ;
piece 28 random adc data a! @ 1ff and a! ;compose 2c a dup dup or notes 127 for
2f over play 30 push a . + pop
next drop drop ;start 33 e000 !b down b! rest
begin piece compose end 3aRouter
ring The address following ring is a variable that holds the next address to
be executed as a coroutine in the list that follows the variable. When
used in voice and force, the effect is to cycle through the
numbers in the "tables", returning the next number each time voice or
force is executed.
+note sends the note-on message on to the mixer chain, along with a
voice number and force number, telling the chain which node should
process this note and how loud it should be.
The main loop of the router first checks io register to see if the composer is
requesting attention. If so then a note is received from the composer
and passed on to the appropriate voice node. In either case a "play"
message is sent on to the next node in the mixer chain, to keep the
note samples going.
1216 list
router 613 node 0 orgring pop b! @b push ex pop !b ; voice ring5 ,r1 0 ex 1 ex 2 ex 3 ex 4 ex 5 ex r1 ;force ring14 ,f1 120 ex 100 ex 80 ex 70 ex 60 ex 50 ex f1 ;+note 4 voice @p ! ! ' a relay '
! @p ! . ' @p a! @p . '
' w lit ! ! @p ! @p a!
! force ! ;start 2c up a! io down
begin
over b! @b 2* 2* 2* 2* -if
33 over a push a! @ pop a! +note
then @p ! dup . ' @p play '
or !
end 3a
Pluck
Pluck uses the Karplus-Strong algorithm, http://en.wikipedia.org/wiki/Karplus-Strong_string_synthesis
A better explanation is at music.columbia.edu - Start with a buffer full of random numbers which is equivalent to an energetic string pluck, read through the buffer using the values as sample values, average each value with the previous value and write it back to the buffer as well as forwarding the sample to the dac player. Over time the averaging is equivalent to a low-pass filter and will remove the higher frequencies until eventually the waveform will be flat i.e. the string has stopped vibrating.
1214 list
pluck - karplus-strong string synthesis0 orgpluck dup push . + 2/ pop a -if
drop 2/ 2/ ;
then push zif
swp 05 over push push drop pop pop ;
then pop a! drop drop @p drop @p
!rnd dup !p ; 3ffff , rnd 0b -if
2* 2cd81 or @p
then 2* dup .. drop !rnd 1ff and dup ;
rwrw 12 @p !b @b . ' !+ @ !b .. ' 1ff and ex
@p !b !b . ' @p .. ' ex
@p !b @b .. ' @ !b .. '
2/ 2/ 2/ 2/ 2/ 2/ 2/ 2/ 2/ 1ff and ex
8 for 2* unext
@p .. ' @p . + . ' !b !b ex rwrw ;play 26 @p drop !p
mix 27 dup @p + ;0 ,pop drop push -if
1ffff and over b! pop ex pluck ex pushthen push over b! pop @p . +w 33 1ffff ,pop mix @p !b !b mxplay 36 ' @p play ' 37
A full listing is on GitHub: https://github.com/garyaj/musicbox
Subscribe to:
Posts (Atom)





