After a bit of a break I am back and need some help. Pasi and Panu helped me out the last time.

I am using a Beagle Bone black to talk to a LC Soft / VS1053b board. The midi works well, and I have reset it into MP3 mode and have managed to get sounds out of the board. The problem is when I play a MP3 file it plays very fast. It is as if someone was pressing fast forward.

Here is some information. From ffprobe there is some file information on the MP3:

I checked that I am waiting on DREQ. I have it as a GPIO-Keys that flag an event, and have a linux pthread event thread that acts as an Interrupt service routine. Just for the sake of completeness I also check the common parameters to make sure playspeed is not set to super fast.

The regular suspects:
- Something wrong in DREQ handling: check for DREQ=1, then send 32 bytes of data.
- Don't change the chip select signals while the SPI is transmitting, otherwise bytes go missing. (See that SPI is idle before changing the chip select signels.)
- Other chip select issues, extra bytes are inserted to SDI.
- You are reading blocks as words but sending them as bytes, sending only half of the data
- Filesystem issues, not sending all blocks.
- The parametric_x.playSpeed variable has been set somehow.

Thanks for your kind tips. I did check DREQ, and the code I think is working OK. on that point. SPI wise I think I am OK. The way the Chip selects are handled is there are two devices in /dev. In the BeagleBone black I have set my device tree to Share an SPI, but with two Chip selects. This allows the AM338 TI Sitara ARM chip to handle the chip selects for me. So unless I have another thread grabbing the other device in /dev I think overlapping Chip selects is not the issue.

You are right in that it could be the word / byte / endianess file format. I know there are lots of ways a MP3 can be encoded, but the file I have is "sample_fmt": "s16p",. So this is signed 16 bit planar.

Does the VS1053 expect a MP3 planar format, as opposed to non-planar MP3?
When I send a s16, signed 16 bit sample, does that mean it needs to be byte swapped?

For my SCI writes, I byteswap the 16bit data. I.E. I assume the VS1053 is Big endian. I need to send the most significant Byte first in a 16 bit word. This works well and I get the correct responses and can dump out the registers in the VS1053.

In sending SDI (data), I simply read the file and send that at the VS1053. That is in AMD / Intel / x86-64 format. Do I need to byte swap every 16 bit word?

What confuses me a bit is if I send a wave file with a RIFF header. That file is signed 16 bit. I understand that by swaping bytes the 16 bit samples will come out right. But what will happen to the header? Won't R I F F then become I R F F? I guess looking at page 52, of the VS1053 ddata sheet (Version 1.22, 2014-12-19 ) It needs to see R I F F, and the header is in little Endian. i.e. for Bits per sample = 16, we send 0x10 then 0x00. I.E. we send the least significant Byte first.

Sorry for the rambling message. Just a bit confused as to why ....

So to end here are some simple questions.

1) VS1053. What does it expect the Mp3 format to be in endian wise. Little Endian like Intel AMD x86 boxes, or Big Endian like Power PC chips?
2) Do you have a known good MP3 file I can download and use to test, or a link to one?
3) If I am using FFMPEG on Linux on an Intel box, do you have a command line that will produce a MP3 file I can play on the VS1053. I.E. what are the command option settings I should set.

All the data in the SDI should be considered sent as bytes (although they are internally collected into words). The first byte in the file should be sent first, MSb first, then the rest of the bytes in the file in sequential order.

If you hear anything from the mp3 file, you have things basically correct.

You were right on day one. The root cause of the issue was not respecting DREQ.

Just for laughs and a lesson of why people write real kernel device drivers rather than try and kludge things like me. I am on a Beagle Bone Black running Linux. ARM-hf, Robert C Nelson kernels.

The first problem was to try and capture DREQ I was using GPIO-keys. An interrupt driven driver for key presses. I though that this could keep up. However it does not and I ended up missing DREQ events. Some DREQ events did work, some did not. Hence the confusion, I was thinking hey I see DREQ's so that means it works. What we really should have said is we see "some" but not *ALL* the DREQ's. The GPIO-Keys implementation I think has some interrupts in there, but I am not sure if it is fully tuned for the TI SItara AM3358 and makes use of all the hardware registers, so could be sub optimal. I think it can capture interrupts well, however there is a cycle time before it is ready for another interrupt. That cycle time using GPIO-Keys was just too long. I read somewhere that the cycle time could be approx 100 milli seconds or so. Which matches with what I observed.

The next issue was also more subtle. If one looks at the Arduino examples, it says send the data, then check DREQ before you send some more data. I tried to do this and it failed. The reason is I was using a linux Write. A Write is simply a hand off of the data buffer to a kernel thread, and eventually some time down the road linux will get round to it. I was checking DREQ immediately, *before* the data had really left the Microprocessor core. Hence the return value on my DREQ check is High, ready for more data, But in fact there is a chunk of data "in transit" that has not hit the VS1053 yet.

So a very kludge hack, which probably will fail or cause glitches etc is:

1 Write a better DREQ pin check. I now use a /dev/mem mmap call to check the pin status. The pin is sampled with a 2 clock cycle delay in hardware. So that is 2 nano seconds on a Beagle Bone Black. Note you have to be Root or set SUID for this to work.

2 A dirty hack of an algo is then:

i) Send 32 byes of data using a buffered, multiple threaded, high latency Linux Write. So not the best way to go because we do not know when it is done.
ii) Wait about 2 milli seconds. (My SPI is 8Mhz, so this takes 32 micro seconds, and on top of that we add a Fudge/Saftely time). We have do do this to improve the chances that the 32 bytes we just sent has really arrived at the VS1053, So that the VS1053 can tell us if it is full of data or not by setting DREQ
iii) CHeck the DREQ pin via /dev/mmap. Wait untill it is high. Sort of test-sleep-wait. Then go back to i

Not the best solution, and bound to fail as the timings will change as the Linux kernel becomes under load. At least the tunes sound better though.