Monday, August 9, 2010

POV Globe - Part IV - Software & Data

This is in continuation to: POV Globe - Part III - Electronics

The data layout on the SD card and the software are rather technical and trivial, but still worth a mention.

Data Layout

I'm using the SD as a raw block device (i.e. no file-system). This is in order to reduce read overhead, as well as to make sure that all image data is in consecutive blocks (as mentioned in the previous post, jumping between non-consecutive blocks takes an eternity of 380us). Since reads are always in blocks, the format is block aligned. Some numbers:
  • One block of data = 512B = 4096bit = 16 columns.
  • One revolution (or "frame") = 512 columns = 32 blocks = 16KB.
  • One second of animation = 50 frames = 800KB.
A quick calculation shows that 1GB of data can hold a little over 20 minutes of 50FPS animation. My card has 2GB, and it is easy to find cards with more.
The format is as follows:
  • First 4 bytes are the total number of blocks in the image, followed by 508B of padding.
  • Then the image itself follows, column-by-column, where the bytes in each column are ordered from top 8 LEDs to bottom 8 LEDs, and the bits in each byte are ordered so that the MSB is the top LED and LSB is the bottom LED.

In order to write the raw data to the SD card, I'm using a USB card reader and the Linux dd command, directly to the device.

Software

I will not get into all the details - most of them are just technicalities.
The only part worth mentioning is how the main loop synchronizes the drawing of the columns to the physical location of the LED row, designated by a pulse from the IR sensor, once per revolution. It also needs to take into account possible out-of-sync situations, and "catch-up" if we're late.
  • A timer keeps the time elapsed since the beginning of the column.
  • The variable col_dur holds the duration of a single column (1/512 the duration of a revolution) - it is updated every time we get an IR pulse.
  • The variable pos keeps the current (estimated) physical position of the LEDs, between 0..511.
  • The variable cur_col keeps the last column that has been drawn, between 0..511.
And the main loop looks something like this:
while (true) {
  // draw all the columns until the current position
  while (cur_col != pos) {
    draw_column();
    if (++cur_col == 512) col = 0;
  }
  while (TIMER < col_dur);  // wait until the end-of row time
  // advance position according to how much time elapsed
  do {
    TIMER -= col_dur;
    if (++pos == 512) pos = 0;
  } while (TIMER >= col_dur);
  // check position sensor and make adjustments
  if (pos == 0) {
    ... wait for rising edge of the sensor ...
    ... recalculate col_dur (make it longer or equal), and reset TIMER ...
  } else if (sensor_rising_edge()) {
    // got a premature signal - we're falling behind
    ... force pos = 0, recalculate col_dur (make it shorter), and reset TIMER ...
  }
}
The draw_column() function just streams 32B of data from the SD to the LED board, pulses the latch line, and then prepares the next column (i.e. issues a SD command to get the next block and waits for it to become ready, if needed).
In practice, because of the SD latency-related problems described in my previous post, this function currently takes care of skipping the first block, while the second is fetched, and in the future it will also take care of streaming the first block from flash.
The last video in the previous post demonstrates this algorithm in action, taking button presses in lieu of IR switch signals.

5 comments:

  1. How about a live demo? :-) (Even of the non-finished design)

    ReplyDelete
  2. waiting for part 5.....

    ReplyDelete
  3. Hello

    I am building a similar project
    http://www.abluestar.com/blog/rgb-led-pov-globe-research/

    I got lots of questions and I am still doing research on all the different parts of this project. I would love to pick your mind about this project.

    1) What is the status of this project?
    2) Why not get a bigger micro-controller that has lots of ram and load as many frames before hand and stream them out as you load more frames in the background. Using a FPGA or XMOS (http://www.xmos.com/products/development-kits/xc-3-led-tile-kit) that has many cores, one to load from the SD, one to process the data, another to steam.
    3) What are you going to use as a power supply?

    I really like your maniacal set up, its a lot smarter then the way I was going to do it and I was going to incorporate it in to my own design.
    I hope thats OK?

    Please feel free to contact me directly or comment on my blog.
    funvill -=@=- funvill d0t com

    I will be checking back here often
    Have a great day

    ReplyDelete