0% found this document useful (0 votes)
76 views7 pages

8x8x8 Code

This document contains code for driving a TLC5940 LED display using a PIC24 microcontroller. It includes functions for initializing the microcontroller clocks and peripherals like SPI and timers. It also contains functions for updating the LED display values in memory and shifting them out via SPI. The main loop uses these functions to test the display by sequentially lighting up rows of LEDs with a scrolling pattern.

Uploaded by

Balu Bhovi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
0% found this document useful (0 votes)
76 views7 pages

8x8x8 Code

This document contains code for driving a TLC5940 LED display using a PIC24 microcontroller. It includes functions for initializing the microcontroller clocks and peripherals like SPI and timers. It also contains functions for updating the LED display values in memory and shifting them out via SPI. The main loop uses these functions to test the display by sequentially lighting up rows of LEDs with a scrolling pattern.

Uploaded by

Balu Bhovi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
You are on page 1/ 7

#include <p24HJ128GP502.

h>
#include "pic24_all.h"
//#include "pic24_util.h"
//#include "pic24_delay.h"

//config bits
_FBS(BWRP_WRPROTECT_OFF);
_FGS(GSS_OFF & GCP_OFF & GWRP_OFF);
_FOSCSEL(FNOSC_PRIPLL & IESO_OFF);
_FOSC(FCKSM_CSDCMD & IOL1WAY_OFF & OSCIOFNC_ON & POSCMD_HS );//High speed external
crystal
_FWDT(FWDTEN_OFF);
_FPOR(FPWRT_PWR1);

#define NUM_TLCS 12 //how many TLCs in serial, this is taken from the arduino
tlc library
#define NUM_ROWS 8 //how many multiplexed rows, this is not currently
implemented here.

int dummy_spi_read; //SPI buffer must be read not to cause overflow even if no data
is received.
//volatile int count=0;

volatile int row = 0;

//static volatile int row_enable[8] ={0b11111110,0b01111111,0b10111111,0b11011111,


0b11101111,0b11110111,0b11111011,0b11111101};
static volatile int row_enable[8] ={0b00000001,0b10000000,0b01000000,0b00100000,
0b00010000,0b00001000,0b00000100,0b00000010};//row select
volatile unsigned char isShifting; //i'm not sure this is necessary,
//stops a second interrupt starting a send if one is already in progress.

volatile int display_array[NUM_ROWS][NUM_TLCS*16]; //this is where the LED data is


actually stored

void init(void); // initialise timers, interrupts and compares


void spiinit(void); //initialise SPI

//some array modifiers


static void set(unsigned char row, unsigned char channel, int value);
static void set_row(unsigned char row, int value);
static void set_all(int value);

//SPI functions
static inline void shiftRow(unsigned char row);
static void shift16(int byte);

void a_delay(int delay);

