Gareeeesh 2 Posted February 5, 2013 Share Posted February 5, 2013 Hi all! I was wondering if anyone has used this algorithm with the G2231 before? I'm trying to use it but I keep getting an error message saying: "program will not fit into available memory. placement with alignment fails for section ".text" size 0x142e ." The reason I am trying to implement this is so I can represent exact colours for RGB LEDS in a large-ish matrix. Does anyone know a method to decrease the amount of memory being consumed by this algorithm, or increase the amount of memory allocated to ".text"? Any advice would be greatly appreciated. Here is the code I am using: #include <msp430g2231.h> #include <math.h> // TLC inputs #define SCLK_PIN BIT5 #define MOSI_PIN BIT7 #define GSCLK_PIN BIT4 #define BLANK_PIN BIT2 #define XLAT_PIN BIT1 #define VPRG_PIN BIT0 // 595 Inputs #define DATA BIT6 // DS -> P2.6 #define LATCH BIT6 // ST_CP -> 1.6 #define CLOCK BIT7 // 11 -> 2.7 // -------------- MACROS ------------------------------------------// #define setHigh(n) ( P1OUT |= n ) // Only for TLC! #define setLow(n) ( P1OUT &= ~n ) // TLC!! #define pulse(n) do { setHigh(n); setLow(n); } while(0) // ---------------------------------------------------------------------// typedef unsigned char u_char; typedef unsigned int u_int; typedef unsigned short int us_int; // Prototypes void init(void); void updateTLC(); void sendMOSI(u_int data); void pulseClock ( void ); void pinWrite ( unsigned int, int ); void shiftOut(unsigned char); void shift(unsigned int); void allrowsON(void); void allrowsOFF(void); void allcolsON(void); void delay (unsigned int); void bounce (int); void knight(int); void HSV2RGB(u_char *r, u_char *g, u_char *b, signed int h, u_char s, u_char v); #define NUMBER_OF_LEDS 24 #define NUMBER_OF_COLUMNS 8 #define NUMBER_OF_ROWS 8 u_int leds[NUMBER_OF_LEDS] = { 0, }; // 0 - 7 Red Rows, 8 - 15 Green Rows, 16 - 23 Blue Rows u_int rows[NUMBER_OF_ROWS] = { 0, }; u_char timerCounter = 0; short int icount = 0; void init(void) { WDTCTL = WDTPW + WDTHOLD; // disable WDT DCOCTL |= DCO0 + DCO1; // DCO = 15.25MHz BCSCTL1 |= RSEL0 + RSEL1 + RSEL2 + RSEL3; // as above BCSCTL2 |= DIVS_2; // divide clock by 8 P1OUT &= ~(VPRG_PIN + BLANK_PIN + XLAT_PIN + SCLK_PIN + MOSI_PIN ); P1DIR |= VPRG_PIN + BLANK_PIN + XLAT_PIN + SCLK_PIN + MOSI_PIN; // 595 P2SEL &= ~(CLOCK + LATCH); P1DIR |= DATA; // Setup pins as outputs P2DIR |= (CLOCK + LATCH); P1DIR |= GSCLK_PIN; // port 1.4 configured as SMCLK out P1SEL |= GSCLK_PIN; // setup timer CCR0 = 0xFFF; TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, up mode, 1:1 CCTL0 = CCIE; // CCR0 interrupt enabled } void main(void) { init(); updateTLC(); pulse(XLAT_PIN); _bis_SR_register(GIE); bounce(300); knight(300); int loopCounter = 0; int p,hue; for(; { // this loop will be executed every 16.384ms, ~61Hz //leds[0-7] = Red //leds[8-15] = Green //leds[16-23] = Blue for( hue = 0 ; hue < 360 ; hue ++) // this is where the problem lies! { HSV2RGB(0,0,0,hue,1,1); } allcolsON(); if (loopCounter < 512) {//512 for( p = 0 ; p < 8 ; p++) // R (0-7) { leds[p]++; } } else if (loopCounter < 1024) { // G (8-15) for( p = 8 ; p < 16 ; p++) { leds[p]++; } } else if (loopCounter < 1536) { //dim R (0-7) for( p = 0 ; p < 8 ; p++) { leds[p]--; } } else if (loopCounter < 2048) { // B (16 - 23) for( p = 16 ; p < 24 ; p++) { leds[p]++; } } else if (loopCounter < 2560) { //dim G (8-15) for( p = 8 ; p < 16 ; p++) { leds[p]--; } } else if (loopCounter < 3072) { // R (0-7) for( p = 0 ; p < 8 ; p++) { leds[p]++; } } else if (loopCounter < 3584) { //dim B (16-23) for( p = 16 ; p < 24 ; p++) { leds[p]--; } } else if (loopCounter < 4096) { //dim R (0-7) for( p = 0 ; p < 8 ; p++) { leds[p]--; } } else { loopCounter = 0; } // do not edit below loopCounter++; // sleep _bis_SR_register(LPM0_bits); } } void updateTLC() { u_char ledCounter = NUMBER_OF_LEDS >> 1; while (ledCounter-- > 0) { u_char i = ledCounter << 1; sendMOSI(leds[i + 1]); sendMOSI(leds[i]); } } // the HSV algorithm void HSV2RGB(u_char *r, u_char *g, u_char *b, signed int h, u_char s, u_char v) { int i,z; float f, p, q, t, hf, sf, vf; hf=(float)h; sf=(float)s; vf=(float)v; sf /=255; if( sf == 0 ) { // achromatic (grey) *r = *g = *b = vf; return; } hf /= 60; // sector 0 to 5 i = floor( hf ); f = hf - i; // factorial part of h p = (u_char)(v * ( 1 - sf )); q = (u_char)(v * ( 1 - sf * f )); t = (u_char)(v * ( 1 - sf * ( 1 - f ) )); switch( i ) { case 0: *r = v; *g = t; *b = p; break; case 1: *r = q; *g = v; *b = p; break; case 2: *r = p; *g = v; *b = t; break; case 3: *r = p; *g = q; *b = v; break; case 4: *r = t; *g = p; *b = v; break; default: // case 5: *r = v; *g = p; *b = q; break; } for( z = 0 ; z < 8 ; z++) { leds[z] = *r; // red pins leds[z+8] = *g; // green pins leds[z+16] = *b; // blue pins } } void allcolsON(void) { for( icount = 0; icount < NUMBER_OF_COLUMNS ; icount++ ) { shiftOut(1 << icount); //1 << } for( icount = NUMBER_OF_COLUMNS-1; icount >= 0 ; icount-- ) { shiftOut(1 << icount); //1 << } } void allrowsON(void) { int x; for( x = 0; x < 8 ; x++ ) { leds[x] = 4095; } for( x = 7; x >= 0 ; x-- ) { leds[x] = 4095; } } void allrowsOFF(void) { int x; for( x = 0; x < 8 ; x++ ) { leds[x] = 0; } for( x = 7; x >= 0 ; x-- ) { leds[x] = 0; } } void delay(unsigned int ms) { while (ms--) { __delay_cycles(2000); // set for 16Mhz change it to 1000 for 1 Mhz } } void bounce (int time) { int a; allcolsON(); for( a = 0; a < 8 ; a++) // red { leds[a] = 4095; delay(time); leds[a] = 0; } for( a = 7 ; a >= 0 ; a--) { leds[a] = 4095; delay(time); leds[a] = 0; } for( a = 0; a < 8 ; a++) // yellow { leds[a] = 4095; leds[a+8] = 3500; delay(time); leds[a] = 0; leds[a+8] = 0; } for( a = 7 ; a >= 0 ; a--) { leds[a] = 4095; leds[a+8] = 3500; delay(time); leds[a] = 0; leds[a + 8] = 0; } for( a = 0; a < 8 ; a++) // green { leds[a+8] = 4095; delay(time); leds[a+8] = 0; } for( a = 7 ; a >= 0 ; a--) { leds[a+8] = 4095; delay(time); leds[a+8] = 0; } for( a = 0; a < 8 ; a++) // cyan { leds[a+8] = 4095; leds[a+16] = 4095; delay(time); leds[a+8] = 0; leds[a+16] = 0; } for( a = 7 ; a >= 0 ; a--) { leds[a+8] = 4095; leds[a+16] = 4095; delay(time); leds[a+8] = 0; leds[a+16] = 0; } for( a = 0; a < 8 ; a++) // blue { leds[a+16] = 4095; delay(time); leds[a+16] = 0; } for( a = 7 ; a >= 0 ; a--) { leds[a+16] = 4095; delay(time); leds[a+16] = 0; } for( a = 0; a < 8 ; a++) // magenta { leds[a] = 4095; leds[a+16] = 4095; delay(time); leds[a] = 0; leds[a+16] = 0; } for( a = 7 ; a >= 0 ; a--) { leds[a] = 4095; leds[a+16] = 4095; delay(time); leds[a] = 0; leds[a+16] = 0; } for( a = 0; a < 8 ; a++) // white { leds[a] = 4095; leds[a+8] = 4095; leds[a+16] = 4095; delay(time); leds[a] = 0; leds[a+8] = 0; leds[a+16] = 0; } for( a = 7 ; a >= 0 ; a--) { leds[a] = 4095; leds[a+8] =4095; leds[a+16] = 4095; delay(time); leds[a] = 0; leds[a+8] = 0; leds[a+16] = 0; } } void knight(int time) { int x; allrowsON(); for( x = 0 ; x < 8 ; x++) { shift(1 << x); delay(time); } for( x = 7 ; x >= 0 ; x--) { shift(1 << x); delay(time); } allrowsOFF(); } #pragma vector = TIMER0_A0_VECTOR __interrupt void Timer_A0(void) { setHigh(BLANK_PIN); pulse(XLAT_PIN); setLow(BLANK_PIN); timerCounter++; if (timerCounter == 8) { // 0x08 - 2ms * 8 = 16.384ms, ~61Hz updateTLC(); timerCounter = 0; _bic_SR_register_on_exit(LPM0_bits); } } void sendMOSI(u_int mosi) { u_char c = 0; while (c < 12) { (mosi & 0x0800) ? (P1OUT |= MOSI_PIN) : (P1OUT &= ~MOSI_PIN); pulse(SCLK_PIN); mosi <<= 1; c++; } } void shiftOut(unsigned char val) { P2OUT &= ~LATCH; pinWrite(DATA, val); pulseClock(); P2OUT |= LATCH; P2OUT &= ~LATCH; } void shift(unsigned int val) { P2OUT &= ~LATCH; int i; for (i = 0; i < 8; i++) { pinWrite(DATA, (val & (1 << i))); pulseClock(); } P2OUT |= LATCH; P2OUT &= ~LATCH; } void pinWrite( unsigned int bit, int val ) { if (val){ P1OUT |= bit; } else { P1OUT &= ~bit; } } // Pulse the clock pin void pulseClock( void ) { P2OUT |= CLOCK; P2OUT ^= CLOCK; } Quote Link to post Share on other sites
spirilis 1,265 Posted February 5, 2013 Share Posted February 5, 2013 G2231 (2K flash) is a bad choice of chip for this. Try a G2553 (16K flash) or maybe G2452 (8K flash). Sent from my C3PO via Tapatalk Rickta59 1 Quote Link to post Share on other sites
igor 163 Posted February 6, 2013 Share Posted February 6, 2013 Assume you tried telling compiler to optimize for code size. Since your problem is code size, one quick way to reduce size would be to combine the code for AllRowsOn and AllRowsOff (parameterize the function with the value to assign, then make AllRowsOn or Off be macros). I would also look at your main program - see what code the compiler generates for all those little loops. You might be able to make them into a function passing a few parameters (could see if that shrinks or expands code size). Similarly could look at bounce to see if can make into multiple calls to a function to reduce the amount of code. (Not sure whether extra code for generality/function preamble would mean net gain or loss.) -- Asside: Code is a bit confusing, why are you passing 0, 0, 0 in to first 3 arguments of HSV2RGB HSV2RGB(0,0,0,hue,1,1); code says those arguments are supposed to be pointers to unsigned characters. void HSV2RGB(u_char *r, u_char *g, u_char *b, signed int h, u_char s, u_char v) I don't know off hand what is stored at address 0 on the 430, but seems like poor style, even if that is available RAM. It also means that inside the call to HSV2RGB r = g = b (not clear why this is desired). Suggest create a variable and pass in the address. Also unclear why call HSV2RGB 360 times, since looks like effect would be the same if just called it the final time, or even just precomputed the final values (unless there is there some side effect of storing a value in location 0). Quote Link to post Share on other sites
roadrunner84 466 Posted February 6, 2013 Share Posted February 6, 2013 If this is your full code (what are you trying to do in bounce()?), you don't need a full-lfedged HSV2RGB function for( hue = 0 ; hue < 360 ; hue ++) // this is where the problem lies! { HSV2RGB(0,0,0,hue,1,1); } This is the only place you're using the HSV2RGB function, and as I can see here (apart from the fact that you'd need to provide variables in the first three arguments), you're not using the saturation and value parameters; they're always 1. So, what you actually "need" is a ranbow lookup table, which would take 360*3 bytes, assuming you'd store the full table. However, you can cut it in 6 symmetric hexants. uint8 HueLUT[60] = {...}; if (hue < 60) R = 255, G = HueLUT[hue], B = 0; else if (hue < 120) R = HueLUT[120 - hue], G = 255, B = 0; else if (hue < 180) R = 0, G = 255, B = HueLUT[hue - 120]; else if (hue < 240) R = 0, G = HueLUT[240 - hue], B = 255; else if (hue < 300) R = HueLUT[hue - 240], G = 0, B = 255; else if (hue < 300) R = 255, G = 0, B = HueLUT[300 - hue]; else // hue >= 360 R = 255, G = 255, B = 255; // white RobG 1 Quote Link to post Share on other sites
Gareeeesh 2 Posted February 6, 2013 Author Share Posted February 6, 2013 Thanks for your replys. @igor - The compiler is set to optimise for code size. I have removed bounce(), allrowsON() and allrowsOFF() from the code because they aren't really necessary at the moment, but it seems that the issue is primarily the HSV2RGB function. With respect to this: Code is a bit confusing, why are you passing 0, 0, 0 in to first 3 arguments of HSV2RGB Gareeeesh, on 05 Feb 2013 - 21:26, said: HSV2RGB(0,0,0,hue,1,1); code says those arguments are supposed to be pointers to unsigned characters. Gareeeesh, on 05 Feb 2013 - 21:26, said: void HSV2RGB(u_char *r, u_char *g, u_char *b, signed int h, u_char s, u_char v) I don't know off hand what is stored at address 0 on the 430, but seems like poor style, even if that is available RAM. It also means that inside the call to HSV2RGB r = g = b (not clear why this is desired). Suggest create a variable and pass in the address. I'll be honest, I'm not entirely sure about how to generate values for r,g and b for that function call, the 0's were there just as a test to see if the uC had enough memory for the floating point operations required - which it didn't. If you have any suggestions that'd be really appreciated . @roadrunner84 - bounce() was just a function I used to test the rows of my matrix, so it doesn't really matter that much just now. This is the only place you're using the HSV2RGB function, and as I can see here (apart from the fact that you'd need to provide variables in the first three arguments), you're not using the saturation and value parameters; they're always 1. The only reason that I used the values of 1 for value and saturation was just to see if the program would run. My end design will (hopefully) be able to interact ith a computer, similar to this - http://www.instructables.com/id/64-pixel-RGB-LED-Display-Another-Arduino-Clone/#intro - therefore it would be ideal to be able to represent all possible colours (or as close to as possible) and shades. I did think that the G2231 would not have enough memory for this kind of function so I had ordered a G2553 but I'm still waiting on its arrival. Thanks Quote Link to post Share on other sites
roadrunner84 466 Posted February 6, 2013 Share Posted February 6, 2013 If you're going to communicate with a computer, let the PC application convert HSV to RGB and send that to the microcontroller. Quote Link to post Share on other sites
RobG 1,892 Posted February 6, 2013 Share Posted February 6, 2013 Just FYI, here's something similar. Quote Link to post Share on other sites
Gareeeesh 2 Posted February 6, 2013 Author Share Posted February 6, 2013 If you're going to communicate with a computer, let the PC application convert HSV to RGB and send that to the microcontroller. @ Roadrunner84 - You make it sound so easy , I don't even know where to begin with that. Any ideas? Quote Link to post Share on other sites
roadrunner84 466 Posted February 6, 2013 Share Posted February 6, 2013 You mean you weren't planning on using a GUI frondend? Just a plain command line? Hmm, that might be a little more complex. You could (if you're using a command line annyway) make a command line application, just google on how to interface with a serial port from (for example) visual C++. The user interaction can be done using scanf() and printf(). Alternatively, use a website to convert a desired color form HSV to RGB and enter those values into your command line in Energia If you feed HSV or HSL to a microcontroller, the best you could get is the same depth resolution in RGB, you cannot enhance the abilities by moving the calculation to the microcontroller. Quote Link to post Share on other sites
roadrunner84 466 Posted February 6, 2013 Share Posted February 6, 2013 /* h = 0 - 359 s = 0 - 255 v = 0 - 255 */ void hsvToRgb(unsigned short* r, unsigned short* g, unsigned short* b, short h, unsigned char s, unsigned char v) { unsigned char i, p, q, t; float fs; if (h < 60) i = 0; else if (h < 120) i = 1; else if (h < 180) i = 2; else if (h < 240) i = 3; else if (h < 300) i = 4; else if (h < 360) i = 5; else return; fs = (h / 60.0 - i) * s; p = 255 - s; q = 255 - fs; t = 255 - s + fs; switch(i){ case 0: *r = 255, *g = t, *b = p; break; case 1: *r = q, *g = 255, *b = p; break; case 2: *r = p, *g = 255, *b = t; break; case 3: *r = p, *g = q, *b = 255; break; case 4: *r = t, *g = p, *b = 255; break; case 5: *r = 255, *g = p, *b = q; break; } *r *= v; *g *= v; *b *= v; } You see it takes way less floating points now? Even better, there is only one FP calculation! Alas, there are two input variables in it: fs = (h / 60.0 - i) * s, in this i is is derived from h and thus not an input. Would we want to make a lookup table off of this, it would be 60 * 255 cells (15K), so that's unacceptable. On the other hand, if we define h - i * 60 as h_rem, the formula would become fs = (h_rem / 60) * s or fs = (h_rem * s) / 60. So why is this nice? because we just reduced the "inputs" to a single value. With these changes, there are no floating point calculations left. there is still a division, which is quite expensive, but not as much as any floating point operation. /* h = 0 - 359 s = 0 - 255 v = 0 - 255 */ void hsvToRgb(unsigned short* r, unsigned short* g, unsigned short* b, short h, unsigned char s, unsigned char v) { unsigned char i, p, q, t; unsigned char fs; if (h < 60) i = 0; else if (h < 120) i = 1; else if (h < 180) i = 2; else if (h < 240) i = 3; else if (h < 300) i = 4; else if (h < 360) i = 5; else return; fs = ((h - i * 60) * s) / 60; p = 255 - s; q = 255 - fs; t = 255 - s + fs; switch(i){ case 0: *r = 255, *g = t, *b = p; break; case 1: *r = q, *g = 255, *b = p; break; case 2: *r = p, *g = 255, *b = t; break; case 3: *r = p, *g = q, *b = 255; break; case 4: *r = t, *g = p, *b = 255; break; case 5: *r = 255, *g = p, *b = q; break; } *r *= v; *g *= v; *b *= v; } Oh, note that the outputs are 16-bit integers, so in the range 0 - 65535. Gareeeesh 1 Quote Link to post Share on other sites
Gareeeesh 2 Posted February 6, 2013 Author Share Posted February 6, 2013 Right, so would i declare h,s and v as floats in the function call and prototype? like: //at top #include <math.h> . . void hsvToRgb(float h, float s, float v){ int r, g, b; int i = floor(h * 6); int f = h * 6 - i; int p = v * (1 - s); int q = v * (1 - f * s); int t = v * (1 - (1 - f) * s); switch(i % 6){ // ive not changed this bit yet case 0: r = v, g = t, b = p; break; case 1: r = q, g = v, b = p; break; case 2: r = p, g = v, b = t; break; case 3: r = p, g = q, b = v; break; case 4: r = t, g = p, b = v; break; case 5: r = v, g = p, b = q; break; } return (r * 255, g * 255, b * 255); } How else could h,s and v be between 0 and 1 if they are not floats? I apologise for my poor programming skills :-P Cheers Quote Link to post Share on other sites
roadrunner84 466 Posted February 6, 2013 Share Posted February 6, 2013 You don't want floats, so if you have anything in the range 0 to 1, try to rewrite it to be in any other range, for example: 0 - 100 (natural percentages) 0 - 256 (8-bit integer) 0 - 360 (natural degrees) 0 - 65536 (16-bit integer) etc. Quote Link to post Share on other sites
Gareeeesh 2 Posted February 6, 2013 Author Share Posted February 6, 2013 Thanks for clarifying that for me. I've included the code you provided and tried to create a test function call to first of see if the code will run, but I got about a thousand errors. I thought I could create a couple of loops to create the values for h (0-359),s(0-255) and v(0-255). short int hue; unsigned char sat, val; int z; for( z = 0 ; z < 8 ; z++) { for( hue = 0 ; hue < 360 ; hue++) { for( sat = 0 ; sat < 256 ; sat++) { for( val = 0; val < 256 ; val++) { HSV2RGB(leds[z],leds[z+8],leds[z+16],hue,sat,val); } } } } Something like that. I really appreciate the help you've given me so far! Quote Link to post Share on other sites
roadrunner84 466 Posted February 6, 2013 Share Posted February 6, 2013 I didn't test my code, it's "all from the head" coding I think your code is almost right, but you should supply it with pointers to the values to write in // this line HSV2RGB(leds[z],leds[z+8],leds[z+16],hue,sat,val); // should be like this HSV2RGB(&leds[z],&leds[z+8],&leds[z+16],hue,sat,val); Gareeeesh 1 Quote Link to post Share on other sites
Gareeeesh 2 Posted February 6, 2013 Author Share Posted February 6, 2013 See in the case statement when you are setting *r,*g and *b : switch(i){ case 0: *r = 255, *g = t, *b = p; break; case 1: *r = q, *g = 255, *b = p; break; case 2: *r = p, *g = 255, *b = t; break; case 3: *r = p, *g = q, *b = 255; break; case 4: *r = t, *g = p, *b = 255; break; case 5: *r = 255, *g = p, *b = q; break; } Would I not need to do a similar thing and put an ampersand in front of the "t" for example? Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.