cubeberg 540 Posted December 1, 2014 Share Posted December 1, 2014 So last year I made a Christmas Ornament - figured I'd do something again this year. It's an MSP430 powered Christmas tree! It uses 2 PCBs that slide together. There is a button and a motion sensor (cheap spring-based motion sensor). It uses 12 leds - broken into two sets of 6 that are charlieplexed (so 6 pins total used). I managed to score some cheap MSP430G2152's off of Newark for $0.50 each (although the $5 shipping cut into it a bit), but the 10 trees cost well over $100 in total (including $25 shipping to get them here before Christmas). For those interested, gerbers and eagle files are attached. I'll post some code as well - it's just very basic right now. Quick video (might put up a nicer one later) It turned out so great - I actually got my wife to solder one! tree_v1_part2.zip tree_batt_v1.zip christmas pcb eagle.zip dubnet, RobG, PTB and 2 others 5 Quote Link to post Share on other sites
cubeberg 540 Posted December 1, 2014 Author Share Posted December 1, 2014 And my code so far: #include <msp430.h> /* * main.c */ void setLED(char led); int main(void) { WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer //reset all pin config P1DIR = 0x00; P1OUT = 0x00; P1IE = 0x00; P2DIR = 0x00; P2SEL2 = 0x00; P2SEL = 0x00; //Clock setup BCSCTL2 = SELM_0 | DIVM_0 | DIVS_0; if (CALBC1_1MHZ != 0xFF) { /* Follow recommended flow. First, clear all DCOx and MODx bits. Then * apply new RSELx values. Finally, apply new DCOx and MODx bit values. */ DCOCTL = 0x00; BCSCTL1 = CALBC1_1MHZ; /* Set DCO to 1MHz */ DCOCTL = CALDCO_1MHZ; } BCSCTL1 |= XT2OFF | DIVA_0; BCSCTL3 = XT2S_0 | LFXT1S_2 | XCAP_1; //set up timer @ 250ms interval /* * TA0CCTL0, Capture/Compare Control Register 0 * * CM_0 -- No Capture * CCIS_0 -- CCIxA * ~SCS -- Asynchronous Capture * ~SCCI -- Latched capture signal (read) * ~CAP -- Compare mode * OUTMOD_0 -- PWM output mode: 0 - OUT bit value * * Note: ~<BIT> indicates that <BIT> has value zero */ TA0CCTL0 = CM_0 | CCIS_0 | OUTMOD_0 | CCIE; /* TA0CCR0, Timer_A Capture/Compare Register 0 */ TA0CCR0 = 2999; /* * TA0CTL, Timer_A3 Control Register * * TASSEL_1 -- ACLK * ID_0 -- Divider - /1 * MC_1 -- Up Mode */ TA0CTL = TASSEL_1 | ID_0 | MC_1; //configure pin for motion interrupt P1IE |= BIT7; P1IES |= BIT7; //high to low P1REN |= BIT7; P1OUT |= BIT7; //pull-up P1IFG = 0x00;; //enable interrupts __bis_SR_register(GIE); while(1) { LPM3; //ACLK remains active - only one we're using } } void setLED(char led) { //set led pins all in high-z (input) P1DIR &= ~(0x7F); //set all as low so that we only have to set high pins P1OUT &= ~(0x7F); switch(led) { case 0: //1.0 in, 1.1 out P1OUT |= BIT1; P1DIR |= BIT0|BIT1; break; case 1: P1OUT |= BIT2; P1DIR |= BIT1|BIT2; break; case 2: P1OUT |= BIT0; P1DIR |= BIT0 | BIT1; break; case 3: P1OUT |= BIT1; P1DIR |= BIT1|BIT2; break; case 4: P1OUT |= BIT2; P1DIR |= BIT2|BIT0; break; case 5: P1OUT |= BIT0; P1DIR |= BIT0|BIT2; break; case 6: P1OUT |= BIT4; P1DIR |= BIT3|BIT4; break; case 7: P1OUT |= BIT5; P1DIR |= BIT4|BIT5; break; case 8: P1OUT |= BIT3; P1DIR |= BIT3|BIT4; break; case 9: P1OUT |= BIT4; P1DIR |= BIT4|BIT5; break; case 10: P1OUT |= BIT5; P1DIR |= BIT3|BIT5; break; case 11: P1OUT |= BIT3; P1DIR |= BIT3|BIT5; break; case 12: P1OUT |= BIT6; P1DIR |= BIT6; break; } } volatile char i, rounds; /* * ======== Timer0_A3 Interrupt Service Routine ======== */ #pragma vector=TIMER0_A0_VECTOR __interrupt void TIMER0_A0_ISR_HOOK(void) { //static char i, rounds; if(rounds <= 4) { setLED(i); i++; } if(i > 12) { i = 0; rounds++; if(rounds > 4) { //rounds = 0; setLED(13);//turns all off //LPM4; //drop into low power until something happens } } //once we implement fuller code - enter LPM4 to disable this timer } // Port 1 interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { P1IFG = 0x00; rounds = 0; //LPM4_EXIT; //wake CPU which will drop us into lpm3 } Quote Link to post Share on other sites
roadrunner84 466 Posted December 1, 2014 Share Posted December 1, 2014 As you have only 2 * 6 + 1 LED, you could use charlieplexing to drive all LEDs. A mere 5 output pins would be enough, or 4 not counting the separate LED (power it from the battery?). You could then use a MSP430g2230 in SOIC8 housing Quote Link to post Share on other sites
cubeberg 540 Posted December 1, 2014 Author Share Posted December 1, 2014 @@roadrunner84 - It's my first time doing charlieplexing - I read that for LEDs with different voltage drops, it was necessary to separate them into different arrays - part of the reason why I broke them out. However - I used the same value resistors all around, so I'm not sure if it would have made a difference or if it was necessary. If I do these next year though - I may go with a smaller pin count because of chip price. We'll see roadrunner84 1 Quote Link to post Share on other sites
roadrunner84 466 Posted December 2, 2014 Share Posted December 2, 2014 @cubeberg: There are several solutions to go around the energy disparity problem. One is to use different resistor values for the red and green LEDs. Another option is to allocate more time to the green LEDs as to the red ones. Quote Link to post Share on other sites
cubeberg 540 Posted December 2, 2014 Author Share Posted December 2, 2014 Thanks @@roadrunner84 - I'll have to try that out next time. BTW - I ran into an odd issue that I'm going to have to do some more testing on. Shouldn't pin interrupts be available on LPM4? I need to do some testing, but once I dropped into LPM4, my PORT1_VECTOR never seemed to fire... Quote Link to post Share on other sites
roadrunner84 466 Posted December 2, 2014 Share Posted December 2, 2014 Yes, LPM4 should allow for any interrupt that does not require an internal clock source (so in theory even timers could fire, given that they use a separate external clock). Make sure to NOT enter any LPM when inside an ISR, your interrupt vector will go haywire, since the GIE is disabled when entering the ISR. Quote Link to post Share on other sites
cubeberg 540 Posted December 2, 2014 Author Share Posted December 2, 2014 Yes, LPM4 should allow for any interrupt that does not require an internal clock source (so in theory even timers could fire, given that they use a separate external clock). Make sure to NOT enter any LPM when inside an ISR, your interrupt vector will go haywire, since the GIE is disabled when entering the ISR. Ah! That's my problem. I was trying to change power states on interrupt. I believe there are some ON_EXIT options available if I remember correctly. I'll have to take a look at that or wake to change states. Quote Link to post Share on other sites
spirilis 1,265 Posted December 2, 2014 Share Posted December 2, 2014 the __bic_SR_register_on_exit() intrinsic should work, but if you are trying to bump LPM4 down to LPM3 then you need to only clear whatever bits differ between LPM4 and LPM3 ... probably OSCOFF I think. 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.