After struggling immensely with the logic part of this project I have somewhat workable code. It was certainly a huge learning experience for me, as I had only ever dabbled with logic programming one other time while playing with a 6502 processor -- but I digress.
Once I started working in Verilog I quickly learned that without creating a test bench for each module I was implementing it would be pretty much impossible to move forward. Test benches turned out to be frustrating because they don't 100% mimic what actual hardware does, so you have to be careful. I ended up making a SPI slave module, clock module, ram module to store the received SID frame and a "SID glue" module to take the received SID registers and write them to the SID. The folks over at edaboard.com were very helpful during this process! I'm a complete hack with Verilog/logic stuff, their patience and input was instrumental.
One frame of register updates for the SID is 200 bits (25 registers x 8bits), and since you need to avoid writing duplicate register information across each update you also need to store the last frame of registers. Because storing 400bits (200 * 2) in CPLD is not possible (AFAIK), I had to move over to an FPGA, which has much more room. Since I am a dev board hoarder I have a Mojo v3, XuLa 2, and a couple of other FPGA dev boards hanging around -- I decided the Mojo would be easiest to slide in place of the CPLD, mostly because I've used it before and learned a lot from the tutorials they offer (http://https://embeddedmicro.com/tutorials/mojo).
At this point I'm not sure if I want to keep the FPGA in the project, because in the future I can implement a 6502 on it and do the SID processing there ... or go back to a CPLD and use SRAM for storage (which would likely be a lot cheaper, but less fun and flexible for experimentation).
Here's a quick video that I made of the thing in action for the first time:
Switching over to the CPLD for glue between the SID and ESP has worked out really well. It's been a lot of fun learning more about logic, somewhat frustrating but mostly fun :)
I figure I shdould now recap how the project will work:
1. Python 6502 implementation runs the SID program and extracts the SID register values for each "frame" of the song, stores them in a FIFO. This code is pretty much complete (thanks greatly to the RealSID project by A.T. Brask http://https://github.com/atbrask/RealSIDShield) 2. ESP receives ~100 frames (2seconds @ 50Hz) of music saves them into another FIFO, a ticker timer is set up for 50Hz which sends the frame data (registers) to the CPLD. I've got some work to do on the TCP code here and sending over to the CPLD but it should be pretty simple. 3. The CPLD clocks the SID, and works as an I/O expander putting the necessary address and data on the SID bus. I need to finalize the SPI slave and then write the glue for the SID (to assert addr and data when the shift register is full). 4. SID plays music (hopefully) 5. LM386 amplifies it 6. ??? profit ???
I've implemented a simple clock divider and a 200 bit shift register that is fed all 25 SID registers for each update from the ESP. Since the ESP SPI is done in hardware it works up to 80MHz! This is waaaaay better than the measly KHz that I I2C was giving me before with the MCP chip.
I wrote a testbench for my shift register to make sure everything is working correctly. Here it is shifting in alternating 0x00 then 0xFF for 25 bytes: [attachment=2] As you can see the MOSI line is just set to invert every byte so I can make sure things are working properly. In the terminal of my test bench I've also set up some debug output so I can follow the register filling up with bits: [attachment=1] I've chosen to do it this way so I can just shift in all 25 one-byte registers at once into one big buffer, then pass them over to another module that will handle writing the value to the bus for the SID. Right now the timing will be handled by the ESP, and that will be fine for 50 and 60 Hz songs but eventually I will build a buffer in the CPLD and have it handle all the timing because it will be much more reliable.
Finally on the ESP8266 side, here is a screenshot from my logic analyzer of the ESP sending out 25 bytes of data on the SPI bus (slowed down to a measly 4Mhz as to not overwhelm the poor Saleae): [attachment=0]
It's all coming together! Soon I will hear bleeps and bloops!
And yes, for those interested, the next step is designing a PCB and slapping this all onto one nice PCB that you can just plug in to your stereo and stream to from anywhere.
Ok, so I struggled a bit with what to add to the constraints file for the oscillator input. It seems to be working but I wanted to double check that I've done this correctly, I added the following
But I also saw these lines in a few other places, I Googled a bit but I can't quite seem to figure them out, I left them out for now and things still seem to be working:
Ok, it's official, I'm dumping the MCP I/O expander in favor of a waaay cooler part: a Xilinx XC9572XL CPLD.
In the first iteration of the project (in my head anyway) I was going to use the CPLD for bus decoding. So I had a couple DP XC9572XL boards sitting around the house. I ordered a couple 20MHz and 50MHz oscillators and slapped them on and voila, I has a clock ;)
Now for the next trick, to make the thing speak SPI so I can send it data from the ESP. This has the benefit of speeding up transfers too since the ESP SPI bus runs at 1Mhz. Woot. This will be the hard part for me as I'm pretty stupid with this logic stuff. Wish me luck.
I don't think anyone has ever been so excited about a clock. [attachment=0]
It's been almost three years since I posted this, but I finally got an oscillator on to my CPLD board. It had been sitting in the closet for a while unused, but I finally have a use for it (for my SID project http://http://dangerousprototypes.com/forum/viewtopic.php?f=56&t=7849).
It's pretty ugly, I used my hot air rework to put it on.. Hint: solder the pins in after you put the oscillator on not before ;) Either way it's on there -- thanks for the help @hlipka
[attachment=2]
Does this look good? I'm kinda new working with this stuff...
[attachment=1]
Wow, it's funny what a difference hooking it up directly to the PCB can make versus using cheap jumper wires (this is on a breadboard too)... This looks a bit better, eh?
[quote author="Markus Gritsch"] No, but the numbers can vary quite a bit. If you have a look at "Fanta in Space" using ACID 64 again, you will see that it has an update rate of 15639 Hz. Further, ACID 64 does not simply send the register values and that's it. To be cycle exact, it also adds the clock count (i.e. timestamp) when a specific value should be written to a specific register. This also adds some overhead.
Since data transfer rate can vary, you should buffer the data coming from ACID 64 and write the SID registers according to the included timestamps at the precise moment. Maybe you should have a look at the ACID 64 network protocol. [/quote]
Ahhh. I thought it was something like that! Haha, I'm hoping most older songs don't use techniques like that, so I can get my little project going first with 50-60Hz songs.
I've looked a bit into the ACID64 protocol, but first I'm going to implement my own dumb protocol that just sends frames so I can hear some music (I'm impatient). I already have a ring buffer on the ESP8266 side, as I anticipated the need to buffer frames.
Now I'm leaning toward throwing out the MCP I/O expander and replacing it with CPLD for I/O and clock generation... I can't make any noise until I figure this damn clock thing out :)
[quote author="Markus Gritsch"] Bit-banging the I/O lines to get a 1 MHz clock is definitely not the way to go. Even if you could achieve 1 MHZ (which you can't) there would be no time to do anything else.
In my SID player project over here viewtopic.php?f=56&t=2197 I used a counter of the PIC32 together with output compare which toggles a pin at 985248 Hz (PAL) or 1022727 HZ (NTSC). I don't know if the ESP8266 has such a pheripheral.
Another thing to investigate is the maximum sustained data rate you can stream to the ESP8266 over WiFi. Some digi-tunes like 'Fanta in Space' or 'Pollycracker' require 100+ kByte/s sustained data rate. [/quote]
Thanks Markus!
I will have to look into the data transfer thing. About that though...please bear with me. For most tunes the SID gets updated at 50Hz, there are 25 registers, each of which are 8 bits, so that means there is 25 bytes per register update. The math per sec is 25B * 50 = 1250B, so by my (probably flawed) math it should be a max of ~1.2kB/sec... or at 60Hz ~1.5kB. Am I doing something very wrong to arrive at these numbers?
I looked and the Fanta in Space file is 51kB, while the Pollycracker file is 48kB. I am guessing all of this is because of sampling in these files, and I have no clue how that works, and am a little foggy on all the different filetypes introduced since I was 13 years old and actually using the C64 :)
Wow, cool! Looks like I made the front page. Hopefully this will help me out in this one question:
The SID needs a 1MHz clock and I thought that since the ESP is clocked at 80MHz that this would be easy. I can't get the GPIO to toggle that fast though, it seems to be limited to a couple hundred KHz when using the Arduino IDE.
I guess my options are 1) figure out how to get faster GPIO, or 2) use an external clock. I really don't want to introduce an extra component to the mix. Anyone have thoughts on this?
I've been trying to start a SID project for about 5 years now. Back then I wanted to use a 6502 along with a CPLD and other 'real' hardware... while I might still do something like that (or even try to use an FPGA for everything except the SID), I think it's probably good that I waited so long because now this great cheap ESP8266 wireless SoC is around.
When I saw the http://https://github.com/atbrask/RealSIDShield project I thought that the whole idea of using py65 to emulate the 6502 was pretty neat, and very accessible for me since I'm a Python guy. Then I stumbled across Acid64, which also emulates the 6502 in software and has a couple of other neat features. So, the plan is to support both. I'm not sure which one I'll implement first, but it should be relatively easy to get both working... and since Acid64 is Windows only, when I'm on Mac or Linux I can use a python script to stream music.
Anyway, so this is my plan for the hardware:
- Adafruit ESP8266 Huzzah module (eventually when I make a PCB I'll just use an ESP8266) - MCP23017 I2C I/O expander (for 16 GPIO) - SID (duh) - LM386 preamp
I've started to breadboard everything: [attachment=0]
If anyone wants to provide feedback, please don't hesitate! In particular, I'm curious about design surrounding the LM386 preamp, should the preamp be on a different board? I'm concerned that there might be noise issues. Also I'm using a 12v supply, and an LM7805 LDO in order to give the SID the required 12 and 5 volts. Is this a bad idea?
Eventually I will definitely get some boards made, I might include a 2nd SID for the option of stereo as well. I have no clue what that involves at the present time but it seems like it shouldn't be too hard.
Since the ESP is clocked at 80Mhz I think that it will be more than fast enough to handle the task. But if anyone thinks otherwise please let me know.
Ok going to play with Python now to see if I can figure out a little more about the py65 emulation method and Acid64 network protocols. Wish me luck.
Looks like I missed something in the protocol. So from what I understand if localhost:6502 is open, Acid64 will send out some sort of discovery packet which you reply to and then it knows there is a SID chip there to send the data to?
I'll have to look at your Python app more closely as I've been looking at all kinds of projects to try to figure that part out and I guess I missed it in every one. D'oh!
And yeah, I also emailed Wilfred and he was incredibly helpful with a very long email back to me (but I still didn't get this one part figured out, hehe). I think that having the IP:PORT as a configuration option would be really nice in order to avoid running a local proxy.
I will certainly post again. Right now the plan is ESP8266 + mcp23017 i2c i/o expander (16 gpio) + SID + LM386 preamp. I want to build the firmware work with both Acid64 and also the route that one other project I saw took, which was to use py65 to emulate the 6502 and then send register information over (just for the learning/fun of it)...
I'll start a thread when I get a bit further because I don't want to hijack this one! Thanks for the help.
I'm a little confused about getting Acid64 to play to the network. I see that you've written some sort of driver for that -- but there appears to be very little documentation on this (unless I missed something obvious).
I'm building an ESP8266 based player, which is connected to the network wirelessly, I want to implement the server directly on the ESP's micro but I can't figure out how to tell Acid to simply use 192.168.x.x:6581 as an output device. Can you please point me in the correct direction?
I am pretty sure that the board takes a 3.3v oscillator, so I am not sure if those would work. Also I think the ideal speed is 50Mhz or 20Mhz for those chips.
Anyone have experience putting a clock on one of these boards?
I am in need of a clock source for a project I am working on with this board. It seems that it's going to be a major pain in the butt to solder on the SMD part -- is it very difficult? Do I need to make a solder mask? Or will I be able to use a normal iron with a fine tip?
Also, can someone recommend an appropriate part from Digikey? I was looking at a few but don't want to pick the wrong one.
If there is one that is breadboard compatible that would let me avoid soldering things that would be nice too!
I am in awe. This is amazing and inspirational! Good work.
I just got 3 C64s with intact SID chips. I have yet to test them, but I have high hopes they will work. I'd love to make one of these and will probably be back with some questions!
Now off to Seeedstudio to buy one of those CUI32Stems :)
Thanks! So, I guess that communicating with an LCD and a shift register is essentially the same then? I did Google and found a few tutorials on 3-wire communication with LCDs but thought it might be different with these character displays because they are driven by shift registers.
Also, many of the tutorials use the terms 3-wire and SPI somewhat interchangeably -- this is a bit confusing for me. Are they really the same thing?