Jump to content
43oh

Sending Image as RGB Array to G2553


Recommended Posts

Hi everybody,

 

Hopefully someone will be able to help.

 

The aim of this project is to send an image from my laptop over a serial port to the MSP430G2553 where the data will be processed and then the image will be shown on my RGB LED display.

 

At present I'm looking at methods of converting an image into an RGB array. I found that using GIMP, a file can be exported as a ".c" source code file which converts the image into an array. - Although the syntax is unlike any I have seen before.

 

Anyways, i am using a program I found on the web to do the sending of the data over the serial port (http://batchloaf.wordpress.com/2013/02/13/writing-bytes-to-a-serial-port-in-c/) then I am simply changing the "bytes_to_send" array to the image array.

 

On the receiving end of the transmission, I am unsure how to process the data - should I do it in the "USCI0RX_ISR" ?

 

Here's the code from which I am working:

 

#include <msp430g2553.h>
#include <msp430.h>

// TLC inputs
#define VPRG_PIN		BIT0 // TIE TO GND?
#define RX_PIN			BIT1
#define TX_PIN 			BIT2
#define GSCLK_PIN		BIT4
#define SCLK_PIN		BIT5
#define DATA    		BIT6  // DS -> 1.6 | 595 DATA PIN
#define MOSI_PIN		BIT7

#define DCPRG_PIN		BIT0 // TIE IT TO GND?
#define XLAT_PIN		BIT1
#define BLANK_PIN		BIT2
#define CLOCK		        BIT3 // SH 11 -> 2.3  // 595 OUTPUTS
#define LATCH                   BIT4 // ST 12 -> 2.4t

typedef unsigned char u_char;
typedef unsigned int u_int;
typedef unsigned short u_short;
typedef unsigned long u_long;
// ================================//
//      Prototypes                 //
// ================================//
void init( void );
void SPI( void );
void UART(void);
void updateTLC( void );
void shiftOut( u_long );
void HSV2RGB( u_short*, u_short*, u_short*, short,u_char);
void set_row_char_hue (u_char, u_long, short,u_char);
void row_refresh(u_char,short,short,short,short,short,short,short,short,short,short,short,short,short,short,short,short);
void clearArray(void);
void serialSnake(void);
void extractRGB();
// =====================================================================================
#define UPDATE {P2OUT |= (BLANK_PIN);P2OUT |= (XLAT_PIN);P2OUT &= ~(XLAT_PIN);P2OUT &= ~(BLANK_PIN);updateTLC();}
#define NUMBER_OF_OUTS 48 // TLC OUTPUTS
#define NUMBER_OF_ROWS 16
#define NUMBER_OF_COLUMNS 16
#define max_COLUMN NUMBER_OF_COLUMNS-1
#define max_ROW NUMBER_OF_ROWS-1

#define OFF 0
u_short leds[NUMBER_OF_OUTS];  // 0 - 15 Red Rows, 16 - 31 Blue Rows, 32 - 47 Green Rows {0, }
short columnArray[16] = {0x8000,0x4000,0x2000,0x1000,0x0800,0x0400,0x0200,0x0100,0x0080,0x0040,0x0020,0x0010,0x0008,0x0004,0x0002,0x0001};
u_char rowArray[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
u_char cnt = 0;
u_char SAT = 255; // full colour

// ========== SERIAL GLOBAL VARIABLES ===================================
u_char rxRow = 0;
u_char rxCol = 0;
u_char image[16][16];
u_char colour[3];
u_char Count = 0;
u_char cCount = 0;
u_char rCount = 0;
// ======================================================================

void init(void)
{
	WDTCTL = WDTPW + WDTHOLD; // disable WDT
	BCSCTL1 = CALBC1_16MHZ; // 16MHz clock
	DCOCTL = CALDCO_16MHZ;
	BCSCTL2 |= DIVS_0; // divide clock by 1

	// Setup TLC and 595 outputs
	P1DIR |= (VPRG_PIN + GSCLK_PIN + DATA);
	P1SEL |= GSCLK_PIN;	// port 1.4 configured as SMCLK out
	P2DIR |= (BLANK_PIN + XLAT_PIN + CLOCK + LATCH + DCPRG_PIN);
	P1OUT &= ~(VPRG_PIN);
	P2OUT &= ~(BLANK_PIN + XLAT_PIN);
	P2OUT &= ~DCPRG_PIN;

	// setup timer
	TA0CCR0 = 0xFFF;
	TA0CTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, up mode, 1:1
	TA0CCTL0 = CCIE; // CCR0 interrupt enabled

//	// setup FrameBuffer Timer
//	TA1CCR0 = 0xFFF;
//	TA1CTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, up mode, 1:1
//	TA1CCTL0 = CCIE; // CCR0 interrupt enabled
}

void SPI(void)
{
	// SPI setup UCB0
	P1SEL |= SCLK_PIN + MOSI_PIN; // pins 5 + 7
	P1SEL2 |= SCLK_PIN + MOSI_PIN; // UCB0CLK + UCB0SIMO
	UCB0CTL0 = UCCKPH + UCMSB + UCMST + UCSYNC; // data captured on 1st UCLK edge/changed on follwing edge, MSB first, master, 3-pin SPI,synchronous
	UCB0CTL1 |= UCSSEL_2; // SMCLK
	UCB0BR0 |= 0x01; // 1:1
	UCB0BR1 = 0;
	UCB0CTL1 &= ~UCSWRST; // clear SW
}

void UART(void)
{
	// UART Setup UCA0
	P1SEL |= RX_PIN + TX_PIN;	//Set P1.1 and P1.2 to RX and TX
	P1SEL2 |= RX_PIN + TX_PIN;
	UCA0CTL1 |= UCSSEL_2;	//SMCLK
	UCA0BR0 = 138;			//115200 @[member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""][member=""] 16MHz
	UCA0BR1 = 0;			//115200
	UCA0MCTL = UCBRS_1;		//Modulation
	UCA0CTL1 &= ~UCSWRST;	        //Start USCI
	IE2 |= UCA0RXIE;		//Enable RX interrupt
}

void main(void)
{
	u_char z;
	init();
	SPI();
	UART();

	updateTLC();
	P2OUT |= (XLAT_PIN);
	P2OUT &= ~(XLAT_PIN);
	_bis_SR_register(GIE);

	for(;
	{
//		extractRGB();
		while (!(IFG2 & UCA0RXIFG));
		for(z = 0; z < 16; z++)
		{
			leds[z] = colour[0] * 16;      //r
			leds[z+32] = colour[1] * 16;  // g
			leds[z+16] = colour[2] * 16;  // b
			shiftOut(columnArray[rxCol]);
		}


		_bis_SR_register(LPM0_bits);
	}
}

void updateTLC(void)                 // RobG's code
{
	u_char ledCounter = NUMBER_OF_OUTS >> 1;
	while (ledCounter-- > 0)
	{
		u_char i = ledCounter << 1;
		UCB0TXBUF = leds[i + 1] >> 4;
		while (!(IFG2 & UCB0TXIFG)); // TX buffer ready?
		u_char unib = leds[i + 1] << 4;
		u_char lnib = (leds[i] >> 8) & 0x0F;
		UCB0TXBUF = unib | lnib;
		while (!(IFG2 & UCB0TXIFG)); // TX buffer ready?
		UCB0TXBUF = leds[i];
		while (!(IFG2 & UCB0TXIFG)); // TX buffer ready?
	}
}

//void extractRGB(void)
//{
//	u_char i;
//	for(i=0;i<16;i++)
//	{
//		leds[i] = image[3*i][rxCol];
//		leds[i+16] = image[(3*i)+1][rxCol];
//		leds[i+32] = image[(3*i)+2][rxCol];
//		shiftOut(columnArray[rxCol]);
//	}
//}


void shiftOut(u_long val)
{
	P2OUT &= ~LATCH;
	int i;
	for (i = 0; i < 32; i++) // iterate over each bit 16
	{
		if(val & (1 << i)) {
			P1OUT |= DATA;
		} else {
			P1OUT &= ~DATA;
		}
		P2OUT |= CLOCK; // PULSE CLOCK
		P2OUT ^= CLOCK;
	}
	P2OUT |= LATCH; // PULSE LATCH
	P2OUT &= ~LATCH;
}

#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
	while(UCA0RXBUF)
	{
		if(Count < 3)
		{
			colour[Count] = UCA0RXBUF;
			Count++;
		}
		else {
			Count = 0;
		}
		if( rCount == 48 )
		{
			rxRow++;
			rCount = 0;
		}
		else {
			rCount++;
		}
		if( cCount == 16 )
		{
			cCount = 0;
		}
		else {
			rxCol++;
			cCount = 0;
		}
	}
}

#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0(void)
{
	_bic_SR_register_on_exit(LPM0_bits); // wake up main loop so that it can prepare data for the next frame
}
#pragma vector = TIMER0_A1_VECTOR
__interrupt void Timer_A1(void)
{}

I've taken out a bunch of functions which won't be used for this part of the project, so there are some variables etc. which arent used.

 

Below is the modified version of the TX code I am using with the GIMP image array included:

 

 

// serial.c / serial.cpp
// A simple serial port writing example
// Written by Ted Burke - last updated 13-2-2013
//
// To compile with MinGW:
//
//      gcc -o serial.exe serial.c
//
// To compile with cl, the Microsoft compiler:
//
//      cl serial.cpp
//
// To run:
//
//      serial.exe
//

#include <windows.h>
#include <stdio.h>

  /* GIMP RGB C-Source image dump (TEST.c) */
// export opacity 68
#define GIMP_IMAGE_WIDTH (16)
#define GIMP_IMAGE_HEIGHT (16)
#define GIMP_IMAGE_BYTES_PER_PIXEL (3) /* 3:RGB, 4:RGBA */
#define GIMP_IMAGE_PIXEL_DATA ((unsigned char*) GIMP_IMAGE_pixel_data)
static const unsigned char bytes_to_send[16 * 16 * 3 + 1] =
("\255\0\0\0\255\255\255\255\255\255\255\255\255\255\255\255\255\255\0\255\255"
 "\255\0\0\255\0\0\0\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\0\255\255\255\0\0\0\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\0\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\0\255\255"
 "\0\255\255\255\255\255\255\0\255\0\0\255\0\255\255\255\255\255\255\255\255"
 "\0\255\255\0\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\0\255\255\0\255\255\255\255\255\255\0\255\0\0\255\0\255\255"
 "\255\255\255\255\255\255\0\255\255\0\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\0\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\0\255\255"
 "\255\0\0\255\255\255\255\255\255\0\255\0\0\255\0\255\255\255\255\255\255\0"
 "\0\255\0\0\255\255\255\255\255\255\255\0\255\0\0\255\0\255\255\255\255\255"
 "\255\255\0\0\255\0\0\255\255\255\255\255\255\0\255\0\0\255\0\255\255\255\255"
 "\255\255\0\0\255\0\0\255\255\255\255\255\255\255\0\255\0\0\255\0\255\255\255"
 "\255\255\255\255\0\0\0\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\0\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\0\255"
 "\255\0\255\255\255\255\255\255\0\255\0\0\255\0\255\255\255\255\255\255\255"
 "\255\0\255\255\0\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\0\255\255\0\255\255\255\255\255\255\0\255\0\0\255\0\255"
 "\255\255\255\255\255\255\255\0\255\255\0\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\0\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\255\0\255"
 "\255\255\0\0\0\255\255\255\255\255\255\255\255\255\255\255\255\255\255\0\255"
 "\255\255\0\0\255\0\0\0\255\255\255\255\255\255\255\255\255\255\255\255\255"
 "\255\0\255\255\255\0\0");
int main()
{
    // Define the five bytes to send ("hello")
//    char bytes_to_send[5];
//  bytes_to_send[0] = 104;
//    bytes_to_send[1] = 101;
//    bytes_to_send[2] = 108;
//    bytes_to_send[3] = 108;
//    bytes_to_send[4] = 111;

    // Declare variables and structures
    HANDLE hSerial;
    DCB dcbSerialParams = {0};
    COMMTIMEOUTS timeouts = {0};

    // Open the highest available serial port number
    fprintf(stderr, "Opening serial port...");
    hSerial = CreateFile(
                "\\\\.\\COM5", GENERIC_READ|GENERIC_WRITE, 0, NULL,
                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
    if (hSerial == INVALID_HANDLE_VALUE)
    {
            fprintf(stderr, "Error\n");
            return 1;
    }
    else fprintf(stderr, "OK\n");

    // Set device parameters (115200 baud, 1 start bit,
    // 1 stop bit, no parity)
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    if (GetCommState(hSerial, &dcbSerialParams) == 0)
    {
        fprintf(stderr, "Error getting device state\n");
        CloseHandle(hSerial);
        return 1;
    }

    dcbSerialParams.BaudRate = CBR_115200;
    dcbSerialParams.ByteSize = 8;
    dcbSerialParams.StopBits = ONESTOPBIT;
    dcbSerialParams.Parity = NOPARITY;
    if(SetCommState(hSerial, &dcbSerialParams) == 0)
    {
        fprintf(stderr, "Error setting device parameters\n");
        CloseHandle(hSerial);
        return 1;
    }

    // Set COM port timeout settings
    timeouts.ReadIntervalTimeout = 50;
    timeouts.ReadTotalTimeoutConstant = 50;
    timeouts.ReadTotalTimeoutMultiplier = 10;
    timeouts.WriteTotalTimeoutConstant = 50;
    timeouts.WriteTotalTimeoutMultiplier = 10;
    if(SetCommTimeouts(hSerial, &timeouts) == 0)
    {
        fprintf(stderr, "Error setting timeouts\n");
        CloseHandle(hSerial);
        return 1;
    }

    // Send specified text (remaining command line arguments)
    DWORD bytes_written, total_bytes_written = 0;
    fprintf(stderr, "Sending bytes...");
    if(!WriteFile(hSerial, bytes_to_send, 769, &bytes_written, NULL))
    {
        fprintf(stderr, "Error\n");
        CloseHandle(hSerial);
        return 1;
    }
    fprintf(stderr, "%d bytes written\n", bytes_written);

    // Close serial port
    fprintf(stderr, "Closing serial port...");
    if (CloseHandle(hSerial) == 0)
    {
        fprintf(stderr, "Error\n");
        return 1;
    }
    fprintf(stderr, "OK\n");

    // exit normally
    return 0;
}

If anyone could help that would be much appreciated since this is the last part of my project!

 

Cheers

Link to post
Share on other sites

Hi,

 

I don't know anything about UART, but I can help explain the syntax used by GIMP for that image array.

 

Each row of the image corresponds to one of the strings. The strings contain escape sequences that encode the RGB components of each pixel in the row as literal byte values. Since there are no commas between the strings they get concatenated into one big string by the preprocessor. The result is that bytes_to_send is a linear array with three bytes for each pixel, and the rows are placed together one after another. The red component of the pixel at (7, 2) should be at bytes_to_send[(7+(2*GIMP_IMAGE_WIDTH))*3]. There's one null-terminator at the end of the big string, which is why the character array length is ((Width*Height*BPP)+1).

 

The escape codes are a bit odd though - standard C doesn't support decimal escape codes. Even stranger, although octal literals need to be preceded with a 0 everywhere else, \255 is actually an octal escape sequence. That means it encodes the decimal value 173 and so bytes_to_send[0] == 173. Weird!

Link to post
Share on other sites

Hi Tripwire, thank you so much for helping me out!

 

What I gather from what you say about the syntax of this array, is that I cannot treat this like an ordinary array.

Since the positioning of

The red component of the pixel at (7, 2) should be at bytes_to_send[(7+(2*GIMP_IMAGE_WIDTH))*3].

would be (2*16+7)*3 = 117?

 

 

Also, I'm not really sure what you mean about the escape codes. How did you get from \255 to 173?

Thanks!

Link to post
Share on other sites

@Gareeeesh: Not entirely correct, this is a ordinary array in any sense. Except for the very last entry. As it is a "string" it conforms to C string behaviours, this means there is a single '\0' character (null character) after the explicitly defined characters to denote the end-of-string (hence the '+ 1' in the array dimension). Since this is actually a binary string nistead of a text string, there might already be null character in the string. Printing this as text would thus stop et the very first occurence of the null character.

But this string is not treated as a string, it is treated as a array of bytes (and unsigned chars happen to be just that; bytes). The writing of '\#' describes a byte value as a character, so '\0' becomes the byte value 0 and '\255' becomes the byte value 173. This is octal, so numbers are conted like 0,1,2,3,4,5,6,7,10,11,12, etc. If you switch your windows calculator to scientific/engineering mode you can switch to octal numbering to convert them to decimal (normal counting), but you can also take these numbers for granted. They'll be sent as 8-bit integer values over your serial line.

Instead of separate arrays per line of image, there is a long string of pixels. After each line of image, the next line of image begins. Since each pixel is 3 bytes long (R,G,B) ech pixel is 3 bytes further in the array than the pixel before.

The first pixel is at position [0], the second at position [3], the third at position [6]. In a general sense pixel N is at position [N*GIMP_IMAGE_BYTES_PER_PIXEL].

Since the second line starts after the first line, and we know the (first) line is a known number of pixels wide, we can calculate the position of the first pixel of the second line by determining the number of pixels in a line and use that as the number of pixels. In this case, the first pixel of the second line (lines are 16 pixels wide) is the 17th pixel or pixel index [16]. In a more general sense, the first pixel of any row M is [M*GIMP_IMAGE_BYTES_PER_PIXEL*GIMP_IMAGE_WIDTH].

If we combine these two formulas. Then the Nth pixel of the Mth line becomes [N*GIMP_IMAGE_BYTES_PER_PIXEL + M*GIMP_IMAGE_BYTES_PER_PIXEL*GIMP_IMAGE_WIDTH], or a bit simpler [(N + (M*GIMP_IMAGE_WIDTH))*M*GIMP_IMAGE_BYTES_PER_PIXEL].

If you want to know the value of pixel (7,2) as tripwire used, the value becomes [(7 + (2*GIMP_IMAGE_WIDTH))*M*GIMP_IMAGE_BYTES_PER_PIXEL]. You see the formula is identical (with tripwire hardcoding 3 for GIMP_IMAGE_BYTES_PER_PIXEL).

Link to post
Share on other sites

In your RX code I see a flaw in your way of thinking. You have a 16x16 array called image, and a separate array of 3 for colour. I think you actually have a 16x16 array of colours; or a 16x16x3 array of values. This is by the way you treat it in extractRGB().

// In main()
		for(z = 0; z < 16; z++)
		{
			leds[z] = colour[0] * 16;      //r
			leds[z+32] = colour[1] * 16;  // g
			leds[z+16] = colour[2] * 16;  // b
			shiftOut(columnArray[rxCol]);
		}

You load leds[] with values from colour[] times a value and then shift out another array called columnArray. So where do you index pixels, a row, how is data transerred from leds to columnArray? I do know the answers, but I'd like you to try and understand the bug here.

 

void shiftOut(u_long val)
{
	P2OUT &= ~LATCH;
	int i;
	for (i = 0; i < 32; i++) // iterate over each bit 16
	{
		if(val & (1 << i)) {
			P1OUT |= DATA;
		} else {
			P1OUT &= ~DATA;
		}
		P2OUT |= CLOCK; // PULSE CLOCK
		P2OUT ^= CLOCK;
	}
	P2OUT |= LATCH; // PULSE LATCH
	P2OUT &= ~LATCH;
}

Why do you count up to 32? Why do you comment it iterates over 16 bits? Why do you latch after counting that?

#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
	while(UCA0RXBUF)
	{
		if(Count < 3)
		{
			colour[Count] = UCA0RXBUF;
			Count++;
		}
		else {
			Count = 0;
		}
		if( rCount == 48 )
		{
			rxRow++;
			rCount = 0;
		}
		else {
			rCount++;
		}
		if( cCount == 16 )
		{
			cCount = 0;
		}
		else {
			rxCol++;
			cCount = 0;
		}
	}
}

Do you use the collumn and row data to store any information? How many unique antries in any array are used to store information? Does that complete a picture?

 

Please, take a try to fix these issues, if you get stuck again I'd like to help you to the solution.

It might help to draw the arrays on paper and make sure you have all information you need available.

Link to post
Share on other sites

Hi Roadrunner, for this code I am using TLC5940's to drive PWM to the rows and 74HC595s for the columns.

You load leds[] with values from colour[] times a value and then shift out another array called columnArray. So where do you index pixels, a row, how is data transerred from leds to columnArray? I do know the answers, but I'd like you to try and understand the bug here.

I've just realised that the code I posted is missing this:

for(;
	{         
		while (!(IFG2 & UCA0RXIFG));
		leds[rxRow] = colour[0]*10;     //
		leds[rxRow+32] = colour[1]*16;  // 
		leds[rxRow+16] = colour[2]*16;  // 
		UPDATE;                       // this line updates the TLC (previously this was in the timer interrupt)
		shiftOut(columnArray[rxCol]); // this controls which column is lit. 
		leds[rxRow] = 0;      //r
		leds[rxRow+32] = 0;  // g
		leds[rxRow+16] = 0;
		_bis_SR_register(LPM0_bits);
	}

Ideally, I would have wanted to make an array "image[16][48]" to store the exact values for R,G and B for each pixel and the position etc.

But, this device does not have enough RAM for this, since it would need to be a global array.
 

 

void shiftOut(u_long val)
{
    P2OUT &= ~LATCH;
    int i;
    for (i = 0; i < 32; i++) // iterate over each bit 16
    {
        if(val & (1 << i)) {
            P1OUT |= DATA;
        } else {
            P1OUT &= ~DATA;
        }
        P2OUT |= CLOCK; // PULSE CLOCK
        P2OUT ^= CLOCK;
    }
    P2OUT |= LATCH; // PULSE LATCH
    P2OUT &= ~LATCH;
}

Why do you count up to 32? Why do you comment it iterates over 16 bits? Why do you latch after counting that?

In a previous version of this code I was displaying images held in memory. For some reason, when I had the for loop only counting up to 16, it did not work properly. The shiftOut function hasn't been an issue apart from that.

 

Last night I made the following changes to the RX ISR:

// In USCI0RX_ISR
        if(UCA0RXBUF)
	{
		if(Count == 0) {
			colour[Count] = UCA0RXBUF;  // should hold R component
			Count++;
		}
		else if( Count == 1 ) {
			colour[Count] = UCA0RXBUF; // G
			Count++;
		}
		else if( Count == 2 ) {
			colour[Count] = UCA0RXBUF; // B
			Count = 0;
		}
		cCount++;          // column counter
		if(cCount == 48)   // i used a premade image array as a test "bytes_to_send[16][48]" - i'll include it below
		{
			cCount=0;
			rxRow++; // go onto next row
		}
		rxCol=cCount/3;  // 16 columns
	}
	IFG2 &= ~UCA0RXIFG; // clear flag

It would be easier to hold each RGB component in an array because then I could save the image whilst nothing was being transmitted, and have the exact positiions of each pixel.

Here's the test array I made which should colour every pixel green:

static const unsigned char bytes_to_send[16][48] = {
//       r  g  b.......
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
{0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,},
};

Link to post
Share on other sites

I hope you do understand that I kind of lost track of the current state of your code.

If you have not enough memory to store [16][48] or [16][16][3] then you can juggle your bytes as much as you want, you just loose information. To show a picture of [16][16][3] you need at least that much memory. You can try to squeeze data in a more compact format, but I'd recommend to reduce the picture size first and verify that it's working as expected.

 

Old-school computers (like the C64 and the Amiga) used to share 16 bits of memory over the three colour components. Most used the 5-6-5 scheme; 5 bits red, 6 bits green and 5 bits blue. This was chosen this way because the human eye is most sensitive to green light. To implement this, you'd need some more code and processing time. But again, please verify that the rest is working as expected before using these kind of tricks.

 

The columnArray and rowArray contain constant data, since you're not changing them, prefix these lines with const to make these values immutable. As a result, the compiler will place those values in flash instead of RAM, this gives you another 48 bytes to play with.

 

Oh, and you send plain picture data over serial, if you'd ever run out of sync, you'll never have your picture showing up as expected anymore.

 

Think of a way to solve your memory issue. As you won't fit a 16x16 picture in RAM, not even using the 16-bit trick, you're bound to take a compromise. Will you reduce pixel count, will you accept using 1 byte (2 or 3 bits per colour) per pixel, or will you use a different chip with 1kB RAM?

Link to post
Share on other sites

I always try and do everything all at once when in fact I should break it down into smaller pieces like you've suggested. Later on tonight I'll create a 8*8 image or even a 4*4 and try and see if that'll work. When I was testing my most recent code the display was all lit in green, but it obviously wasn't working properly because some pixels then flashed red etc.

 

To be honest I'm to be completed this project by the end of the month where the initial spec was to display images sent via serial, so I'd compromise with a reduction in resolution as long as i could still display an image being transmitted serially.

 

Thanks again for your help Roadrunner! - especially with the GIMP .c array because I wouldn't have had a clue!

Edited by Gareeeesh
Link to post
Share on other sites

[8][8][3] fits in 192 bytes of RAM, so you should be able to fit that in. After that you could try to go to [12][12][3], which might just fit (use const on the rowArray and columnArray to free up RAM) at 432 bytes. The most important lesson of going from 8 to 12 is whether you can cross the 8 boundary, since you might have hidden dependency on 8-bits-in-a-byte that will/might show up when going to any value over 8. Going from 12 to 16 isn't much of a problem code-wise, it's just your RAM that will be a problem then.

Good luck with cleaning up and fixing code :)

Link to post
Share on other sites

I mean I could maybe use an array like: image[16][16] but first the received RGB bytes could be converted to HSV? This would take much longer for the processor to perform however. The array could either be unsigned short or u_char (limit max value to 180 then 180*2-1).

Link to post
Share on other sites

No, a unsigned short array of [16][16] is 512 bytes long. Since you have 512 bytes of RAM in total you have no RAM left for execution of the code. A [16][16] array of unsigned char can be done. But if you want to store HSV, you have the same limitation; you can store only 2 or 3 bits per component. Unless you put limitations on yourself. You could for example use 6 1 1 values; 6 bits hue, 1 bit (colour/white) saturation, 1 bit (on/off) value. Then you have 26=64 different colours (rainbow palette), plus white, plus black.

Or 5 1 2; 32 colours in either full or half intensity, full white, half intensity white and off.

But please, you're getting ahead of yourself again. You'd rather go for monochrome 8-bit value for now, if you prefer to stick with [16][16] dimension. You can choose to drive green and keep red and blue on a hard value of 0, or drive each colour with the same value and have a white image.

Link to post
Share on other sites

Old-school computers (like the C64 and the Amiga) used to share 16 bits of memory over the three colour components. Most used the 5-6-5 scheme; 5 bits red, 6 bits green and 5 bits blue. This was chosen this way because the human eye is most sensitive to green light.

 

Apologies for drifting way off topic, but 16-bit 5-6-5 format came into use a little later than that. It was used in the early days of the PC's transition to 3D hardware rendering, as well as on consoles a generation or two ago (eg PSP).

 

C64 and Amiga used indexed colour screen modes, where each pixel stored an index into a colour look-up table (aka palette).

Link to post
Share on other sites

Erm.... no. Not really.

You could link the two launchpads together over some interface (SPI, UART, etc.) and have one dedictate its behaviour to reading or writing data it sends or receives over this interface to RAM. But that would require both chips to run some more code and sacrifice pins. Additionally both will need some memory dedictated to this communication as buffers. Plus, the "external RAM" is slower than the internal RAM.

If you really want to try something like this, try splitting the display from 16x16 into two 16x8 displays and load both with half the image. You'd need to keep them in sync, but that won't be much of a problem if you use both as output device from a PC. If you let them run standalone with moveing images you'd need to have some kind of sync pulse from one to the other.

Again, such a solution will make your code more complex and thus a little harder to debug.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...