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.


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:
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 wiz550io
705 node 0 org
start 00 left a! io b!
2 20 1000 dup -++ half
nxt @ 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 
drive spi 705 iface
706 node 0 org
lsh for 2* unext ;
cmd push 9 lsh pop 1 lsh
06 @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
   
warm
end 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
spi boot top/bot
4 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
c1


1014 list 
install via async bootstream
empty compile
streamer load framer load
async frame ae fram ;
wizspi align create
708 705 to
-1 ,

wizspi course
2 fh load frame stream

serial load -canon
a-com sport ! a-bps bps ! !nam
talk send
2 706 hook panel


1016 list 
705 +node 705 /ram 0 /p
706 +node 706 /ram 14 /p
2 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.

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.

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.


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:

  1. Move synth nodes to top of chip (609-617, 709-717) and verify it works.
  2. Load 1152 samples out of synth into RAM of 18 nodes. Easy enough to verify in Sim. Model transport from MD5 hash encoder example.
  3. 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.
  4. Implement fft_long and fft_short and test. Will need to also tool up LAME code for single step debugging so can verify results
  5. Implement window type selection based on FFT analysis.
  6. Implement mdct*. This might need cosine calc/lookup as used in (co)sine synth from previous project.
  7. Implement Huffman encoder. Needs a table of lookup vals.
  8. Create output frame from encode data plus side info.
  9. 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.