This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430G2553 PWM of RGB LED using 3 potentiometer

Other Parts Discussed in Thread: MSP430G2553

I am using a potentiometer to generate different colours in RGB led. The adc  reads the value from the 3 potentiometers and uses them for pwm in 3 pins. The problem is that the  adc retains its initial value and doesn't change on rotating the potentiometer knob. hence the intensity of light doesn't change. What is the problem in my code?

#include <msp430.h>
unsigned int pointer[2];
int jum;
volatile int redder,greener,bluer;
#define PIN_REDLED BIT6
#define PIN_GREENLED BIT4
#define PIN_BLUELED BIT2

//Hardware configuration
#define BLUEREG TA1CCR1
#define GREENREG TA1CCR2
#define REDREG TA0CCR1

void setBlueChannel(int value)
{
TA0R = 0;
BLUEREG = value;
}

void setGreenChannel(int value)
{
TA1R = 0;
GREENREG = value;
}

void setRedChannel(int value)
{
TA0R = 0;
REDREG = value;
}


int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
ADC10CTL1 = INCH_2 + CONSEQ_3; // A2/A1/A0, repeat multi channel
ADC10CTL0 = ADC10SHT_2 + MSC + ADC10ON + ADC10IE;
ADC10AE0 |= BIT0 + BIT1 + BIT2; // P1.1,2 ADC option select
ADC10DTC1 = 3; // 3 conversions

P2DIR |= PIN_GREENLED + PIN_BLUELED ;//output
P2SEL |= PIN_GREENLED + PIN_BLUELED; //TA 1.2 on P2.4 TA1.1 on P2.2
P2SEL2 = 0;

P1DIR |= PIN_REDLED; //Output
P1SEL |= PIN_REDLED; //TA 0.1 on p1.6

TA1CCR0 = 1023- 1;
TA1CCTL1 = OUTMOD_7;
TA1CCTL2 = OUTMOD_7;
// Set timer A0
TA0CCR0 = 1023 -1;
TA0CCTL1 = OUTMOD_7;

TA1CTL = TASSEL_2 + MC_1; // SMCLK, up mode
TA0CTL = TASSEL_2 + MC_1; // SMCLK, up mode tassel 01 is aclk good to test


for (;;)
{
ADC10CTL0 &= ~ENC;
while (ADC10CTL1 & BUSY); // Wait if ADC10 core is active
ADC10SA = (unsigned int)&pointer; // Data buffer start
ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion ready
setRedChannel(redder);
setGreenChannel( greener);
setBlueChannel( bluer);
__bis_SR_register(CPUOFF + GIE); // LPM0, ADC10_ISR will force exit
//_NOP(); // space for debugger
//_NOP(); // Set Breakpoint here to read ADC
}
}

// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR (void)
{ redder = pointer[0];
greener = pointer[1];
bluer = pointer[2];


//ADC10SA = (unsigned int)&TACCR1; // Data transfer location
__bic_SR_register_on_exit(CPUOFF); // Clear CPUOFF bit from 0(SR)
}

  • Hi Mridul,

    I'm looking into this and should have some feedback for you tomorrow.

    Regards,

    James
    MSP Customer Applications
  • could start wit this fix
    unsigned int pointer[2]; << reserves 2 ints, not 0,1 & 2

  • Hi Midrul!

    There is one code example available that samples three ADC channels:

    • msp430g2x33_adc10_10.c                     ADC10, ADC10, DTC Sample A3-01, AVcc, Single Sequence, DCO

    The code examples can be downloaded here.

    Dennis

  • Hi Mridul,

    First, thanks for providing your code - it helps tremendously and makes debugging easier.

    After digging into your code, I found a timer issue (setting TA0R to zero), not an ADC issue. As mentioned at the top of page 358 in the User's Guide, "it is recommended to stop the timer before modifying its operation (with exception of the interrupt enable, and interrupt flag) to avoid errant operating conditions". I just commented out that line of code. For now, I just commented out that line of code, since it's not crucial that the timer restarts before using the new TA0CCR1.

    Also, keep in mind that the ADC samples are stored in descending order with regard to their ADC channel number. For example, P1.2 (A2) -> pointer[0] and P1.1 (A1) -> pointer[1] and P1.0 (A0) -> pointer[2].

    I've modified your code (see below) to have three ADC inputs (A2, A1, A0), but only one LED output (P1.6). In the ADC ISR, I'm changing the LED duty-cycle based on channel A2. I checked this code on an MSP-EXP430G2 LaunchPad (removed J5 jumper for P1.0, since it's an input). When A2 is connected to a potentiometer, the green LED is bright near VCC and gets dimmer as the voltage decreases to GND where the LED is off.

    #include <msp430.h>
    
    unsigned int pointer[3];		// index = 0, 1, 2 (thanks for "pointing" this out, Tony)
    int jum;
    volatile int redder;
    #define PIN_REDLED BIT6
    
    //Hardware configuration
    #define REDREG TA0CCR1
    
    void setRedChannel(int value)
    {
    	//TA0R = 0;
    	REDREG = value;					// Duty-cycle
    }
    
    
    int main(void)
    {
    	WDTCTL = WDTPW + WDTHOLD; 			// Stop WDT
    	ADC10CTL1 = INCH_2 + CONSEQ_1; 		// A2/A1/A0, repeat multi channel
    	ADC10CTL0 = ADC10SHT_2 + MSC + ADC10ON + ADC10IE;
    	ADC10AE0 |= BIT0 + BIT1 + BIT2; 	// P1.0 (A0), P1.1 (A1), P1.2 (A2) ADC option select
    	ADC10DTC1 = 3; 						// 3 conversions
    
    	P1DIR |= PIN_REDLED; 				// Output
    	P1SEL |= PIN_REDLED; 				// TA 0.1 on P1.6
    
    	// Set timer A0
    	TA0CCR0 = 1024;						// Period (keep this larger than highest input 0x3FF, which is 1023)
    	TA0CCTL1 = OUTMOD_7;
    	TA0CTL = TASSEL_2 + MC_1; 			// SMCLK, up mode tassel 01 is aclk good to test
    
    	for (;;)
    	{
    		ADC10CTL0 &= ~ENC;
    		while (ADC10CTL1 & BUSY); 			// Wait if ADC10 core is active
    		ADC10SA = (unsigned int)&pointer; 	// Data buffer start, index starts at 0
    		ADC10CTL0 |= ENC + ADC10SC; 		// Sampling and conversion ready
    		setRedChannel(redder);				// Adjust LED brightness
    		__bis_SR_register(CPUOFF + GIE); 	// LPM0, ADC10_ISR will force exit
    	}
    }
    
    
    // ADC10 interrupt service routine
    #pragma vector=ADC10_VECTOR
    __interrupt void ADC10_ISR (void)
    {
    	redder = pointer[0];				// P1.2 (A2) ADC input
    	__bic_SR_register_on_exit(CPUOFF); 	// Clear CPUOFF bit from 0(SR)
    }
    

    Hope this helps!

    Regards,

    James

    MSP Customer Applications

  • Mridul Sharma, the one that started this thread, probably lost interest and went somewhere else.

    It would be much simpler to just connect a fixed resister and a variable resister in series with each GRB LED between power and ground. No MSP or uC is needed at all. The fixed resister is for max brightness when the variable resister is set at min. When the variable resistor is set at max, the total resistance determines the min brightness.

    If one has to use MSP430G2553 to do it the complicated way. I would do it as follows.

    I would connect the three potential meters between Vcc and Vss with the center tabs connected to P1.4, P1.5, and P1.7.

    I would connect two of the three GRB LEDs to P2.1/P2.2 and P2.4/P2.5.

    The above connections do not conflict with the existing connections on the G2PL board. But for the remaining GRB LED, I can only use either P1.2, P1.6, or P2.6 and either way there may be a conflict. If I use P1.2, it cannot be used for TXD and I have to remove the jumper for it on the G2LP board. If I use P1.6, It cannot be used for the Green LED on the G2LP board and I have to remove the jumper for that. If I use P2.6, it cannot be used for XIN and I cannot use watch crystal or input external ACLK.

    I would to use both TA0 and TA1 to generate the three PWM signals and one interrupt to coordinate the ADC and adjust the duty cycles.

    I would start TA0 and TA1 so that they count in sync in up-mode with the same CCR0 period setting. (This can be done.) And I would not need to nor want to stop them (even briefly) after that.

    I would use TA0CC2 to generate an interrupt at various phase of the PWM. The ISR will use a finite state machine to (a) start ADC conversion, (b) read the ADC result and map that into duty cycle, and (c) change the duty cycle of the PWM in a way that would not produce unexpected result.

    I can go in more details. But I do not think anybody would be interested.
  • Sorry for late reply...
    Thanks for the reply
    I am using msp430 in this instead of just a variable resistor because i am trying to build a game using 2 RGB leds where one of the led will generate a random colour (using software pwm) and you have to match the colour on the other rgb using the 3 potentiometers(normal pwm) . and once the player matches a piezo buzzer plays a tune.
  • You did not mansion this overall goal before. G2553 may not be able to do all this. You may run out of I/O pins and peripheral modules.

    Looks like you need 7 output pins with pwm and 3 analog input pins. How do allocate these I/O pins with a G2553?
  • As it will be to hard if you have 1000s of colors, maybe limited it to less than 1000.

    As human eye see shades of blue less, maybe use ccr0 for blue with only 3 choices: OUT0, 50%, OUT1

    Red and Green could get 4bit step resolution using ccr1 and ccr2

    so 16*16*3 = 768 colors

    Probably could just use a button for blue and not a potentiometer, as there is only 3 choices.
    Optional, could make green 5bit steps as human eye see shades of green better.

**Attention** This is a public forum