The Netduino forums have been replaced by new forums at community.wildernesslabs.co.
This site has been preserved for archival purposes only
and the ability to make new accounts or posts has been turned off.
My idea is pretty much the same than this topics but I don't use sd card for now. Anyway, it doesn't really help me, hanzibal describe his project but didn't say "how" he did it, and the only code spinnet I found are for an other component...
the second one is a c# implementation of the third resources. So i tried to use it but I don't succeed to read any data from the board...
This is my code :
using System;using System.IO;using Microsoft.SPOT.Hardware;using SecretLabs.NETMF.Hardware.Netduino;using System.Threading;using System.Diagnostics;using Microsoft.SPOT;namespace NetduinoApplication2{ public class VS1053 { // GPIO ports: private OutputPort _reset; private InterruptPort _dreq; private Cpu.Pin PinBsync = Pins.GPIO_PIN_D2; private Cpu.Pin PinDreq = Pins.GPIO_PIN_D3; private Cpu.Pin PinReset = Pins.GPIO_PIN_D6; // NOTE: This doesn't map to an actual pin private Cpu.Pin PinCs = Pins.GPIO_PIN_D9; // Define SPI Configuration for VS1053 MP3 decoder: private SPI.Configuration DataConfig; private SPI.Configuration CmdConfig; private SPI _spi; // Registers: private byte RegisterSciMode = 0x00; private byte RegisterSciVol = 0x0B; private byte RegisterSciClockf = 0x03; public static readonly int BufferSize = 96; private ushort SciMode = 0x880; // SM_SDINEW (default) + SM_EARSPEAKER_HI private bool _isInitialized; private readonly byte[] ReadBuffer = new byte[BufferSize]; private readonly byte[] CmdBuffer = new byte[4]; private readonly AutoResetEvent AutoResetEvent = new AutoResetEvent(false); public void Initialize() { DataConfig = new SPI.Configuration(PinBsync, false, 0, 0, false, true, 3000, SPI.SPI_module.SPI1); CmdConfig = new SPI.Configuration(PinCs, false, 0, 0, false, true, 3000, SPI.SPI_module.SPI1); Debug.Print("--- _isInitialized : " + _isInitialized.ToString()); if (_isInitialized) { Debug.Print("Shutdown !"); Shutdown(); } _spi = new SPI(CmdConfig); _reset = new OutputPort(PinReset, true); _dreq = new InterruptPort(PinDreq, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth); _dreq.OnInterrupt += _dreq_OnInterrupt; _isInitialized = true; Reset(); var test = SciMode | (1 << 2); var test2 = (ushort)test; Debug.Print("--- set : " + test2.ToString("x") + " : " + test2.GetType()); CommandWrite(RegisterSciMode, test2); var result = CommandRead(RegisterSciMode); Debug.Print("--- read :"); foreach (byte b in result) { Debug.Print(b.ToString("x")); } //CommandWrite(RegisterSciClockf, 7 << 13); //CommandWrite(RegisterSciVol, 0x2424); //_spi.Config = DataConfig; } private void _dreq_OnInterrupt(uint port, uint state, DateTime time) { if (state == 0) { AutoResetEvent.Set(); } else { AutoResetEvent.WaitOne(); } _dreq.ClearInterrupt(); } private void Reset() { Debug.Print("--- Start reset ---"); _reset.Write(false); Thread.Sleep(1); _reset.Write(true); Thread.Sleep(1); Debug.Print("--- Finish reset ---"); } private void CommandWrite(byte address, ushort data) { CmdBuffer[0] = 0x02; CmdBuffer[1] = address; CmdBuffer[2] = (byte)(data >> 8); CmdBuffer[3] = (byte)data; _spi.Write(CmdBuffer); } private byte[] CommandRead(byte address) { var buffer = new byte[4]; CmdBuffer[0] = 0x03; CmdBuffer[1] = address; CmdBuffer[2] = 0; CmdBuffer[3] = 0; _spi.WriteRead(CmdBuffer, buffer, 0); //ushort command = CmdBuffer[0]; //command <<= 8; //command += CmdBuffer[1]; return buffer; } public void SetVolumePercent(int volume) { if (volume < 0 || volume > 100) throw new ArgumentOutOfRangeException("volume"); SetVolumePercent(volume, volume); } public void SetVolumePercent(int leftChannel, int rightChannel) { if (leftChannel < 0 || leftChannel > 100) throw new ArgumentOutOfRangeException("leftChannel"); if (rightChannel < 0 || rightChannel > 100) throw new ArgumentOutOfRangeException("rightChannel"); // TODO: Invert decibel value, divide by percent, call SetVolume(ushort leftChannel, ushort rightChannel) } public void SetVolume(ushort bothChannels) { CommandWrite(RegisterSciVol, bothChannels); // TODO: This doesn't work outside the Initialize() method } public void SetVolume(ushort leftChannel, ushort rightChannel) { SetVolume((ushort) (leftChannel*256 + rightChannel)); // TODO: Verify no loss of fidelity } public void SendData(FileStream fileStream) { var size = fileStream.Length - fileStream.Length % BufferSize; for (var i = 0; i < size; i += BufferSize) { fileStream.Read(ReadBuffer, 0, BufferSize); _spi.Write(ReadBuffer); } } private void Shutdown() { if (!_isInitialized) return; Reset(); _spi.Dispose(); _reset.Dispose(); _dreq.Dispose(); _isInitialized = false; } }}
using System;using System.Net;using System.Net.Sockets;using System.Threading;using Microsoft.SPOT;using Microsoft.SPOT.Hardware;using SecretLabs.NETMF.Hardware;using SecretLabs.NETMF.Hardware.Netduino;namespace NetduinoApplication2{ public class Program { public static void Main() { VS1053 vs = new VS1053(); vs.Initialize(); //vs.SetVolume(0xFEFE); } }}
And this is this output I got :
--- _isInitialized : False--- Start reset ------ Finish reset ------ set : 884 : System.UInt16--- read :00000000The thread '<No Name>' (0x1) has exited with code 0 (0x0).Done.
I think I'm supposed to receive the exact same byte array that I send with CommandWrite, but I just receive 0...
I haven't taken the time to look through your code but in the post below, you'll find code that is known to work perfectly well with Netduino mini and should work equally well with a NP2 after a few modifications.
The code is stripped from stuff that are specific to my application and the remaining code is very simplistic which makes it fairly easy to follow and use as kind of a ground to work from. For example, you'd have to add your existing code for fancy things like changing volume, etc. The code simply plays all songs from and SD card, one song after the other.
Also, there might be some reading of interest from that post on-wards.
I remember initially having quite some trouble with getting the chip to play. My problems turned out to be SPI related and at some point, I got a faulty GPIO pin connected to DREQ which was really hard to track down.
I've made many more posts on the vs1053b department of the VLSI forum. Please do search for my posts over there and I'm pretty sure you will find something useful:
Ok so the error that I got come from a bad SPI configuration in my code. But I have an other problem now.
I can play a file on my sd card but the play rate is really too low, it's like a "slow-motion" but for a song (RATE = 8000 Hz display in the visual output)
How can I speed it up ? (I'm sorry I don't understand perfectly your playstream function hanzibal ^^")
I send order to my netduino card over network by my windows phone with an app I made. This app send to the netduino the song's name to play, On the netduino there is a socket server witch process the phone request and then send byte data to the vs1053.
With hanzibal's code, on the first song, i get this output :
RATE=8000 Hz (mono)
The music speed is really slow. And when I send a second order with another song :
RATE=44100 Hz (stereo)
But nothing is play...
I think i should have RATE=44100 Hz (stereo) at the first song to ear a clean sound, isn't it ?
Sample rate and stereo/mono mode are properties of the song you are playing and so they depend on how each song was recorded. I added this info just for fun and it should not effect how well or poor a song is played.
By the sound of it, you are suffering from poor transfer rate between the SD card (songs are on an SD card right?) and the vs1053b. If you look into my code, you can see that I crank up SPI speed as part of initialization. Have you incorporated that part into your code?
Also I remember someone else had similar problems not all that long ago where I tried to help. Use google to search the forum for "vs1053b", the forum search does not work very well (or maybe it does now).
Also, you cannot have Debug.Print in performance critical parts of your code, it will slow you down a great deal. I assume you don't use interrupts for DREQ since it too will add significant overhead. You must poll DREQ in a tight loop and then feed the chip fresh chunks of 32 bytes each as quickly as you can until DREQ changes again to indicate the buffer is now full and cannot accept any more data until the chip has consumed what you just fed it.
Now, I did this with a mini which is considerably slower that an NP2 but I recall there were some problems mentioned in the thread I mentioned above.
So, basically you're running the same s/w as me, then it ought to work especially on a faster uC. Well, at least one would think so but...
Here's the thread I was thinking about in my last post:
http://forums.netdui...ge-3#entry44437
It took me a while before I realized it's my own old thread but I believe it might be very relevant indeed from the post referred to and onwards, so read it carefully.