VS1000 overall latency

Writing software that controls the system and peripherals such as displays, SD cards, Buttons, LEDs, Serial Ports etc.
Post Reply
blowtorch
User
Posts: 4
Joined: Sat 2019-06-29 13:01

VS1000 overall latency

Post by blowtorch »

Hi
We need to add audio to an existing product, and are considering the VS1000 for this. We do not need huge storage, or amazing high fidelity.
What we do need is good response time (low latency) to a "trigger" to play a sound, also to stop and restart a sound that may be playing.

So, I have bought several of the Sparkfun "little soundie" with the VS1000D to experiment with. I have Vside loaded, and downloaded various sample programs and datasheets. Quite a big learning curve to get started! And many variables, depending on using OGG or WAV, many other considerations.

Before expending more effort, I though to ask the experts here some questions:
1. From power off, how long does it take to initialise, and start playing a sound?
2. From power on but idle, how long to play a new sound?
3. How long to stop an existing file being played, and either restart it or start new one?

I see that the Sparkfun board has the identical software to the example software provided by VLSI, but they are using "GPIO_MASK" and not "GPIO_PRIORITIES", so it is impossible for me to test the timing without compiling new firmware and sending to the VS1000D.

That is next step!

Finally, is the VS1000D the way to go? Cost is a concern, we would like to lowest cost BOM going forward. As mentioned, adding audio will enhance our product, but it is not the main feature so we have to be careful with cost. So, a more detailed spec in terms of choosing the right chip:
1. Must be easy to add or replace new sounds (even for customer to do it in the field).
2. Fast to respond to instruction to play sound, or stop playing sound, or start new sound
3. Will not be needing much storage and many files (the 4mbit flash on the SParkfun board is sufficient)
3. Not sure of quantities at this stage!
User avatar
pasi
VLSI Staff
Posts: 2120
Joined: Thu 2010-07-15 16:04

Re: VS1000 overall latency

Post by pasi »

Even with GPIO_MASK, when you change the GPIO pins to have a different value, the current song is cancelled and the new one started.

