Вы находитесь на странице: 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

Вам также может понравиться