(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
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
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/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
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
705
+node
705
/ram
0
/p
706
+node
706
/ram
14
/p
2 0 705
hook
No comments:
Post a Comment