Another code dump... God I hate serial communication.
main.h
// ----------------------------------------------------------------------
// Include files
// ----------------------------------------------------------------------
#ifndef _MAIN_H_
#define _MAIN_H_
#include "msp430f5172.h"
#include "init.h"
#include "render.h"
#include "drawUtils.h"
#include "uart.h"
// ----------------------------------------------------------------------
// definitions
// ----------------------------------------------------------------------
// PWM resolution
#define PWM_RESOLUTION 0x0E
// how many cycles to delay between shift register writes (is multiplied by inverse square root lookup table)
#define PWM_DELAY_CYCLES 16
// enable and disable rows
#define ENABLE_ROW 0x00
#define DISABLE_ROW 0x10
// shift register control
#define SHIFT_REGISTER_WRITE 0x40
#define SHIFT_REGISTER_OUTPUT 0x80
// ----------------------------------------------------------------------
// global variables
// ----------------------------------------------------------------------
// holds the data of the matrix
//
// The array is structured in a way so only one byte has to be written to the port every cycle in order to save time.
// The PWM data is precalculated in the ISR and is stored in the array as well.
// There are physically multiple entire frames of the matrix stored in memory. The number of frames is specified by PWM_RESOLUTION.
// Even though a lot of memory is being used, it's being exchanged for speed.
//
// bit0 - bit5 hold the next bits to be shifted into the shift registers
// bit6 - bit7 must be 0 to ensure SHCP and STCP can trigger the shift registers to write
// array is structured as [Serial data for shift registers][Row][PWM vector]
extern unsigned char pixelArray[8][16][PWM_RESOLUTION];
// variable for enabling and disabling rows.
// Should be set to either ENABLE_ROW or DISABLE_ROW
extern unsigned char ROW_EN;
// utility functions
unsigned char absolute( char value );
extern inline unsigned short blendColours( unsigned short colour1, unsigned short colour2, unsigned char startPosition, unsigned char endPosition, unsigned char position, unsigned char blendDistance );
extern inline unsigned char isOffScreen( signed char x, signed char y );
#endif // _MAIN_H_
main.c
// ----------------------------------------------------------------------
// LED Matrix Driver
// ----------------------------------------------------------------------
// Programmed by : Alex Murray
// Marcel Kaltenrieder
// ----------------------------------------------------------------------
// This program will render a 16x16 matrix of RGB LEDs.
//
// This module can communicate via UART with other devices.
// Check the documentation for protocol details.
// ----------------------------------------------------------------------
/*
-------------------------------------------------------------------------
Pin Layout
-------------------------------------------------------------------------
_______________________
| MSP430F5172 |
| |
------| P1.0 P3.0 |------ DS_R_0 OUT/D
TxD ------| P1.1 P3.1 |------ DS_R_1 OUT/D
RxD ------| P1.2 P3.2 |------ DS_G_0 OUT/D
------| P1.3 P3.3 |------ DS_G_1 OUT/D
------| P1.4 P3.4 |------ DS_B_0 OUT/D
------| P1.5 P3.5 |------ DS_B_1 OUT/D
------| P1.6 P3.6 |------ SHCP OUT/D
------| P1.7 P3.7 |------ STCP OUT/D
| |
OUT/D ROW_0 ------| P2.0 |
OUT/D ROW_1 ------| P2.1 |
OUT/D ROW_2 ------| P2.2 |
OUT/D ROW_3 ------| P2.3 |
OUT/D /ROW_EN ------| P2.4 |
------| P2.5 |
------| P2.6 |
------| P2.7 |
| |
|_______________________|
-------------------------------------------------------------------------
Pin description
-------------------------------------------------------------------------
Pin Name | Description
---------------------+-------------------------------------------------------------
TxD | For serial communication
RxD |
---------------------+-------------------------------------------------------------
ROW_0 | Selects the active row to write to.
ROW_1 | These 4 bits are externally demultiplexed to 16 bits.
ROW_2 |
ROW_3 |
---------------------+-------------------------------------------------------------
/ROW_EN | When set to 1, all LEDs are deactivated
---------------------+-------------------------------------------------------------
DS_R_0 | Lower byte for Red colour data to write to shift registers
DS_R_1 | Higher byte for Red colour data to write to shift registers
DS_G_0 | Lower byte for Green colour data to write to shift registers
DS_G_1 | Higher byte for Green colour data to write to shift registers
DS_B_0 | Lower byte for Blue colour data to write to shift registers
DS_B_1 | Higher byte for Blue colour data to write to shift registers
---------------------+-------------------------------------------------------------
SHCP | Serial data is read in on positive edge
STCP | Serial data is applied to outputs on positive edge
*/
// ----------------------------------------------------------------------
// Include files
// ----------------------------------------------------------------------
// main header
#include "main.h"
// ----------------------------------------------------------------------
// global variables & arrays
// ----------------------------------------------------------------------
// see main.h for more info
unsigned char pixelArray[8][16][PWM_RESOLUTION];
unsigned char ROW_EN;
// ----------------------------------------------------------------------
// Main entry point
// ----------------------------------------------------------------------
void main( void )
{
// Initialse device
initDevice();
// initialise screen
cls();
/*
// annoy zingg
dot( 0x2F, 0xEEE );
dot( 0x1E, 0xEEE );
dot( 0x0D, 0xEEE );
dot( 0x0C, 0xEEE );
dot( 0x0B, 0xEEE );
dot( 0x0A, 0xEEE );
dot( 0x19, 0xEEE );
dot( 0x28, 0xEEE );
dot( 0x38, 0xEEE );
dot( 0x48, 0xEEE );
dot( 0x58, 0xEEE );
dot( 0x69, 0xEEE );
dot( 0x7A, 0xEEE );
dot( 0x7B, 0xEEE );
dot( 0x7C, 0xEEE );
dot( 0x7D, 0xEEE );
dot( 0x6E, 0xEEE );
dot( 0x5F, 0xEEE );
dot( 0x4F, 0xEEE );
dot( 0x3F, 0xEEE );
dot( 0x2A, 0x00E );
dot( 0x5A, 0x00E );
dot( 0x2B, 0x00E );
dot( 0x5B, 0x00E );
dot( 0x2D, 0x0EE );
dot( 0x3E, 0x0EE );
dot( 0x4E, 0x0EE );
dot( 0x5D, 0x0EE );
*/
//blendColourLine( 0, 8, 6, 12, 0x0E0, 0xE00 );
//blendColourBox( 0, 8, 7, 15, 0xE00, 0x0E0, 0x00E, 0xEE0 );
//blendColourFillBox( 0, 8, 7, 15, 0xEEE, 0xEEE, 0x000, 0x000 );
blendColourFillBox( 0, 0, 7, 7, 0xE00, 0x0E0, 0x00E, 0xEEE );
blendColourFillBox( 8, 8, 15, 15, 0xEEE, 0xEE0, 0xE0E, 0x0EE );
blendColourFillBox( 0, 8, 8, 15, 0x0E0, 0xE70, 0xEEE, 0xEE0 );
blendColourFillBox( 8, 0, 15, 7, 0x00E, 0xEEE, 0x70E, 0xE0E );
// main loop
while( 1 )
{
if( timeToProcessBuffer == 2 ) processCommandBuffer();
}
}
// ----------------------------------------------------------------------
// Utility functions and other stuff
// ----------------------------------------------------------------------
// returns the absolute value of a number
unsigned char absolute( char value )
{
if( value & 0x80 ) return 0-value;
return value;
}
// The question is: Will it Blend?
extern inline unsigned short blendColours( unsigned short colour1, unsigned short colour2, unsigned char startPosition, unsigned char endPosition, unsigned char position, unsigned char blendDistance )
{
return ((((colour1&0xF00)>>8)*(endPosition-position)/blendDistance + ((colour2&0xF00)>>8)*(position-startPosition)/blendDistance)<<8) | ((((colour1&0x0F0)>>4)*(endPosition-position)/blendDistance + ((colour2&0x0F0)>>4)*(position-startPosition)/blendDistance)<<4) | ((colour1&0x00F)*(endPosition-position)/blendDistance + (colour2&0x00F)*(position-startPosition)/blendDistance);
}
// returns true if the point is out of bounds of the screen
extern inline unsigned char isOffScreen( signed char x, signed char y )
{
return (x&0xF0 || y&0xF0);
}
init.h
// ----------------------------------------------------------------------
// Initialisations
// ----------------------------------------------------------------------
#ifndef _INIT_H_
#define _INIT_H_
// initialising functions
void initDevice( void );
void cfgPort1( void );
void cfgPort2( void );
void cfgPort3( void );
void cfgUART( void );
void cfgSystemClock( void );
void cfgTimerA( void );
#endif // _INIT_H_
init.c
// ----------------------------------------------------------------------
// Initialisations
// ----------------------------------------------------------------------
// header files
#include "init.h"
#include "main.h"
// ------------------------------------------------------------------------------------------------------------------
// call this to initialise the device
void initDevice( void )
{
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
// setup clock
cfgSystemClock();
// configure timers
cfgTimerA();
// configure ports
cfgPort1();
cfgPort2();
cfgPort3();
// configure UART serial interface
cfgUART();
// enable global interrupts
__bis_SR_register(GIE);
}
void cfgPort1( void )
{
P1SEL = 0x06; // select TxD and RxD
}
void cfgPort2( void )
{
P2DIR |= 0x1F;
P2SEL = 0xE0;
P2OUT = 0x00;
}
void cfgPort3( void )
{
P3DIR |= 0xFF;
P3SEL = 0x00;
ROW_EN = ENABLE_ROW;
}
void cfgSystemClock( void )
{
// set up internal clock
UCSCTL3 |= SELREF_2; // Set DCO FLL reference = REFO
UCSCTL4 |= SELA_2; // Set ACLK = REFO
__bis_SR_register(SCG0); // Disable the FLL control loop
UCSCTL0 = 0x0000; // Set lowest possible DCOx, MODx
UCSCTL1 = DCORSEL_5; // Select DCO range 24MHz operation
UCSCTL2 = 0x0300; // Set DCO Multiplier for 30MHz
__bic_SR_register(SCG0); // re-enable the FLL control loop
// Worst-case settling time for the DCO when the DCO range bits have been
// changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
// UG for optimization.
// 32 x 32 x 12 MHz / 32,768 Hz = 375000 = MCLK cycles for DCO to settle
__delay_cycles(375000);
// Loop until XT1 & DCO fault flag is cleared
do
{
UCSCTL7 &= ~(XT1LFOFFG + XT1HFOFFG + DCOFFG);
// Clear XT1,DCO fault flags
SFRIFG1 &= ~OFIFG; // Clear fault flags
}while (SFRIFG1&OFIFG); // Test oscillator fault flag
}
void cfgTimerA( void )
{
TA0CCTL0 = CCIE; // CCR0 interrupt enabled
TA0CCR0 = 35000;
TA0CTL = TASSEL_2 + MC_1 + TACLR + 0x00C0; // SMCLK, upmode, clear TAR
}
void cfgUART( void )
{
// configure UART
UCA0CTL1 |= UCSWRST; // **Put state machine in reset**
UCA0CTL1 |= UCSSEL_2; // SMCLK (29088000)
UCA0BR0 = 0xDA; // 252 for Baud 115'200
UCA0BR1 = 0;
UCA0MCTL |= UCBRS_1 + UCBRF_0; // Modulation UCBRSx=1, UCBRFx=0
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt
}
drawUtils.h
// ----------------------------------------------------------------------
// Drawing Utilities
// ----------------------------------------------------------------------
#ifndef _DRAWUTILS_H_
#define _DRAWUTILS_H_
void cls( void );
void dot( unsigned char coord, unsigned short rgb );
void blendColourBox( unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned short topLeftColour, unsigned short bottomLeftColour, unsigned short topRightColour, unsigned short bottomRightColour );
void blendColourFillBox( unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned short topLeftColour, unsigned short bottomLeftColour, unsigned short topRightColour, unsigned short bottomRightColour );
void box( unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned short colour );
void fillBox( unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned short colour );
void blendColourLine( unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned short colour1, unsigned short colour2 );
void line( unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned short colour );
void _circle_draw8points( unsigned char* cx, unsigned char* cy, signed char* x, signed char* y, unsigned short* colour );
void circle( unsigned char x, unsigned char y, unsigned char radius, unsigned short colour );
void fillCircle( unsigned char x, unsigned char y, unsigned char radius, unsigned short colour );
void blendColourFillCircle( unsigned char x, unsigned char y, unsigned char radius, unsigned short insideColour, unsigned short outsideColour );
#endif // _DRAWUTILS_H_
drawUtils.c
// ----------------------------------------------------------------------
// Drawing Utilities
// ----------------------------------------------------------------------
// include files
#include "drawUtils.h"
#include "main.h"
// ------------------------------------------------------------------------------------------------------------------
// Will draw a filled box from x1,y1 to x2,y2 with a different colour for each corner and blend between them
void blendColourFillBox( unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned short topLeftColour, unsigned short bottomLeftColour, unsigned short topRightColour, unsigned short bottomRightColour )
{
// local variables
unsigned char x, y;
unsigned short finalColour;
unsigned char blendFactorX = x2-x1;
unsigned char blendFactorY = y2-y1;
// blend entire top and bottom rows and store in array
unsigned char blendTableR[16][2];
unsigned char blendTableG[16][2];
unsigned char blendTableB[16][2];
for( x = x1; x <= x2; x++ )
{
blendTableB[x][0] = ((topLeftColour&0xF00)>>8)*(x2-x)/blendFactorX + ((topRightColour&0xF00)>>8)*(x-x1)/blendFactorX;
blendTableR[x][0] = ((topLeftColour&0x0F0)>>4)*(x2-x)/blendFactorX + ((topRightColour&0x0F0)>>4)*(x-x1)/blendFactorX;
blendTableG[x][0] = (topLeftColour&0x00F)*(x2-x)/blendFactorX + (topRightColour&0x00F)*(x-x1)/blendFactorX;
blendTableB[x][1] = ((bottomLeftColour&0xF00)>>8)*(x2-x)/blendFactorX + ((bottomRightColour&0xF00)>>8)*(x-x1)/blendFactorX;
blendTableR[x][1] = ((bottomLeftColour&0x0F0)>>4)*(x2-x)/blendFactorX + ((bottomRightColour&0x0F0)>>4)*(x-x1)/blendFactorX;
blendTableG[x][1] = (bottomLeftColour&0x00F)*(x2-x)/blendFactorX + (bottomRightColour&0x00F)*(x-x1)/blendFactorX;
}
// blend between rows calculated above
for( x = x1; x <= x2; x++ )
{
for( y = y1; y <= y2; y++ )
{
// blend y coordinates
finalColour = (blendTableB[x][0]*(y2-y)/blendFactorY + (blendTableB[x][1])*(y-y1)/blendFactorY)<<8;
finalColour |= (blendTableR[x][0]*(y2-y)/blendFactorY + (blendTableR[x][1])*(y-y1)/blendFactorY)<<4;
finalColour |= blendTableG[x][0]*(y2-y)/blendFactorY + (blendTableG[x][1])*(y-y1)/blendFactorY;
// set pixel
dot( y|(x<<4), finalColour );
}
}
// return
return;
}
// ------------------------------------------------------------------------------------------------------------------
// Will draw the outline of a box from x1,y1 to x2,y2 with a different colour for each corner and blend between them
void blendColourBox( unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned short topLeftColour, unsigned short bottomLeftColour, unsigned short topRightColour, unsigned short bottomRightColour )
{
// local variables
unsigned char x;
unsigned char blendFactorX = x2-x1;
unsigned char blendFactorY = y2-y1;
// blend top and bottom rows
for( x = x1; x <= x2; x++ )
{
dot( y1|(x<<4), blendColours( topLeftColour, topRightColour, x1, x2, x, blendFactorX) );
dot( y2|(x<<4), blendColours( bottomLeftColour, bottomRightColour, x1, x2, x, blendFactorX) );
}
// blend left and right columns
for( x = y1; x <= y2; x++ )
{
dot( x|(x1<<4), blendColours( topLeftColour, bottomLeftColour, y1, y2, x, blendFactorY) );
dot( x|(x2<<4), blendColours( topRightColour, bottomRightColour, y1, y2, x, blendFactorY) );
}
// return
return;
}
// ------------------------------------------------------------------------------------------------------------------
// will draw the outline of a box with one colour
void box( unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned short colour )
{
// local variables
unsigned char x;
// draw box
for( x = x1; x <= x2; x++ )
{
dot( y1|(x<<4), colour );
dot( y2|(x<<4), colour );
}
for( x = y1; x <= y2; x++ )
{
dot( x|(x1<<4), colour );
dot( x|(x2<<4), colour );
}
// return
return;
}
// ------------------------------------------------------------------------------------------------------------------
// will draw a filled box with one colour
void fillBox( unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned short colour )
{
// local variables
unsigned char x, y;
// draw box
for( x = x1; x <= x2; x++ )
{
for( y = y1; y <= y2; y++ )
{
dot( y|(x<<4), colour );
}
}
// return
return;
}
// ------------------------------------------------------------------------------------------------------------------
// will draw a line from point A to point B with one colour
void line( unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned short colour )
{
// get delta
unsigned char dx = absolute(x2-x1);
unsigned char dy = absolute(y2-y1);
char sx, sy;
if( x1 < x2 ) sx=1; else sx=-1;
if( y1 < y2 ) sy=1; else sy=-1;
char err = dx - dy;
char e2;
// plot line
while(1)
{
dot( y1|(x1<<4), colour );
if( x1 == x2 && y1 == y2 ) break;
e2 = 2*err;
if( e2 > 0-dy )
{
err -= dy;
x1 += sx;
}
if( e2 < dx )
{
err += dx;
y1 += sy;
}
}
// return
return;
}
// ------------------------------------------------------------------------------------------------------------------
// will draw a line from point A to point B and blend between two colours
void blendColourLine( unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned short colour1, unsigned short colour2 )
{
// get delta
unsigned char dx = absolute(x2-x1);
unsigned char dy = absolute(y2-y1);
char sx, sy;
if( x1 < x2 ) sx=1; else sx=-1;
if( y1 < y2 ) sy=1; else sy=-1;
char err = dx - dy;
char e2;
// plot line
unsigned char x=x1, y=y1, blendStart, blendEnd;
while(1)
{
// blend colours using longest distance and draw line
if( dx > dy )
{
if( x2 > x1 ){ blendStart = x1; blendEnd = x2; }else{ blendStart = x2; blendEnd = x1; }
dot( y|(x<<4), blendColours( colour1, colour2, blendStart, blendEnd, x, dx) );
}else{
if( y2 > y1 ){ blendStart = y1; blendEnd = y2; }else{ blendStart = y2; blendEnd = y1; }
dot( y|(x<<4), blendColours( colour1, colour2, blendStart, blendEnd, y, dy) );
}
// draw line
if( x == x2 && y == y2 ) break;
e2 = 2*err;
if( e2 > 0-dy )
{
err -= dy;
x += sx;
}
if( e2 < dx )
{
err += dx;
y += sy;
}
}
// return
return;
}
// ------------------------------------------------------------------------------------------------------------------
// will draw an empty circle with one colour
void circle( unsigned char cx, unsigned char cy, unsigned char radius, unsigned short colour )
{
// local variables
signed char f = 1-radius;
signed char ddF_x = 1;
signed char ddF_y = (-2)*radius;
signed char x = 0;
signed char y = radius;
// draw first 8 points
_circle_draw8points( &cx, &cy, &x, &y, &colour );
// Bresenham Algorithm
while ( x < y )
{
if( f >= 0 )
{
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;
_circle_draw8points( &cx, &cy, &x, &y, &colour );
}
// return
return;
}
// ------------------------------------------------------------------------------------------------------------------
// will draw a filled circle with one colour
void fillCircle( unsigned char x, unsigned char y, unsigned char radius, unsigned short colour )
{
// draw circles with decreasing radius
for( int i = radius; i != 0; i-- )
{
circle( x, y, i, colour );
circle( x+1, y, i-1, colour );
}
// return
return;
}
// ------------------------------------------------------------------------------------------------------------------
// will draw a filled circle and blend between an outer and inner colour
void blendColourFillCircle( unsigned char x, unsigned char y, unsigned char radius, unsigned short insideColour, unsigned short outsideColour )
{
// draw circles with decreasing radius
for( int i = radius; i != 0; i-- )
{
circle( x, y, i, blendColours( insideColour, outsideColour, 0, radius, i, radius ) );
circle( x+1, y, i-1, blendColours( insideColour, outsideColour, 0, radius, i, radius ) );
}
// dot in centre
dot( y|(x<<4), insideColour );
// return
return;
}
void _circle_draw8points( unsigned char* cx, unsigned char* cy, signed char* x, signed char* y, unsigned short* colour )
{
signed char nx, ny;
nx = *cx+*x; ny = *cy+*y; if( isOffScreen( nx, ny ) ){}else{ dot( ny|(nx<<4), *colour ); }
nx = *cx-*x; ny = *cy+*y; if( isOffScreen( nx, ny ) ){}else{ dot( ny|(nx<<4), *colour ); }
nx = *cx+*x; ny = *cy-*y; if( isOffScreen( nx, ny ) ){}else{ dot( ny|(nx<<4), *colour ); }
nx = *cx-*x; ny = *cy-*y; if( isOffScreen( nx, ny ) ){}else{ dot( ny|(nx<<4), *colour ); }
nx = *cx+*y; ny = *cy+*x; if( isOffScreen( nx, ny ) ){}else{ dot( ny|(nx<<4), *colour ); }
nx = *cx-*y; ny = *cy+*x; if( isOffScreen( nx, ny ) ){}else{ dot( ny|(nx<<4), *colour ); }
nx = *cx+*y; ny = *cy-*x; if( isOffScreen( nx, ny ) ){}else{ dot( ny|(nx<<4), *colour ); }
nx = *cx-*y; ny = *cy-*x; if( isOffScreen( nx, ny ) ){}else{ dot( ny|(nx<<4), *colour ); }
return;
}
// ------------------------------------------------------------------------------------------------------------------
// will clear the screen
void cls( void )
{
unsigned char x, y, i;
for( x = 0; x != 8; x++ )
{
for( y = 0; y != 16; y++ )
{
for( i = 0; i != PWM_RESOLUTION; i++ ) pixelArray[x][y][i] = 0x00;
}
}
return;
}
// ------------------------------------------------------------------------------------------------------------------
// Will set a pixel to the specified colour
void dot( unsigned char coord, unsigned short rgb )
{
// get x coordinate
unsigned char x = (coord & 0x70) >> 4;
unsigned char x_inverse = 7-x;
// shift bit is set to one if x coordinate > 7 so the pixel is rendered to the other half of the display
unsigned char shift = (coord & 0x80) || 0;
// get y coordinate
unsigned char y = coord & 0x0F;
// used to extract the data
unsigned char i, colour, pwm;
// disable interrupts during array manipulation
__bic_SR_register( GIE );
// clears only the pixels we're manipulating in the array
unsigned char clr1 = 0xF5>>shift, clr2 = 0xDF>>shift;
for( i = 0; i != PWM_RESOLUTION; i++ )
{
pixelArray[x][y][i] &= clr1;
pixelArray[x_inverse][y][i] &= clr2;
}
// extracts blue
pwm = rgb & 0x000F;
colour = 0x02 >> shift;
for( i = 0; i != pwm; i++ )
{
pixelArray[x][y][i] |= colour;
}
// extracts green
rgb = rgb >> 4;
pwm = rgb & 0x000F;
colour = 0x20 >> shift;
for( i = 0; i != pwm; i++ )
{
pixelArray[x_inverse][y][i] |= colour;
}
// extracts red
pwm = rgb >> 4;
colour = 0x08 >> shift;
for( i = 0; i != pwm; i++ )
{
pixelArray[x][y][i] |= colour;
}
// enable interrupts
__bis_SR_register( GIE );
// return
return;
}
render.h
// ----------------------------------------------------------------------
// Handels rendering of LEDs
// ----------------------------------------------------------------------
#ifndef _RENDER_H_
#define _RENDER_H_
void refreshScreen( void );
#endif // _RENDER_H_
render.c
// ----------------------------------------------------------------------
// Handels rendering of LEDs
// ----------------------------------------------------------------------
// include files
#include "render.h"
#include "main.h"
// ------------------------------------------------------------------------------------------------------------------
// refreshes the entire screen
void refreshScreen( void )
{
// local variables
unsigned char x, y, currentPWMCycle;
for( y = 0; y != 16; y++ )
{
// output current row
P2OUT = y | ROW_EN;
// pwm control
for( currentPWMCycle = 0; currentPWMCycle != PWM_RESOLUTION; currentPWMCycle++ )
{
// delay as to make LED brightness to PWM ratio linear
// Lookup table: 255, 180, 128, 90, 64, 45, 32, 23, 16, 12, 8, 6, 4, 3, 2, 1,0
switch( currentPWMCycle )
{
case 1 : __delay_cycles( PWM_DELAY_CYCLES*0 ); break;
case 2 : __delay_cycles( PWM_DELAY_CYCLES*1 ); break;
case 3 : __delay_cycles( PWM_DELAY_CYCLES*2 ); break;
case 4 : __delay_cycles( PWM_DELAY_CYCLES*3 ); break;
case 5 : __delay_cycles( PWM_DELAY_CYCLES*4 ); break;
case 6 : __delay_cycles( PWM_DELAY_CYCLES*6 ); break;
case 7 : __delay_cycles( PWM_DELAY_CYCLES*8 ); break;
case 8 : __delay_cycles( PWM_DELAY_CYCLES*12 ); break;
case 9 : __delay_cycles( PWM_DELAY_CYCLES*16 ); break;
case 10 : __delay_cycles( PWM_DELAY_CYCLES*23 ); break;
case 11 : __delay_cycles( PWM_DELAY_CYCLES*32 ); break;
case 12 : __delay_cycles( PWM_DELAY_CYCLES*45 ); break;
case 13 : __delay_cycles( PWM_DELAY_CYCLES*64 ); break;
case 14 : __delay_cycles( PWM_DELAY_CYCLES*90 ); break;
default: break;
}
// output serial data
for( x = 0; x != 8; x++ )
{
// NOTE: my god, I hope the shift registers can handle this. It's torture I say, TORTURE
// NOTE2: On second thought, they *were* a pain to solder. I guess it's only fair to punish them
// output next 6 bits
P3OUT = pixelArray[x][y][currentPWMCycle];
// write them to shift registers
P3OUT |= SHIFT_REGISTER_WRITE;
}
// output shift registers to LEDs
P3OUT |= SHIFT_REGISTER_OUTPUT;
}
// reset shift registers to 0
// stops signals from overlapping and causing half-on LEDs
for( x = 0; x != 8; x++ )
{
P3OUT = 0x00;
P3OUT |= SHIFT_REGISTER_WRITE;
}
P3OUT |= SHIFT_REGISTER_OUTPUT;
}
// return
return;
}
// ------------------------------------------------------------------------------------------------------------------
// for refreshing the display
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR( void )
{
refreshScreen();
}
#pragma vector=CODE
uart.h
// ----------------------------------------------------------------------
// UART handling
// ----------------------------------------------------------------------
#ifndef _UART_H_
#define UART_H_
// command list
#define CMD_CLS 0x00
#define CMD_DOT 0x01
#define CMD_BLEND_COLOUR_BOX 0x02
#define CMD_BLEND_COLOUR_FILL_BOX 0x03
#define CMD_BOX 0x04
#define CMD_FILL_BOX 0x05
#define CMD_BLEND_COLOUR_LINE 0x06
#define CMD_LINE 0x07
#define CMD_CIRCLE 0x08
#define CMD_FILL_CIRCLE 0x09
#define CMD_BLEND_COLOUR_FILL_CIRCLE 0x0A
// command states
#define CMD_STATE_NOP 0x00
#define CMD_STATE_CLS 0x01
#define CMD_STATE_DOT__POSITION 0x02
#define CMD_STATE_DOT__COLOUR_MSB 0x03
#define CMD_STATE_DOT__COLOUR_LSB 0x04
#define CMD_STATE_BLEND_COLOUR_BOX__POSITION_A 0x05
#define CMD_STATE_BLEND_COLOUR_FILL_BOX__POSITION_A 0x06
#define CMD_STATE_BOX__POSITION_A 0x07
#define CMD_STATE_FILL_BOX__POSITION_A 0x08
#define CMD_STATE_BLEND_COLOUR_LINE__POSITION_A 0x09
#define CMD_STATE_LINE__POSITION_A 0x0A
#define CMD_STATE_CIRCLE__POSITION 0x0B
#define CMD_STATE_FILL_CIRCLE__POSITION 0x0C
#define CMD_STATE_BLEND_COLOUR_FILL_CIRCLE__POSITION 0x0D
// buffer for commands
#define COMMAND_BUFFER_SIZE 12
extern unsigned char commandBuffer[ COMMAND_BUFFER_SIZE ];
extern unsigned char commandBufferWritePtr;
extern unsigned char commandBufferReadPtr;
extern unsigned char timeToProcessBuffer;
// function prototypes
void processCommandBuffer( void );
#endif // _UART_H_
uart.c
// ----------------------------------------------------------------------
// UART handling
// ----------------------------------------------------------------------
// include files
#include "uart.h"
#include "main.h"
// initialise buffer
unsigned char commandBuffer[ COMMAND_BUFFER_SIZE ];
unsigned char commandBufferWritePtr = 0;
unsigned char commandBufferReadPtr = 0;
unsigned char timeToProcessBuffer = 0;
// ------------------------------------------------------------------------------------------------------------------
// process data if command buffer is full
void processCommandBuffer( void )
{
// reset flag
timeToProcessBuffer = 0;
// state of the command
unsigned char commandState = CMD_STATE_NOP;
// data to be extracted
unsigned char posA, posB;
unsigned short cA, cB, cC, cD;
unsigned char data;
// disable UART interrupt
//UCA0IE &= ~UCRXIE;
// extract command to execute
switch( commandBuffer[ commandBufferReadPtr ] )
{
case CMD_CLS : commandState = CMD_STATE_CLS; break;
case CMD_DOT : commandState = CMD_STATE_DOT__POSITION; break;
case CMD_BLEND_COLOUR_BOX : commandState = CMD_STATE_BLEND_COLOUR_BOX__POSITION_A; break;
case CMD_BLEND_COLOUR_FILL_BOX : commandState = CMD_STATE_BLEND_COLOUR_FILL_BOX__POSITION_A; break;
case CMD_BOX : commandState = CMD_STATE_BOX__POSITION_A; break;
case CMD_FILL_BOX : commandState = CMD_STATE_FILL_BOX__POSITION_A; break;
case CMD_BLEND_COLOUR_LINE : commandState = CMD_STATE_BLEND_COLOUR_LINE__POSITION_A; break;
case CMD_LINE : commandState = CMD_STATE_LINE__POSITION_A; break;
case CMD_CIRCLE : commandState = CMD_STATE_CIRCLE__POSITION; break;
case CMD_FILL_CIRCLE : commandState = CMD_STATE_FILL_CIRCLE__POSITION; break;
case CMD_BLEND_COLOUR_FILL_CIRCLE : commandState = CMD_STATE_BLEND_COLOUR_FILL_CIRCLE__POSITION; break;
default : commandState = CMD_STATE_NOP; break;
}
// command not recognized or no more buffer space left
if( commandBufferReadPtr == commandBufferWritePtr )
{
//UCA0IE |= UCRXIE;
return;
}
if( commandState == CMD_STATE_NOP )
{
commandBufferReadPtr = commandBufferWritePtr;
//UCA0IE |= UCRXIE;
return;
}
commandBufferReadPtr++;
// loop through buffer
for( ; commandBufferReadPtr != commandBufferWritePtr; commandBufferReadPtr++ )
{
// get next set of data
data = commandBuffer[ commandBufferReadPtr ];
// process command states
switch( commandState )
{
// clear screen
case CMD_STATE_CLS :
cls();
commandState = CMD_STATE_NOP;
break;
// dot
case CMD_STATE_DOT__POSITION :
posA = data;
commandState = CMD_STATE_DOT__COLOUR_MSB;
break;
case CMD_STATE_DOT__COLOUR_MSB :
cA = data;
cA <<= 4;
commandState = CMD_STATE_DOT__COLOUR_LSB;
break;
case CMD_STATE_DOT__COLOUR_LSB :
cA |= (data>>4);
dot( posA, cA );
commandState = CMD_STATE_NOP;
break;
// nothing
default: break;
}
// wrap buffer
if( commandBufferReadPtr+1 == COMMAND_BUFFER_SIZE ) commandBufferReadPtr = 255;
}
// enable UART interrupt
//UCA0IE |= UCRXIE;
// return
return;
}
// ------------------------------------------------------------------------------------------------------------------
// Interrupt for receiving data
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR( void )
{
// process received data, if any
switch(__even_in_range(UCA0IV,4))
{
case 0:break; // Vector 0 - no interrupt
case 2: // Vector 2 - RXIFG
// check for buffer overflow
if( commandBufferWritePtr+1 == commandBufferReadPtr ) break;
// store received command
commandBuffer[ commandBufferWritePtr ] = UCA0RXBUF;
// check for ending signature (0xFFFF)
if( commandBuffer[ commandBufferWritePtr ] == 0xFF )
timeToProcessBuffer++;
else
timeToProcessBuffer = 0;
// increase pointer
if( commandBufferWritePtr+1 == COMMAND_BUFFER_SIZE ) commandBufferWritePtr = 255;
commandBufferWritePtr++;
break;
case 4:break; // Vector 4 - TXIFG
default: break;
}
}
TheComet