Efficient coordinate to 3D mapping routine?

Discussion in 'Embedded Systems and Microcontrollers' started by thatoneguy, Nov 20, 2011.

  1. thatoneguy

    Thread Starter AAC Fanatic!

    Feb 19, 2009
    Making a 4x4x4 LED Cube with kid, he's doing the soldering and animations if I get the set/clear voxel, line and plane basic functions written.

    Addresses for each of the 64 LEDs are in an 8 byte array. Each LED is 3mm Teal (Blue/Green) and 1" apart in all directions from nearest neighbor. Common cathode driven, a transistor switches on the cathode for each layer when it is written to, then switches it off while next layer is on.

    Code ( (Unknown Language)):
    2. 4x4x4 LED Cube
    4.       Z-axis 0,0,3
    5.       ^
    6.      |    / Y-axis 0,3,0
    7.      |   /
    8.      |  /
    9.      | /
    10.      |/__________>  X-axis  
    11.  0,0,0           3,0,0
    Does anybody know if a nifty transformation to flip the correct bit / voxel when setvoxel(2,1,1) or clrvoxel (1,3,2) is called?

    I'd like to do is along these lines, except with 4 arrays of 16 bits.

    Below is for a tiny 2x2x2 cube, lightning fast.
    Code ( (Unknown Language)):
    2. temp=1 ;for setvoxel (0 for clrvoxel)
    4. temp <<x*1; // Shift left 0 or 1 times if x is 0 or 1
    5. temp <<(y+2)*2; // Shift left 0 or  2 times if y is 0 or 1
    6. temp << z*4; // Shift left 0 or 4 times if z is 0 or 1
    8. framebuffer=framebuffer & temp;  //Change only the requested bit via AND
    framebuffer on 2x2x2 cube is: yyxxyyxx First set of y's is top level, second set of ys is lower level, same with first/second set of x's.

    I was thinking of simply making Z a 2 byte array for xy, unsure of layout of array at the moment. A different Z array for each vertical "layer" and using shift functions.

    Interrupt sets outputs/display, lower nibble on first call to interrupt, high nibble on second call to interrupt, redraw is 130 times/second on 4Mhz internal oscillator with no glitches.

    This works with a one byte array to put the x and y in the right spot, has anybody worked with this to scale to 4x4x4 or 8x8x8?

    Once I figure out the fastest set/clear voxel routines, drawline and plane(x,y,z) functions will be next. Undecided on vector/wireframe operations.

    Platform: PIC 16F690@4Mhz code written in Sourceboost BoostC. Will probably switch to 8Mhz for 4x4x4 cube, the 2x2x2 could run at 1Mhz without glitches, but it is just one byte being dealt with.

    So far I never realized cool animations could be made with 8 LEDs in 3 dimensions.

    For an 8x8x8, may go to an 18F for more I/O on an 8x8x8, or use I2C LED Drivers to shift data into while sticking with the 16F690

    There are lots of examples of these on Youtube, from 4 to 15 LED cubes, once past 10 LEDs per side, they get really awesome looking, especially when made with RGB.
    Last edited: Nov 20, 2011
  2. John P

    AAC Fanatic!

    Oct 14, 2008
    Each plane (z = 0 to z = 3) is filled with data from 2 sequential bytes in the array, to be known as array[8].

    Then within the 2 bytes, the lowest 4 bits of the lowest byte correspond to y = 0, the higher 4 bits to y = 1, the 4 low bits of the next byte to y = 2 and finally 4 bits for y = 3.

    So for a voxel (x, y, z), I think the byte and bit numbers are:

    Byte (i.e. array index) = z*2 + y/2
    Bit (bit number 0-7 within a byte) = ((y & 1) * 4) + x

    If you chose to do a bit-set operation without using a function, it would be:

    bit_set(array[z*2 + y/2], ((y & 1)*4) + x);


    array[z*2 + y/2] |= 1 << (((y & 1)*4) + x);
    thatoneguy likes this.
  3. thatoneguy

    Thread Starter AAC Fanatic!

    Feb 19, 2009
    I'm trying to get it mapped so each 2 bytes of Z are one plane, then the same x and y pins map to the same I/O pins.

    So 0,0,0, 0,0,1 0,0,2 and 0,0,3 would be x=0, y=0 in 4 separate Z layers, since the layers are multiplexed from top to bottom.

    In other words, an x,y coordinate would make a vertical line if all z layers were enabled.

    This makes for 4 y outputs, 4 x outputs, and 4 layer select transistors for the display routine, 16 total I/O. (X PortC:0:3 and Y PORTC:4:7, and Z will be Port B 4:7)

    At a glance, I think I got which direction Z is confused on your code in my mind, so I thought I'd be more specific with which ports are connected to what for fast output.
  4. John P

    AAC Fanatic!

    Oct 14, 2008
    I was assuming, since you talked about an 8 byte array, that each LED corresponded to 1 bit. So I worked out bytes and bits to turn on any LED in XYZ space.

    But just by coincidence I read about someone else's 8x8x8 cube last night (it's attractive in operation and very neatly built) here:
    What they did was connect together the cathode of every LED in a given plane, and run vertical wires down the cube linking the anodes of all the LEDs in any vertical column--i.e. where X and Y are the same--then each of the verticals got its own anode driver. They had 64, and if you did it that way you'd need 16. I don't understand what you mean by "X and Y pins".

    If you wired it as a matrix like that, you'd have 4 plane drivers (cathodes) and 16 anode drivers, so only 20 bits to control, or if you demultiplexed the planes from 2 processor outputs, only 18 bits. But you'd probably still want to have an 8-byte array internal to the processor.
  5. thatoneguy

    Thread Starter AAC Fanatic!

    Feb 19, 2009
    Each bit is an LED, only 12 control lines, 4 for X, 4 for Y and 4 for Z, Layer Z0 is displayed during the loop, next interrupt Layer Z0 is turned off and Z1 is on (from framebuffer), displayed until next interrupt, where Z1 is turned off and Z2 is turned on, etc.

    X and Y would be the 4x4 matrix looking straight down on the cube. The method you described seems a bit more complicated. The common cathode of all LEDs in a layer are connected to the Z transistor for that layer, then the layers are cycled through quickly enough that POV leaves no flicker.

    I planned on writing to an 8 byte/64 bit array as bits, 2 bytes for each layer (4x4) framebuffer variable (or 4 2 byte/16 bit variables). I just need to figure out the easiest way to set that up so the display routine is quickest, copying the framebuffer contents to the output pins directly, for example.
  6. T.Jackson

    New Member

    Nov 22, 2011
    So you have a multi-dimensional array that you're trying to manipulate, is this correct?

    Bit confused with what you're asking if not the case :confused:
  7. nickelflipper

    Active Member

    Jun 2, 2010
    I would either get a larger PIC with two full ports available, or find a 16 bit CA led driver to write the 4x4 (i.e. two byte) array buffers. For instance a 18f26k22, 1 and 1/2 tlc59401's, and eight high side switches can produce an 8x8 rgb array running over 1000Hz easy. More of a brute strength approach.

    There are free bitmap to glcd converters out there that may work for mono color arrays. More exotic would be to use pyPIL to work things out. Never tried a cube before.