void a_delay(int delay) {


uint16 u16_i,u16_k;
// change count values to alter delay
for (u16_k=delay; --u16_k;)
{
for (u16_i = 200 ; --u16_i ;);
}
}//delay
//main loop
int main(void)
{

init();
spiinit();

int ch;
int a;
int b;

set_all(0);

while(1)
{
//test pattern
int a =0;
for (a=0; a<8; a+=1)
{//set_all(0);

for (ch=160; ch<192; ch+=1)


{
set(a,ch,3590);
a_delay(30);
}
for (ch=80; ch<112; ch+=1)
{
set(a,ch,3590);
a_delay(30);
}
for (ch=0; ch<24; ch+=1)
{
set(a,ch,3590);
a_delay(30);
}
for (ch=40; ch<56; ch+=1)
{
set(a,ch,3590);
a_delay(30);

a_delay(600); a_delay(600);

}
}

}//main
void init(void)
{
/* Oscillator clock config */
OSCCONbits.LPOSCEN = 0; //2nd osc off
OSCCONbits.CF = 0; //clock fail off
OSCCONbits.NOSC = 0b011; //HS w PLL

//setting for 40MHz operation with 10MHz crystal


CLKDIVbits.PLLPRE = 0; //n1= 2 vco 5MHz
CLKDIVbits.PLLPOST = 0; // n2 = 2 = 80MHz
PLLFBDbits.PLLDIV = 0x1E; // m =32 vco 160MHz

AD1PCFGL = 0b1111111111; //ADC set to digital


TRISA = 0; // all PORTA pins output
TRISB = 0; // all PORTB pins output

RPOR6bits.RP12R = 0b10010; // tie rp12 to oc1 gsclk


RPOR6bits.RP13R = 0b10011; // tie rp13 to oc2 blank
RPOR7bits.RP14R = 0b10011; // tie rp14 to oc2 xlat

// Initialize and enable Timer2


T2CONbits.TCS = 0; // Select internal instruction cycle clock
T2CONbits.TGATE = 0; // Disable Gated Timer mode
T2CONbits.TCKPS = 0b00; // Select 1:1 Prescaler
T2CONbits.T32 = 0; //16bit mode

TMR2 = 0x00; // Clear timer register


PR2 = 1; // Load the period value
IPC1bits.T2IP = 0x01; // Set Timer2 Interrupt Priority Level
IFS0bits.T2IF = 0; // Clear Timer2 Interrupt Flag
IEC0bits.T2IE = 0; // Enable Timer2 interrupt

T2CONbits.TON = 1; // Start Timer 2

//Initialize Output Compare Module 1


OC1CONbits.OCM = 0b000; // Disable Output Compare Module
OC1CONbits.OCTSEL = 0; // Select Timer 2 as output compare time base

//OC1R = 0; //read only register in pwm mode

OC1RS = 1; // Load the Compare Register Value for falling edge gsclk output

//IPC0bits.OC1IP = 0x01; // Set Output Compare 1 Interrupt Priority Level


//IFS0bits.OC1IF = 0; // Clear Output Compare 1 Interrupt Flag
//IEC0bits.OC1IE = 1; // Enable Output Compare 1 interrupt
OC1CONbits.OCM = 0b110; // Select the Output Compare PWM mode

// Initialize and enable Timer3


T3CONbits.TCS = 0; // Select internal instruction cycle clock
T3CONbits.TGATE = 0; // Disable Gated Timer mode
T3CONbits.TCKPS = 0b00; // Select 1:1 Prescaler

TMR3 = 0x00; // Clear timer register


//PR3 = 4096; // Load the period value, interrupt after every gsclk cycle
PR3 = 8190; // Load the period value
//PR3 = 16380;

IPC2bits.T3IP = 0x01; // Set Timer3 Interrupt Priority Level


IFS0bits.T3IF = 0; // Clear Timer3 Interrupt Flag
IEC0bits.T3IE = 1; // Enable Timer3 interrupt

T3CONbits.TON = 1; // Start Timer

//Initialize Output Compare Module 2, blank and xlat fire immediately before
interrupt
OC2CONbits.OCM = 0b000; // Disable Output Compare Module
OC2CONbits.OCTSEL = 1; // Select Timer 3 as output compare time base

//OC2R = 4094;
OC2R = 8189;
//OC2RS = 16380;

//OC2RS = 4095;
OC2RS = 8190;
//OC2RS = 16380;

IPC1bits.OC2IP = 0x01; // Set Output Compare 2 Interrupt Priority Level


IFS0bits.OC2IF = 0; // Clear Output Compare 2 Interrupt Flag
IEC0bits.OC2IE = 0; // Enable Output Compare 2 interrupt
OC2CONbits.OCM = 0b101; // Select the Output Compare Continuous Pulse mode

void spiinit(void)
{

//config pins for SPI1


RPOR4bits.RP9R = 0b01001; //ss out RP9, unused ensures slave mode isn't
accidentally initiated

RPOR5bits.RP10R = 0b00111; //SDO data out RP10


RPOR5bits.RP11R = 0b01000; //sck clock out RP11

IFS0bits.SPI1IF = 0; //Clear the Interrupt Flag


IEC0bits.SPI1IE = 0; //Disable the Interrupt

// SPI1CON1 Register Settings


SPI1CON1bits.DISSCK = 0; //Internal Serial Clock is Enabled
SPI1CON1bits.DISSDO = 0; //SDOx pin is controlled by the module
SPI1CON1bits.MODE16 = 1; //Communication is word-wide (16 bits)
SPI1CON1bits.SMP = 0; //Input Data is sampled at the middle of data output time
SPI1CON1bits.CKE = 1; //Serial output data changes on transition from
//Idle clock state to active clock state

SPI1CON1bits.PPRE = 0b11; //prescale 1


SPI1CON1bits.SPRE = 0b110; //prescale 2
SPI1CON1bits.CKP = 0; //Idle state for clock is a low level
//active state is a high level

SPI1CON1bits.MSTEN = 1; //Master Mode Enabled


SPI1STATbits.SPIEN = 1; //Enable SPI Module
SPI1BUF = 0x0000; //Write data to be transmitted

//Interrupt Controller Settings


IFS0bits.SPI1IF = 0; //Clear the Interrupt Flag
IEC0bits.SPI1IE = 0; //Enable the Interrupt

}//spiinit

void _ISR __attribute__((no_auto_psv)) _T2Interrupt(void) //not used


{
/* Interrupt Service Routine code goes here */
IFS0bits.T2IF = 0; //Clear Timer2 interrupt flag
PORTA ^= 0x01;

void _ISR __attribute__((no_auto_psv)) _T3Interrupt(void) //send data to TLC


{

if (!isShifting)
{
//asm( "nop");
//PORTB = 0b11111111;
PORTB = 0b00000000;
//asm( "nop");
//a_delay(1);

RPOR7bits.RP14R = 0b00000; // release rp14 = XLAT off


isShifting = 1;
//PORTB = 0b11111111;
IFS0bits.T3IF = 0; //Clear Timer3 interrupt flag

PORTA ^= 0x01;
//PORTB = 0b11111111;

shiftRow(row);

//row = 0;
//PORTB = 0b11111111;
RPOR7bits.RP14R = 0b10011; // tie rp14 back to oc2
//PORTB = 0b11111111;

PORTB = row_enable[row];
row++;

isShifting = 0;
if (row == (NUM_ROWS))
{
row = 0;

// PORTA ^= 0x01;
}
}//if isShifting
}//ISR T3 interrupt

static void shift16(int byte)


{
while( !SPI1STATbits.SPIRBF); // wait for transfer to complete
dummy_spi_read = SPI1BUF; //read spi buffer
SPI1BUF = byte; //byte is actually 2 bytes sent to spi
}

static inline void shiftRow(unsigned char row) //4 tlc values sent in 3 16 bit SPI
sends
{
int *p = display_array[row];
int * const end = p + NUM_TLCS * 16;
while (p < end)
{
unsigned int a = *p++;
unsigned int b = *p++;
unsigned int c = *p++;
unsigned int d = *p++;
shift16((a << 4) | (b >> 8));
shift16((b << 8) | (c >> 4));
shift16((c << 12) | d);
}//while
}//shiftROW

static void set(unsigned char row, unsigned char channel, int value) //very
simple!
{

display_array[row][NUM_TLCS * 16 - 1 - channel] = value;

}//set

static void set_row(unsigned char row, int value)


{

int rowlen = (NUM_TLCS*16);


int countleds;
for (countleds = 0; countleds < rowlen; countleds++)
{
display_array[row][countleds] = value;
}

}//set

static void set_all(int value)


{
int row;
for (row = 0; row < NUM_ROWS; row++)
set_row(row, value);

}//set

You might also like