Rethinking POV : what about 3D?

Public Chat
Similar projects worth following
This is a final year students' project made in 3 month at Telecom Paris in a course about Embedded Systems (ROSE, aka SE302, given by Sam and me, Alexis), by Baptiste Pecatte, Guillaume Soudais, Ambroise Vincent, and Paul Vinchon.

CyL3D is a 3D POV system, based on an FPGA able to display images, text, 3D animations streamed through WiFi or from on-board memory.

This project describes a joint hardware and software solution that delivers a 3D-display made from a rotating 2D panel. Depth is created by lighting the pixels at a precise time during a rotation and by using the viewer’s persistence of vision to generate animations in volume. The system is connected to a WiFi network, and can thus be used for displaying enriched types of content remotely.

System components

The main part of CyL3D is a rotating PCB. It features a 40x30 LED screen divided into 10 small areas of 15 rows and 8 columns. They are driven using a TI LED driver (TLC5957), which can drive up to 16 RGB LED, and is capable of receiving the next frame while displaying the current one. The 15 rows of each area are displayed simultaneously by each driver, and the 8 columns are multiplexed using a MOSFET (Vishay Si2333CDS) and a MOSFET driver (Renesas ISL55110). The main logic for sending frames to the drivers and multiplexing columns is implemented on an Intel Cyclone V FPGA. The system uses a magnet and a hall sensor to compute the rotation speed, and thus the correct rate at which to send frames, display frames, and change columns.

The actual data sent by the FPGA comes from an HPS (an ARM processor connected to an FPGA on the same die) running Linux. A custom kernel driver is used to exchange data between a user application and the FPGA. The user application can use any means to generate a 3D image. We made most of our tests using a simple application that can render text and images on a cylinder. But through a USB port with a WiFi dongle, we've also built an application to stream an animation from our laptops. This was a very important feature since, being a rotating screen, it was really the only way to display something without having to preload it first. (As a side note, the limit on the screen size came from the maximum throughput achievable using a rotating Wifi dongle). The rotating cube example was computed on a laptop and streamed to the platform in real-time.

Power management

The display is rotated by a brushless motor, powered separately from the rest of the electronics. A single 12V input is passed to the rotating element through the brushless motor (Turnigy Aerodrive SK3 - 4250-500kv Brushless Outrunner Motor). This 12V input is then converted to 2 different voltages: 5V for the LEDs and the WiFi dongle, and 3.3V for the System On Module containing the FPGA. The system is designed to power the LEDs up to 9A on the 5V rail, enough to give a clear rendering in a brightly lit room.


As CyL3D is connected to a WiFi network, it is possible to directly control the device through a shell. Several commands are available, here are the most interesting ones:

  • Testing: To test the driver and the display system
  • Display settings: To change the general brightness of the display as well as the power given to each color. It is also possible to add a fixed angle to the image to align the front of 3D objects
  • Display Text: Show a specific string on a specific cylinder slice of the system
  • Display Time: Shows the current time on the screen
  • Display Speed: Shows the current rotation speed of the rotating screen.
  • Display Sphere: Draws a 3D sphere of given radius on the screen
  • Display Droplets: Generates falling droplets on the screen to simulate a rain effect
  • Display RAW: Loads a 3D model previously saved on the display system
  • Display Streaming: The most interesting mode, which opens a TCP server to listen on. With the appropriate client, it is possible to live stream 2D and 3D animations to the display system over the network. In our case we had a client that was able to stream a 3D game of life simulation, as well as animated 3D models generated on Blender. Take a look at the videos below for demos! It would even be possible to use a 3D camera to capture a real-life 3D model, such as a face, adapt the data and retransmit it to the 3D display system, creating what we would...
Read more »


Rotating board schematics

Adobe Portable Document Format - 882.51 kB - 06/13/2021 at 19:14



Power base schematics

Adobe Portable Document Format - 20.63 kB - 06/13/2021 at 19:06


  • 1 × SoM (FPGA: Intel 5CSEBA6U23C7N (Cyclone V SE)) MCV-6DB
  • 1 × Arduino Micro
  • 1200 × LED Broadcom ASMB-KTF0-0A306
  • 10 × LED driver TI TLC5957
  • 40 × MOSFET Vishay Si2333CDS