However, normally the GPIO pins are scanned only 16 times per second, the normal "keyscan" rate, which adds up to 125ms 62.5ms delay. (With GPIO_NODRIVE defined the GPIO's are read whenever there is free time from the decoding.)

1. Around 160-200ms from power-up. It takes a while for the oscillator to start and the firmware to load (the latter could be made faster with some tricks).
  • Starting play of WAV from SPI FLASH can be considered instantaneous.
  • Ogg Vorbis needs to create decoding tables and to decode two audio frames before you get samples out, which takes longer. (If you use the same samplerate and quality for all files, you can cheat and skip creating the decoding tables if they are already in memory, but that is advanced usage.)
2&3. Stopping play is quick for WAV (assuming GPIO are scanned continuously), but it takes a little longer for Ogg Vorbis, because it may not detect the cancel request while in audio frame decoding. For the minimum delay you would also need to empty the audio FIFO before starting the decoding of the next file.

VS1000 Audio Module can update content (and firmware) using a uSD card. If SDUPDATE.PRG is found on the card, it is loaded and run, and can then reprogram the SPI FLASH on the module. (You can't replace just some of the sounds though, you need to rewrite the whole content area.)

VS1010 is also a contender.
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook
blowtorch
User
Posts: 4
Joined: Sat 2019-06-29 13:01

Re: VS1000 overall latency

Post by blowtorch »

Thank you Pasi.

I have been figuring out your chip this weekend and made some progress in setting it up the way I want it. I actually bought 5 of the breakout boards, and all 5 are now programmed in slightly different manner.

On the original Sparkfun implementation, the current song is not cancelled. Their code via Github using GPIO_MASK:

Code: Select all

if (mask)
      {
        player.currentFile = player.nextFile = mask - 1;
        player.pauseOn = 0;
      }
On the one board I have inserted

Code: Select all

cs.cancel = 1;
which seems to have done the trick.

Thanks for advice regarding WAV versus OGG. We want to create slightly different products using your chip, each one will need slightly different program. So for example,
Product 1: Always play same sound, must be very fast, lowest latency from command to play and actual sound. New trigger must stop and restart the associated sound. A variation on this could be say 16 different sounds, all WAV, all of short duration. Fast restart critical requirement.
Product 2: Play different sounds, depending on activity. MCU can use GPIO_MASK to select different sounds. New activation will be ignored unless current sound is finished. Timing not critcal
Product 3: Play different sounds, depending on activity. MCU can use GPIO_MASK to select different sounds. New activation will stop playback and start new sound. Timing not critical

So with the information you have provided, we must stick with WAV format for the quick response for product 1. Which leads me to more questions on this, will 8 bit encoding have faster load time than 16bit? The 16 bit wav file will be bigger.

Where can I find more information on items such as GPIO_NODRIVE , and other information to help with programming? For example, you say that the GPIO pins are scanned normally at 16Hz. But you also say that we have up to 125ms delay. 16Hz has period of 62.5ms, so what else is happening to add up to 125ms? Are other activities running that could maybe be optimised? Also, if I use GPIO_NODRIVE, is there any benchmark for knowing the frequency of keyscan?

Sorry for all these questions, but I am unsure how to find all the information for myself or how to rig up a scope to measure things for myself. Some of the information is critical to have. For example, if I am driving the IO pins with a MCU to trigger a sound, or to restart a sound, I need to drive them and hold them for enough time that the VS1000D will read the pins and action the command, but I must not hold them for too long otherwise it will see it as second activation.

Also for the GPIO_MASK where a file number to be played is provided by binary activation of GPIO, there is no "latch" pin, so in theory the VS1000D can read wrong file number if it reads just as my MCU is setting more than 1 pin? Am I overthinking this?

I assume GPIO are read (keyscan) via "GPIOCtrlIdleHook"?

When I compile, I get warning saying the following code has no effect:

Code: Select all

for (mask = 0; mask < 10000; mask++)
                USEX(0);
What command is USEX?

Where do I define GPIO_NODRIVE and find more information on this? What is frequency of reading IO pins likely to be if using this option?
I am driving the GPIO pins using a MCU, so do not need debounce, is there a way of switching this off?
User avatar
pasi
VLSI Staff
Posts: 2120
Joined: Thu 2010-07-15 16:04

Re: VS1000 overall latency

Post by pasi »

blowtorch wrote: Mon 2019-07-01 12:32So with the information you have provided, we must stick with WAV format for the quick response for product 1. Which leads me to more questions on this, will 8 bit encoding have faster load time than 16bit? The 16 bit wav file will be bigger.
There is no difference between 8-bit and 16-bit wav when latency is concerned. And practically no difference in other ways either.
blowtorch wrote: Mon 2019-07-01 12:32Where can I find more information on items such as GPIO_NODRIVE , and other information to help with programming?
A lot of the "top-level" defines are documented in the vs1000 audio module pdf. With more low-level stuff you have to go with what little there is in the comments for each #define, and the code itself, and what you can get out of me.
blowtorch wrote: Mon 2019-07-01 12:32For example, you say that the GPIO pins are scanned normally at 16Hz. But you also say that we have up to 125ms delay. 16Hz has period of 62.5ms, so what else is happening to add up to 125ms?
Ah, a brainfart on my part. The max latency is 1x 62.5ms and not 2x.
blowtorch wrote: Mon 2019-07-01 12:32Also, if I use GPIO_NODRIVE, is there any benchmark for knowing the frequency of keyscan?
With WAV I expect it to be very fast, because WAV decoding takes no time at all, and it is handled in 16-sample packets.
blowtorch wrote: Mon 2019-07-01 12:32Also for the GPIO_MASK where a file number to be played is provided by binary activation of GPIO, there is no "latch" pin, so in theory the VS1000D can read wrong file number if it reads just as my MCU is setting more than 1 pin? Am I overthinking this?
The probability will be very, very low. And if the player detects a change, it will cancel the current song (probably before it has output anything) and play the new one.
blowtorch wrote: Mon 2019-07-01 12:32 I assume GPIO are read (keyscan) via "GPIOCtrlIdleHook"?
When I compile, I get warning saying the following code has no effect:

Code: Select all

for (mask = 0; mask < 10000; mask++)
                USEX(0);
What command is USEX?
USEX(0) is a macro for volatile read from (or write to) X data memory, address 0. Thus the code produces a small delay. (The GPIO pins are first driven low, then switched to inputs, and read after delay. This works even when there are no pull-downs on the pins.) The warning by the compiler is probably incorrect.
blowtorch wrote: Mon 2019-07-01 12:32Where do I define GPIO_NODRIVE and find more information on this? What is frequency of reading IO pins likely to be if using this option?
I am driving the GPIO pins using a MCU, so do not need debounce, is there a way of switching this off?
The GPIO control doesn't need debounce, because it doesn't get triggered by changes in the GPIO but the scans happen by sampling.

GPIO_NODRIVE should be in gpioctrl.c . Which version of the package you have?
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook
blowtorch
User
Posts: 4
Joined: Sat 2019-06-29 13:01

Re: VS1000 overall latency

Post by blowtorch »

All noted, thank you Pasi.

First to answer your question regarding version: The first version used was the Sparkfun "little soundie" project, stored on github. I have no idea what changes they made to your issued code or what version they based their release on in the first place. I am still using this code, modified by myself.

I have also downloaded "VS1000AudioModule-072-VSIDE.zip" and installed that to vside, and I am looking at basing all my code on this version. First I will have to study this code, because your module is using older "B" version of VS1000 chip, and the board I have uses "D" version. Also, the board I have is lacking many pins broken out on the VS1000 Audio module you supply and that this code was developed for. And the flash size is different.

Staying on the GPIO control subject and timing, I see in GPIOCtrlIdleHook the first thing the code does is test the value of "uiTrigger", if this is zero the code does nothing. From what you have told me, uiTrigger is being set 16 times per second. But then how often is GPIOCtrlIdleHook being called? If at same rate, there would be no need to test uiTrigger. Also I can find no reference to GPIO_NODRIVE, where would this be declared and what exactly would it do?

I am a little OCD and I hate code that has no effect or good reason for existing, and just wastes instruction cycles that could be used for other things. In my use case the pcb design is pulling down the IO pins so there is no need to drive them low first. Can I remove this code, and the delays, and just have GPIOCtrlIdleHook read the GPIO? This will then execute in a fraction of the time it is taking at the moment. I do not know the VS1000 architecture,but we going from maybe > 68k instructions to maybe <100 instructions (eliminate 2 x 10k loops + loop overhead). I have not seen the option for vside to generate assembly listing so cannot quantify this.

Some electrical question:
1. Regarding voltage...I have seen the chip power specifications listed at 3.3V to 5.5V. But elsewhere I saw minimum voltage was 3.6V. On the back page of datasheet under errata it says for the VS1000D "Default 3V IO voltage setting reduced from 3.6V to 3.3V (control value 31 to 27)". On Page 5 of datasheet it says for Recommended operating, Regulator input: Min AVDD+0.3, typical 4, max 5.25. Weighing up all these items, it seems that using 3.3V would be OK, and that is what we have used so far. Can you confirm this is OK for production design? And could we use 3.3V for both the VS1000D and VS1000B versions of the chip?


Our production design will use 16 megabit flash. The boards we are using now have only 4m bits, so around 476k bytes available. I plan to swap out the flash chips for some 16mb version, and will order these this week.
Ultimately the plan is to integrate the VS1000 chip into an existing pcb design. An option is to use UART control to save pins, so I must still look at that.

Final questions:
Where can I test if a file is being played, or if it has finished?

Is there any benefit to turning volume to 0 if no file active, and to turn it back up when a file starts?
User avatar
pasi
VLSI Staff
Posts: 2120
Joined: Thu 2010-07-15 16:04

Re: VS1000 overall latency

Post by pasi »

Voltage: The supply of the VS1000 Audio Module is 3.6..5.5V. The voltage goes to VHIGH, and the regulators in VS1000 IC are used to generate CVDD, IOVDD, and AVDD under software control. There are defaults after reset, e.g. IOVDD starts with 1.8V. If GPIO0_7 is pulled high during boot, the ROM firmware switches the IOVDD to 3.3V (closer to 3.6V in VS1000B/C).

VS1000D contains some ROM patches, including the more sensible 3.3V IOVDD. The difference should not be relevant with the Audio Module firmware, for example the firmware overrides the IO voltage after booting.
usbmass.c:

Code: Select all

#if 1 /* 2015-04-27 3.3V */
  voltages[voltIoSuspend] = voltages[voltIoPlayer] = voltages[voltIoUSB] = 27;
  PowerSetVoltages(&voltages[voltCorePlayer]);
#endif
The 0.72 version should adapt to the SPI FLASH size as long as the FLASH supports the REMS command in the way it's expected to work. The size is only used for the USB Mass storage, so getting the size wrong is not really a big deal if you program content through the uSD card.

However, if you want to use programming through USB, you must check that the SPI FLASH has the 4kB sector erase option. (And also SDUPDATE.PRG probably needs some changes if only 64kB block erase is available.)
blowtorch wrote: Thu 2019-07-04 11:39 I see in GPIOCtrlIdleHook the first thing the code does is test the value of "uiTrigger", if this is zero the code does nothing. From what you have told me, uiTrigger is being set 16 times per second. But then how often is GPIOCtrlIdleHook being called?
The main player loop opens a file, then calls the appropriate decoder. The decoder reads raw data and outputs samples, ending up in the audio FIFO. If the FIFO is too full and cannot take more samples, the output routine will wait until there is more room, and during this wait the idle hook gets called so that you can perform co-operative multitasking.

Usually the user interface runs on the idle hook.

As long as there is enough CPU to decode the audio at real time, the idle hook gets called a lot.
blowtorch wrote: Thu 2019-07-04 11:39Also I can find no reference to GPIO_NODRIVE, where would this be declared and what exactly would it do?
It seems I'm a bit ahead in my development version and should schedule some time to make a new release of the firmware. See attached for the latest gpioctrl.c .
blowtorch wrote: Thu 2019-07-04 11:39I am a little OCD and I hate code that has no effect or good reason for existing, and just wastes instruction cycles that could be used for other things. In my use case the pcb design is pulling down the IO pins so there is no need to drive them low first. Can I remove this code, and the delays, and just have GPIOCtrlIdleHook read the GPIO?
Yeah, that's what GPIO_NODRIVE does. It expects the GPIO's to have pull-downs (or pull-ups depending on the GPIO_INVERTED define), so it can just read the pins without waiting.

You can look at the ".a" files in the Emulation-Debug/ directory for the asm version of the compilation.
blowtorch wrote: Thu 2019-07-04 11:39Where can I test if a file is being played, or if it has finished?
The main play loop set player.currentFile to -1 when it is not playing a file. (See GPIO_PLAYING_INDICATOR from gpioctrl.c .)
blowtorch wrote: Thu 2019-07-04 11:39Is there any benefit to turning volume to 0 if no file active, and to turn it back up when a file starts?
No, but it might make cancelling songs behave a little better. (See QUIET_CANCEL, but it doesn't seem to be implemented with gpio control. Could be copied from uartctrl.c though.)
Attachments
gpioctrl.c
(10.22 KiB) Downloaded 417 times
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook
blowtorch
User
Posts: 4
Joined: Sat 2019-06-29 13:01

Re: VS1000 overall latency

Post by blowtorch »

Hi Pasi

All noted. Thank you. I had a frustrating time with some programming, but it turned out the problem seems to be a WAV file, not the code. Here is much simplified code to:
1. Read first 3 GPIO, and play according sound file
2. If GPIO is high before end of play, restart the sound file
3. When sound file finished, and no more GPIO, do nothing, and wait for next GPIO.

It works perfect with OGG, but when using same code with 8 bit or 16 bit WAV file, the module hangs up after playing. Same result if testing for uiTrigger or not.

Do you have any idea why it will work with OGG but not WAV?

Code: Select all

// JN GPIOCTRL.H for fast, restartable sound
// This code working perfectly with OGG.  Files restart, and play once

#include "system.h"
#include <stdio.h>  // Standard io
#include <stdlib.h> // VS_DSP Standard Library
#include <vs1000.h> // VS1000B register definitions
#include <vectors.h>  // VS1000B vectors (interrupts and services)
#include <minifat.h>  // Read Only Fat Filesystem
#include <mapper.h> // Logical Disk
#include <string.h> // memcpy etc
#include <player.h> // VS1000B default ROM player
#include <audio.h>  // DAC output
#include <codec.h>  // CODEC interface
#include <vsNand.h>
#include <mappertiny.h>
#include <usb.h>
#include <dev1000.h>
#include "gpioctrl.h"

extern struct CodecServices cs;
void puthex(u_int16 a);

#define GPIO_0_to_2     0x0007 // 7 for first 3 pins, F for first 4 pins
//#define GPIO0_PLAYING_INDICATOR  (1<<6) // GPIO0_CLE /*CLE=GPIO0_12*/

void GPIOCtrlIdleHook(void)
{

//    if (uiTrigger) {
 //       uiTrigger = 0;
        {
            register u_int16 mask;
            mask = (PERIP(GPIO0_IDATA) ^ GPIO0_PULLUPS) & GPIO_0_to_2;
            if (mask) {
                    player.currentFile = player.nextFile = mask - 1;
                    cs.cancel = 1;
                    player.pauseOn = 0;
            }
            else {
                player.currentFile = 0xffffU;
            }
        }
   // }
}

void GPIOInit(void)
{
register u_int16 mask;
    player.nextFile = -1; // No file is being played when we start
    player.volume = -24; // Max volume
    
    PERIP(GPIO0_MODE) &= ~GPIO_0_to_2;
    PERIP(GPIO0_CLEAR_MASK) = GPIO_0_to_2;
    PERIP(GPIO0_SET_MASK) = GPIO_0_to_2 & GPIO0_PULLUPS;
    PERIP(GPIO0_DDR) |= GPIO_0_to_2; // Drive to 0
    PERIP(GPIO0_DDR) &= GPIO_0_to_2; // To inputs    
}
User avatar
pasi
VLSI Staff
Posts: 2120
Joined: Thu 2010-07-15 16:04

Re: VS1000 overall latency

Post by pasi »

WAV decoding is faster, so more time is spent in the idle hook.

Maybe a few debugs can tell you whether the lockup happens in the player (is idlehook being called?) or in the main play loop - doesn't start a new file playback when it should.

Continuously writing to player.currentFile in idlehook might produce some interaction with the main play loop.
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook
Post Reply