I am currently working on a visible light communication project. I have seen similar projects made by other people, for example:



But they all have one thing in common, that is the system needs a continuous light source to operate. If the light source is moved away or a hand is blocking the light path, the photodiode on the receiving end cannot detect light and the communication stops. To come up with a solution, I want to send data in chunks so that even if the light source is moved away during transmission, the audio can still be played for another 10~15 seconds.

Below is a block diagram that illustrates my very rough idea:

block diagram

  1. A headphone jack is connected to a smartphone to get the analog signal of the music
  2. Signal is amplified and converted to digital signal and sends to a microcontroller
  3. To send data in chunks, the data should be recorded and stored inside a buffer
  4. The mcu modulates the LED to send the data. I am using OOK modulation (so for example if a data value is 100, the binary representation is 01100100, then the LED goes OFF-ON-ON-OFF-OFF-ON-OFF-OFF)
  5. Sensor receives the data, data is amplified and stored inside a buffer of the receiving end's mcu
  6. Use a DAC and play the audio

So my question is: Is this the most straightforward way to achieve what I want? Am I going in the right direction and is there anything that can be improved? I know this question is very broad since I didn't specify the size of the audio, the sampling rate, the desired quality of the sound, the speed of transmission... list can go on. I am only aiming to send a 10~15 seconds audio file for now and the quality isn't the main goal as long as its recognizable.

Any suggestion and advice is appreciated!

  • \$\begingroup\$ Have you looked at IEEE 802.15.7 LAN, Visible Light Communications \$\endgroup\$ – Misunderstood Mar 6 '18 at 22:34

Your overall approach looks good but its missing a few elements.

Unless the light received from the LED by the photodiode is much more powerful than the ambient light, you will need some way to reject ambient light. Typically ambient light is going to be more powerful than your LED.

850nm (near IR) LEDs are often used specifically because there is not very much sunlight near that wavelength. You would then use a photodiode that is matched to the frequency of your LED.

Using an LED with an narrow beam angle will concentrate the light in a smaller area. Narrower angles will give you correspondingly more flux for a given wattage, but will be correspondingly harder to aim at the receiver.

Using the right LED and photodiode will help a lot but it may not get you all the way there. You may need to add a high pass filter as part of your photodiode amplifier. The cutoff frequency should be much higher than 60Hz to avoid picking up flicker from light bulbs.

You need to consider what sample rate and bit depth you want for the audio stream. For example 32Ksps 16-bit audio would need to transmit at 512kbps. If you were using a micro-controller that could execute 32 million instructions per second, then you would only have 64 instruction cycles to process each bit. That's a pretty tight timing budget considering that you need to do an ADC conversion, possibly send each bit multiple times as part of some modulation scheme, and manage buffers.

Telephone quality audio has a bandwidth of 3.4kHz. If transmitted at 8 bits per sample it would need need to transmit 27.2kbps. In that case the same 32 MIPS microcontroller would have closer to 1200 cycles to process each sample, which is far more manageable.

You need to decide if you want the transmission to be loss-less or if you are willing to accept some loss. The additional overhead of acknowledged transmission may force a tradeoff that lowers your sample rate or bit depth in order to meet timing.

You don't really need two way communication to send to music. The success of broadcast radio proves that. Just accepting a few bad bits could just mean that occasionally you get a blip of static from the speaker (the same as you do from broadcast radio). Using the proper encoding scheme for the transmitted bits (such as delta-sigma or similar) would reduce he effects of any single bit errors.

Adding packet overhead to verify that the data is correct will require more CPU clock cycles to process checksums or CRCs. Acknowledgement of packets could take additional time while the CPU waits for the reply. It would double the number of transmitters / receivers you need. But for all its down sides you could at least guarantee with very high certainty that the data was correct.

You need to consider the effect of clock drift between the two MCUs. For example if your first MCU sends a bit every 100 clock cycles and the second MCU samples a bit every 100 cycles and the clocks frequencies are different by say 1%, then every 100 bits you may get an extra bit (or loose a bit). A UART is a common way of synchronizing timing when sending bytes between two systems. Other methods such as delta sigma modulation (mentioned above) are tolerant of single bit errors.

  • \$\begingroup\$ Why not use a laser instead of an LED? Laser modules are extremely cheap. That would solve ambient issues. \$\endgroup\$ – panic attack Feb 23 '18 at 1:01
  • \$\begingroup\$ Good point about the relative clock drift, it's an easily overlooked issue in digital audio transmission. You have basically three options: 1.) Have the receiver discard or repeat samples to avoid overflowing or underflowing its buffer, respectively. 2.) In many microcontrollers you can slightly tune the RC oscillator frequency with control bits. Use that feature to increase the clock frequency of the receiver as the buffer fills up and vice versa, forming a kind of PLL. Alternatively vary the DAC sample rate, although the timer res might be insufficient 3.) Do variable sample rate conversion. \$\endgroup\$ – jms Feb 23 '18 at 1:05
  • \$\begingroup\$ User is not talking about single bit errors though but second or two long holes in the signal. \$\endgroup\$ – Trevor_G Feb 23 '18 at 9:21

What are describing is buffering the audio data for a number of seconds to cover breaks in transmission.

This is a common practice in pretty much every streaming audio and video service you will find on the internet etc and is why there is a delay between live to air and streaming signals.

However, in order to do that you may need to have bidirectional communication.

That is, somehow the transmitting side needs to know the receiver has correctly detected the previous packet before it can send the next one. If it the receiver reports an error or does not respond the transmitter keeps sending the same packet till it does, or till it times out. If you do not do that you will of course have annoying holes in the sound.

When things are working well, the transmitter/receiver will be transferring data in almost real time, but the receiver holds off on playing for a number of seconds so there is a buffer of time to allow the occasional intermittent break in communications. Since the communication rate is faster than the play rate, once communications is re-established, the buffer quickly refills.

Other than that, the rest of your scheme is fairly classic.

However, the light signal should be sent as a modulated carrier, not just on off. That way the receiver can selectively extract the signal light from any other background light or other sources.


As Immibus points out, I think, there is another way that is single ended.

The transmitter can break it's buffer up into say one 15 one second chunks each with a sequence number or timestamp then send the entire buffer as a packet. Then collect another second of sound adding it the end of the FIFO buffer, (ditching the 15S old chunk) send the whole thing, repeat. That way each chunk gets sent chunks number of times.

The receiver then keeps it's own buffer of chunks filled from those packets.

When it successfully receives the next packet from the sender it sticks the chunks in the appropriate locations in the buffer based on the chunk sequence number or time stamp, basically stitching the data back into the right time sequence.

This method does require higher bandwidth though.

  • 1
    \$\begingroup\$ It doesn't necessarily need to, the sender could use forward error correction (most basically, it could send the same 10-15 second chunk over and over for the whole 10-15 seconds) \$\endgroup\$ – immibis Feb 22 '18 at 23:14
  • \$\begingroup\$ @immibis how would it know when to stop? \$\endgroup\$ – Trevor_G Feb 22 '18 at 23:16
  • \$\begingroup\$ when the next chunk is available and the previous one has expired (so sending it now would be useless) \$\endgroup\$ – immibis Feb 22 '18 at 23:22
  • \$\begingroup\$ @immibis I think we are at cross-purposes here, but I think I get what you meant... See edit \$\endgroup\$ – Trevor_G Feb 22 '18 at 23:32
  • \$\begingroup\$ @Trevor_G To make it bidirectional, can I use a different wavelength LED (maybe IR) on the receiving side to let the transmitter know that a packet has been correctly received? \$\endgroup\$ – Wei T Feb 22 '18 at 23:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.