View all 19 components

  • Final result!

    Alexis06/13/2021 at 18:20 0 comments

    Everything is working ! Now on for the videos :-)

    Teacher (Alexis)'s word to the team : congrats for this amazing work !  

    All details and logs can be found here:

    First tests:

    And it's finally working!

  • FPGA debugging

    Alexis06/13/2021 at 18:17 0 comments

    By Ambroise:

    We are using the PIO core IP from Intel to implement debug registers accessible from the HPS to communicate easily with the FPGA. After testing that we could read and write such a register, I implemented a shell accessible in a Linux terminal inspired from ChibiOS.

    I used those IPs to act as bypass registers in our FPGA modules. The implementation is still ongoing, but I currently have a shell command to test the correct soldering of the LEDs (by lighting all of them in a dim white).

    The next step will be to complete all of our FPGA modules as well as their basic bypass register and test-benches (should be done by Monday).


    Alexis06/13/2021 at 18:16 0 comments

    By BP:

    I’ve been working on the HPS/FPGA communication, and how we will handle buffering.


    I came up with this completed version of the architecture:

    FPGA buffers will be fed by a DMA Controller. The DMAC will read data from RAM using the fpga2hps bus, and write to an AXI bus connected to all FPGA buffers.

    On the HPS side, we will have a kernel module controlling the DMAC through the hps2fpga bus. It will be responsible of DMA transfer sequencing (between all buffers), and also the transfer timing.

    The DMA source will be a pool of contiguous RAM buffers allocated by the driver.

    Finally, the driver will expose a Linux char device. Through this device, a user-space app will be able to feed the buffers with data from various source (an SD card, a Wifi streaming).


    If you think about it, each half frame-slice will need to be printed twice, for it to be seen from all points of view. Thus, the drawing flow looks like this (where each line is a half turn, and the two numbers represents the frame being drawn by each half of the panel) :

    • F(n, right) ; F(n+1, left)
    • F(n+1, left) ; F(n+1, right)
    • F(n+1, right); F(n+1, left)
    • F(n+1, left) ; F(n+2, right)

    We can see that the first half always get data from the second half at previous round. Thus, if we swap buffers smartly across drivers, we can use half-a-turn buffers. This results in 3 buffers for 2 drivers storing (F(n), right), F(n+1, left), F(n+1, right)), where at each time, one buffer is useless and can be fed by the DMAC with the next correct half.

    To start with simpler code, we will approximate to 1 buffer per driver (+33% data stored), with a full turn capacity. We will optimize only if needed, that is, if the throughput of the HPS -> FPGA is not sufficient to transfer that much data.

    In RAM, we will have a double buffer. One where we write data for the next turn, and one with data that should be used during this turn.

  • PCB done, FPGA started

    Alexis06/13/2021 at 18:13 0 comments

    By BP:


    It’s been a long time since the last post. I’ve been busy finished the routing of our vertical PCB. We use 4 layers, layer 2 being a GND plane.

    Here is the routing layer by layer, with explanations:

    Layer 1 (top)
    Layer 3
    Layer 4 (bottom)

    FPGA architecture

    Since we’re done (modulo reviewing) with the PCB, we started thinking about the FPGA architecture.

    We came up with an architecture based on 4 modules.

    • We will use the Altera On-chip Memory IP as our per-driver buffers. It is practical since it has an AXI-compatible interface that we can use to easily connect to the HPS. 
    • A synchronizer module will be in charge of time-keeping in order to load and display data at the right time. It will also select which column to display.
    • The data provider will load data from the memory and pass them to the LED-driver driver.
    • Finally, the LED-driver driver is in charge of creating the SIN/LAT signals. It will both send data to the driver (as requested per the data provider), and display those data (as requested per the synchronizer)

  • Rethinking the motor

    Alexis06/13/2021 at 18:10 0 comments

    By Guillaume:

    We had a long discussion with a student from SpiROSE (last year’s project with a rotative LED panel). He told us the problem they faced with the motor and ESC (Electronic Speed Controller). They could not get a constant speed output from the motor because the ESC was overheating, causing a shutdown and a boot up. It was caused by the motor asking too much current. The motor was one the had on hand and not perfectly fitted to their use. It was rated at 2100 RPM per Volt. While turning at 1500 RPM the ESC pulled 5A on 12V from the power supply, the same 60W would go to the motor, but to rotate at 1500 RPM it only needed 0.7V so the output current from the ESC was closing in on the max output, which caused overheating.

    So I am looking for a motor  with a lower RPM per Volts constant. I reckon a motor at around 500 RPM/V would be suitable for our project. For now I have have settled on Turnigy Aerodrive SK3 – 4250-500kv Brushless Outrunner Motor from HobbyKing. 

    Another problem was to convey the power through the axis. They had to scrub the anodising paint from the top of the motor to make a connexion to a ball bearing which was connected to the motor shaft. I would like if possible to stay away from passing to much power through the ball bearing as it can cause sparks and damage the balls. To replace this connection I am looking toward brush slip rings.

  • Size constraints

    Alexis06/13/2021 at 18:09 0 comments

    By Ambroise:

    As we are proceeding with the schematics and the PCB placing, we are realizing that we will need more than a single PCB to make everything fit. We will then design an horizontal PCB, very much like SpiRose, though ours will be rectangular for budgetary reasons and it will only host our voltage regulators. The interface between the horizontal and vertical PCBs will be three big pads: GND, 3.3V and 5V. Hence, no signal integrity concerns (at least not at this interface). I placed our 12 to 5V converter on Xpedition Layout while conforming to the PCB layout guide of the module.


    Furthermore, it appears that the PCB size of 190 by 190mm that we initially chose will be problematic for us to solder the LED automatically: the problem being the width of the PCB. I was going through the process of routing the LED drivers so that we could be stacking five of them on each side of the panel (according to our previous PCB layout idea), but that will have to be abandoned in order to make our PCB thinner. We will put 4 driver on each side and 2 above.

  • Finalizing the schematics of our ULPI transceiver

    Alexis06/13/2021 at 18:08 0 comments

    By Paul:

    Last friday we had a class about signal integrity. As we learnt about all the problems we could have, I finally understood the use of all the bypass capacitors and some of the other esoteric symbols or annotation that are no longer a mystery (such as 0-ohm resistors or DNI annotations)

    Thus, I had to update the schematic of the ULPI/USB subsystem of our project.  You can see it below. Here are some important changes :

    • Disconnected the oscillator ENA pin : according to the datasheet, having the pin on high impedance does enable the oscillator.
    • Added USB power distribution switch, the TPS2051C that is needed not to break our USB device. It limits the current of our usb device to 500mA.
    • Added bypass capacitor to oscillator and power switch.
    • Updated power supply capacitors
    • Added 10K resistor for VBUS, connected to a 10uF capacitor that should be enough for our system. The USB 2.0 specification recommends a 120uF capacitor for hosts but we do not intend to hot-plug our USB device or have a cable between our device and our system. 
    • Added names to everything.
    • Connected the RESETBn pin to our nRST.
    ULPI/USB Subsystem Schematic

    As such, our ULPI/USB system should work. However, I have a doubt about whether or not I should add a resistor on the wire between the oscillator’s CLK and the USB3320C REFCLK. Our development kit has a resistor on its schematic, but the oscillator’s datasheet does not mention to put a resistor on the CLK output. If anybody has an idea about it, I’d be happy to hear it.

  • Booting the FPGA & Schematization of the USB3320

    Alexis06/13/2021 at 18:08 0 comments

    By Paul:

    For the past days, I have been working on the schematics of our ULPI transceiver, the USB3320 and when my colleagues were working on other parts of the schematics, I had to focus on other stuff such as making our SOM work and improving our system architecture.

    Making our Cyclone V SOM work was a breath of air compared to the schematic part. Following the Quick Start Guide of our development kit, I had to make sure the jumpers were setup correctly (and they were – not sure if it was the factory default or if Alexis did his magic before giving us the devkit) and configure the UART0 interface. Once everything was set and connected on /dev/ttyUSB0, I simply plugged in the devkit and it booted correctly.

    You can see the booting log on this pastebin post

    As we would like to be able to use Wi-Fi USB dongles, we are currently adding host USB 2.0 support. Unfortunately, we must use the ULPI interface to communicate with our USB devices. Thus, we have to use a ULPI-USB transceiver.

    ULPI works with a 60MHz clock and I am unsure for now if our FPGA can generate such an accurate reference. However, the USB3320 can work with a external oscillator and it has its own PLLs to generate a 60MHz clock from a 12MHz reference clock.

    Below is a work in progress of the schematic of the USB3320 in our system. It also includes a Linear Voltage Regulator as the transceiver also needs a 1.8V DC supply. 

    What is definitely missing are the appropiate capacitors and resistors that I have not added everywhere yet.

    USB3320 Schematic (WIP)

  • Decoupling of the SoM

    Alexis06/13/2021 at 18:06 0 comments

    Altera made a spreadsheet named “Power Delivery Network” designed to determine an optimum number, type and value of decoupling capacitors to achieve the target impedance. I select the VRM type (Switcher), the supply voltage (3.3V), maximum current (2.58A), transient current (I typed 30%, but it seems extremely complicated to obtain a value without having the programming of the FPGA already done) and ripple tolerance (5% given the specifications of the FPGA and knowing that we don’t have transceivers for PCIe, which is the only bank requiring at most 3% ripple). For the spreading inductance, BGA Via inductance and plane capacitance profile I left the default values because I don’t know how to estimate that.

    Auto decoupling

    The tool looks up the capacitors it has in its database and tries to find the optimal combination for our target. With the preceding values it outputs 2x 0.01µF, 2x 0.047µF, 1x 1µF and 1x 10µF capacitors, with their respective ESR, ESL and mounting inductance (Lmnt).

    Auto decoupling

    Development board decoupling

    Development board decoupling: capacitors

    If I take the configuration of the development board of our SoM, they are using 4x 10µF and 9x 100nF capacitors. If I use the capacitors pre-configured in the Altera tool, it shows that the resulting impedance is higher than the one I got with my inputs, but given that the development board has to be designed for any configuration of the FPGA, their decoupling capacitors are certainly adapted to more extreme power draws than what we will be experiencing. So, I think it would be a good idea to keep what Aries did with their development board.

    Development board decoupling: impedance

  • Motor’s First Turns

    Alexis06/13/2021 at 18:06 0 comments

    In order to determine how much current the motor pulls, we had to make it turn with a load and monitor its consumption. The perfect load was in hand, we took last year’s LED pannel, as ours will have approximatly the same weight and dimension, therefore giving a good estimate on our power consumption.

    We took the same brushless motor as last year, a MEGA Acn 22/20/4. Which is connected to a motor controller, a EZRUN Max 10 SCT. It is rated to be able to supply up to 120A, so we could not take this value to size our power supply.  So I tested the whole system to see how much would it drain.

    First I had to understand how the controller worked. The datasheet is not very helpful, as it only says to put a RC receiver on the input wires. So I emulated one with an arduino. A RC receiver uses PPM signal, and is waiting for a 1 to 2ms pulse every 20ms. 1ms being the command for neutral throttle and 2ms for full throttle.

    In order for the motor controller to acknowledge that you sent a RC signanl, you need to start by sending neutral throttle command. It is a security measure to prevent the motor turning on when it has just been plugged in. 

    After came my first attempt with no load on the motor. It ran fine and the controller pulled around 1.5 to 2A. Then Itried with last year’s pannel, and it would not start rotating at the lowest speed, or be all jittery. My teacher told me that last year, in order to start the rotation, they sent a high speed command and backed down to lower one when it started. I did so and now the whole structure is rotating.

    LED pannel rotating. Slowed down 16 times.

    I filmed it slow motion to be able to determine the speed it’s rotating at. With the almost lowest setting it is rotating just under 20rps. At this speed it is pulling 4A under 12V. I tried making it rotate faster, so I just left it at the high speed command I use to start it up. I did not go well. Leaving a high speed command made the controller pull more than 20A because it was unable to match the requested speed. So the power outlet shut down.

    In order to get the whole system to high speed I proceeded gradually. Letting it establish at low speed for seconds and increasing the speed slowly.

    An other problem rose up, at low speed it was not that wobbly. The structure was only a bit unstable. At high speed it is a whole different story. The metal structure would move around the table and produce more noise. We will have to be very carefull about the placement of the component and plan to be able to put masses and the lower rotating part to balance the whole structure, as you would on a car tire.

View all 20 project logs

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates