• Sampling & Why My Brain Hurts

    Sam Griffen01/09/2023 at 11:41 0 comments

    Okay, so I started this project very naiive. "Why don't I just take one sample, transmit it over wireless, then output it to a DAC on the receiver". The answer to that question is: Because audio is fast.

    While trialling that approach, I quickly realised that the limiting factor would quite possibly be the SPI connection to the NRF24L01+ module. To get an audio signal that is even passable, Nyquist says I will need to sample at >40kHz, let's just do what CDs do and sample at 44kHz. That's fine, the RP2040 has a 48MHz processor - Plenty of room there!

    So, the next problem. For every packet I send over the network, there is an overhead byte where I tell the wireless module I want to transmit. Therefore, to transmit a single sample of 16 bits I need to send 24 bits over the SPI connection (I know, the RP2040 ADC is doo doo and is 12 bits at best, but realistically can only do 8 bit resolution reliably. That's fine, if it is an issue I will look into a *nice* 16 bit ADC at a later stage - That is beside the point right now). There is also a 2uS window between bytes in the RP2040 SPI protocol. Which means that for three bytes, I have an extra 6uS overhead. That means that in order to fit within the 22uS window I have between ADC samples, I would need to transmit one bit every 0.66uS. That equates to a baud rate of 1515151 baud - I reckon I can get to a lower number than this.

    I can reduce the overhead, and also increase the time I have to complete a transmission by sending multiple packets at once. After all, my plan for the receiver side is to shove samples into an external I2S DAC module. With that thing, I can just set it up to output samples at 44kHz and call it a day - it won't know the difference between one sample and four samples in a packet.

    The NRF module can technically send 32 bytes in a single packet. However, the RP2040 ADC FIFO module is only four samples long, so it doesn't really make sense to try to send more than this - Because then I would need to muck around with DMA code and work out how I know when to send 16 packets. I'm not keen on that, so for now I will take the lazy option if it works.

    So, I want to send 8 bytes (4 16 bit samples) in a single packet. This means I now have 9 bytes to transmit in a single packet, which is equivalent to 72 bits. However, I now only need to send them at a quarter of the frequency - so approximately 11kHz. That gives me a window of 90uS to transmit a single packet. Given the approximately 2uS between bytes in the RP2040 SPI protocol, so for 9 bytes I expect to have an extra 18uS overhead - Meaning that I have 72uS to send the SPI transmission in.

    Therefore, there is exactly 1uS per bit, requiring a baud rate of 1000000 minimum. Let's go for a nice 1200000 baud, which will also give a bit of a buffer at the end of the SPI transaction (Also, this will technically reduce audio lag by a few tens of microseconds?? Don't know that I care too much though).

    Okay, so. I get the RP2040 ADC to fill its FIFO, I have a dumb loop that is just checking how full the ADC FIFO is. Once it is full, the dumb loop will drain the FIFO into a byte buffer, and then throw that buffer to the wireless module to transmit over a 1200000 baud SPI connection. Seems good. 

    Checking this with my oscilliscope, it looks pretty good! 

    The transmissions repeats every 91uS (And I expect the period of one wireless transmission sequence to be 90.9uS), and I can see the command byte followed by 8 bytes, meaning that 4 samples of two bytes each are being sent. 

    .The scope also shows the SPI transaction completing after 76uS - Giving me plenty of time.

    What next? I need to check if this is actually sampling the ADC properly. That should be easy enough, drive 0V into the ADC pin, check on the scope if the bytes are all 0. Drive maximum voltage into the ADC pin, check if all the bytes are 255. The other step is to get the receiver to work, that is going to be another trick. Hopefully now that...

    Read more »