Subversion Repositories Code-Repo

Rev

Blame | Last modification | View Log | RSS feed

#include <xc.h>
#include <plib.h>
#include "defines.h"
#include "CUBE.h"
#include "SPI1.h"

static CUBE_DATA *cube_data_ptr;
static unsigned char current_layer;

inline void Cube_Delay() {
    // Small delay to ensure that latch speeds are < 30Mhz
    Nop();
    Nop();
    Nop();
}

void Cube_Init(CUBE_DATA *data) {
    cube_data_ptr = data;
    current_layer = 0;

    SFT_D = 0;
    SFT_S = 0;
    SFT_K = 0;
    SFT_R = 0;
    GSLAT = 0;
    XBLNK = 0;
    
    SFT_D_TRIS = 0;
    SFT_S_TRIS = 0;
    SFT_K_TRIS = 0;
    SFT_R_TRIS = 0;
    GSLAT_TRIS = 0;
    XBLNK_TRIS = 0;

    // Clear the shift register
    Cube_Delay();
    SFT_K = 1;
    Cube_Delay();
    SFT_K = 0;
    Cube_Delay();
    SFT_S = 1;
    Cube_Delay();
    SFT_S = 0;
    Cube_Delay();
    SFT_R = 1;

    int i,j;
    // Write configuration data to the DC/BC/FC/UD registers
    unsigned char DCS[GCS_LAYER_SIZE] = {0};
    for (i = 0; i < 8; i++) {
        int offset = i * GCS_REG_SIZE;

        for (j = 0; j < 21; j++) {
            DCS[offset + j] = 0xFF; // Dot correction
        }
        
        // Warning: do not set BC > 0x8F
        DCS[offset + 21] = 0x1F; // Global red brightness
        DCS[offset + 22] = 0x1F; // Global green brightness
        DCS[offset + 23] = 0x1F; // Global blue brightness

        // DC low range, auto repeat, no timing reset, 8 bit counter mode
        DCS[offset + 24] = 0x68; // 0110 1000
    }

    Cube_Clear();
    
    GSLAT = 1;
    SPI1_Write(DCS, GCS_LAYER_SIZE, &Cube_DCS_Write_Callback);
    Delay_MS(8); // Delay until the entire DCS write is finished
}

void Cube_Timer_Interrupt(void) {
    // Write to the GCS register
    SPI1_Write(cube_data_ptr->GCS[current_layer], GCS_LAYER_SIZE, &Cube_GCS_Write_Callback);
}

void Cube_DCS_Write_Callback(void) {
    // GSLAT must be >7ms after DCS write
    Delay_MS(7);
    GSLAT = 0;
    Cube_Delay();
    GSLAT = 1;
    Cube_Delay();
    GSLAT = 0;
}

void Cube_GCS_Write_Callback(void) {
    // Disable LED output and latch in written data to GCS
    XBLNK = 0;
    Cube_Delay();
    GSLAT = 1;
    // Set the shift register to turn on the current layer
    int i;
    for (i = 0; i < CUBE_LAYER_COUNT; i++) {
        Cube_Delay();
        SFT_D = (i == CUBE_LAYER_COUNT - current_layer - 1) ? 1 : 0;
        Cube_Delay();
        SFT_K = 1;
        Cube_Delay();
        SFT_K = 0;
    }
    Cube_Delay();
    SFT_S = 1;
    Cube_Delay();
    SFT_S = 0;
    Cube_Delay();
    // Enable LED output
    XBLNK = 1;
    Cube_Delay();
    GSLAT = 0;

    current_layer = (current_layer == CUBE_LAYER_COUNT-1) ? 0 : current_layer + 1;
}

void Cube_Clear(void) {
    int i,j;
    for (i = 0; i < CUBE_LAYER_COUNT; i++)
        for (j = 0; j < GCS_LAYER_SIZE; j++)
            cube_data_ptr->GCS[i][j] = 0x00;
}

void Cube_Set_All(int R, int G, int B) {
    R &= 0x0FFF;
    G &= 0x0FFF;
    B &= 0x0FFF;
    int i,j,k;
    for (i = 0; i < CUBE_LAYER_COUNT; i++) {
        for (j = 0; j < CUBE_ROW_COUNT; j++) {
            int j_var = j * GCS_REG_SIZE;
            for (k = 0; k < 4; k++) {
                int k_var = j_var + (k * 9);
                cube_data_ptr->GCS[i][k_var+0] = R & 0xFF;;
                cube_data_ptr->GCS[i][k_var+1] = (G << 4) | (R >> 8);
                cube_data_ptr->GCS[i][k_var+2] = G >> 4;
                cube_data_ptr->GCS[i][k_var+3] = B & 0xFF;
                cube_data_ptr->GCS[i][k_var+4] = (R << 4) | (B >> 8);
                cube_data_ptr->GCS[i][k_var+5] = R >> 4;
                cube_data_ptr->GCS[i][k_var+6] = G & 0xFF;
                cube_data_ptr->GCS[i][k_var+7] = (B << 4) | (G >> 8);
                cube_data_ptr->GCS[i][k_var+8] = B >> 4;
            }
        }
    }
}

void Cube_Set_Layer(int layer, int R, int G, int B) {
    R &= 0x0FFF;
    G &= 0x0FFF;
    B &= 0x0FFF;
    int i,j;
    for (i = 0; i < CUBE_ROW_COUNT; i++) {
        int i_var = i * GCS_REG_SIZE;
        for (j = 0; j < 4; j++) {
            int j_var = i_var + (j * 9);
            cube_data_ptr->GCS[layer][j_var+0] = R & 0xFF;;
            cube_data_ptr->GCS[layer][j_var+1] = (G << 4) | (R >> 8);
            cube_data_ptr->GCS[layer][j_var+2] = G >> 4;
            cube_data_ptr->GCS[layer][j_var+3] = B & 0xFF;
            cube_data_ptr->GCS[layer][j_var+4] = (R << 4) | (B >> 8);
            cube_data_ptr->GCS[layer][j_var+5] = R >> 4;
            cube_data_ptr->GCS[layer][j_var+6] = G & 0xFF;
            cube_data_ptr->GCS[layer][j_var+7] = (B << 4) | (G >> 8);
            cube_data_ptr->GCS[layer][j_var+8] = B >> 4;
        }
    }
}

void Cube_Set_Pixel(int layer, int row, int column, int R, int G, int B) {
    R &= 0x0FFF;
    G &= 0x0FFF;
    B &= 0x0FFF;
    int var = row * GCS_REG_SIZE + (column / 2 * 9);
    switch (column % 2) {
        case 0:
            cube_data_ptr->GCS[layer][var+0] = R & 0xFF;
            cube_data_ptr->GCS[layer][var+1] = (G << 4) | (R >> 8);
            cube_data_ptr->GCS[layer][var+2] = G >> 4;
            cube_data_ptr->GCS[layer][var+3] = B & 0xFF;
            cube_data_ptr->GCS[layer][var+4] = (cube_data_ptr->GCS[layer][var+4] & 0xF0) | (B >> 8);
            break;
        case 1:
            cube_data_ptr->GCS[layer][var+4] = (cube_data_ptr->GCS[layer][var+4] & 0x0F) | (R << 4);
            cube_data_ptr->GCS[layer][var+5] = R >> 4;
            cube_data_ptr->GCS[layer][var+6] = G & 0xFF;
            cube_data_ptr->GCS[layer][var+7] = (B << 4) | (G >> 8);
            cube_data_ptr->GCS[layer][var+8] = B >> 4;
            break;
    }
}