roadrunner84 466 Posted February 21, 2013 Share Posted February 21, 2013 So we have this IKEA toy kitchen (Duktig). There are two hotplates in it (LED lit plastic) which run from 6xAA cells. Within two weeks these cells are drained! So I fixed it With an MSP430, this is for a 14-pin value line, but it could run on a 20-pin value line, or even on an 8-pin value line (MSP430G22x0). It's really straighforward, except for the _BIC_SR_IRQ #include <msp430.h> #define P2MAP (BIT6 | BIT7) /* set to 0xFF for 20-pin device */ #define TOP_BUTTON BIT0 #define BOTTOM_BUTTON BIT1 #define TOP_PLATE BIT2 #define BOTTOM_PLATE BIT3 int main(void) { // Stop WDT WDTCTL = WDTPW | WDTHOLD; // Stop WDT BCSCTL1 = DIVA_3; // ACLK /= 8 BCSCTL2 = SELM_3 | SELS; // MCLK = VLO, SMCLK = VLO BCSCTL3 = LFXT1S_2; // LFXT1 = VLO // Set up I/O (buttons as interrupt, LEDs off) P2SEL = 0; // Set crystal I/O to GPIO P1REN = ~(TOP_PLATE | BOTTOM_PLATE); // All pin pull up/down, except ouputs P2REN = P2MAP; // Also on port 2 P1OUT = TOP_BUTTON | BOTTOM_BUTTON; // pull up button inputs P1DIR = ~(TOP_BUTTON | BOTTOM_BUTTON); // disable all input, except inputs P2DIR = P2MAP; // Also on port 2 P1IES = TOP_BUTTON | BOTTOM_BUTTON; // high->low transition P1IFG = 0; // clear interrupt flags P1IE = TOP_BUTTON | BOTTOM_BUTTON; // enable interrupts LPM4; } #pragma vector=PORT1_VECTOR __interrupt void PORT1_ISR(void) { IE1 &= ~ WDTIFG; // clear WDT interrupt flag WDTCTL = WDT_ARST_1000; // WDT on at ACLK/32k => ~22 sec // Toggle respective LED if (P1IFG & TOP_BUTTON) { P1IFG &= ~TOP_BUTTON; P1OUT ^= TOP_PLATE; } if (P1IFG & BOTTOM_BUTTON) { P1IFG &= ~BOTTOM_BUTTON; P1OUT ^= BOTTOM_PLATE; } // Leave LPM4 _BIC_SR_IRQ(OSCOFF); // Enable ACLK after ISR (LPM4 -> LPM3) } Nowhere are we limited to leave low power mode altogether. So instead of leaving low power (4) mode and entering LPM3 again from the main, I just alter the difference between LPM4 and LPM3 and so enable ACLK.When imported in Energia this compiles to 241 bytes. The idea is that when toggling a hotplate on or off, the timer will start (or restart). I used the WDT because it's easy; it will reset the chip for me. After the timeout occurs, main() is executed again and will put the chip in LPM4 again. SirPatrick and GG430 2 Quote Link to post Share on other sites
GG430 53 Posted February 21, 2013 Share Posted February 21, 2013 Cool, we have the same one Our kids accepted that the plates are not working after the 2nd charge :? I never checked what's inside (which is actually odd for me ;-)) Did you rip out the original stuff? Does that run on 3V? Aren't the 22secs a bit short? Just two minors on your code: I guess this should be BCSCTL2 = SELM_3 | SELS and there is a typo in the __interrupt Quote Link to post Share on other sites
roadrunner84 466 Posted February 21, 2013 Author Share Posted February 21, 2013 You're right, I fixed it. I haven't opened it yet, but I do know the LEDs are driven by all 6 cells, while the control logic taps in after only 2 cells (so 3 volts). Quote Link to post Share on other sites
GG430 53 Posted February 21, 2013 Share Posted February 21, 2013 This would have given me a hard time sleeping tonight. Kids are in bed, so I opend it up. I guess the PCB in there will be gone this weekend ;-) Thanks for posting this "nano project"! Quote Link to post Share on other sites
roadrunner84 466 Posted February 22, 2013 Author Share Posted February 22, 2013 I've opened mine up too. And pulled the PCB out to photograph the backside. Give me a few minutes to "reverse engineer" it. So far I noticed it's running from a 4MHz crystal and uses two transistors for LED driving. The only resistor type used is 1kOhm~1%. The buttons, batteries and LEDs are connected to the PCB using latching connectors. This could save Ikea a bunch of money if they just solder the stuff right on there! Quote Link to post Share on other sites
roadrunner84 466 Posted February 22, 2013 Author Share Posted February 22, 2013 Thanks to digikey for their drawing tool (singce I have no EDA at hand). This is the "guts" of the hotplates. The chip (the 14-pin header in the middle of this drawing) is designated "XH8815A", of which I find no information at all. So the switches use pull up. There is one weird capacitor between pin 7 of the chip and Vcc, maybe it's reset related, but I'm not sure (who knows?). It looks like the Vcc is at 6 volts, while Vdd is at 9 volts. I assumed the transistors are of the NPN type, since they have one pin connected to ground. This seems really straightforward and easy to replace. We're just out of luck with the pinning; all value line MSP430 have RST and TEST next to the power supply, so we'll need to alter the circuit to have a drop in replacement. The crystal is kind of useless for the MSP, since we have this great VLO available. bluehash and GG430 2 Quote Link to post Share on other sites
roadrunner84 466 Posted February 22, 2013 Author Share Posted February 22, 2013 Drop in ready A small side note: I used a resistor divider as power control (get 2.8-3.6V out of a 6V source). It's ugly and icky. If you decide to move the power tap back two notches (and get 3V instead of 6V) you can cut off R2, C2 and R3 from the right of the PCB. This is a flip chip design; the MSP430G2210 (the second cheapest MSP430) is upside down in the cavity in the middle. The arrow points to pin number 1. If anyone is interested in this, I can post the gerbers or the KiCad schematics if you want. In earlier code use this #define TOP_BUTTON BIT2 #define BOTTOM_BUTTON BIT5 #define TOP_PLATE BIT6 /*or is it BIT7?*/ #define BOTTOM_PLATE BIT7 /*or is it BIT6?*/ Quote Link to post Share on other sites
GG430 53 Posted February 22, 2013 Share Posted February 22, 2013 Awesome, that was fast! I was just looking at the schematic you posted earlier, there are just a couple of blue-wire changes and the original PCB should work with the 14pin.However I like seeing that you used the 8pin Since it Quote Link to post Share on other sites
GG430 53 Posted February 22, 2013 Share Posted February 22, 2013 I think I was too lazy to make a board today ;-) Just rewired the original board and used a MSP430F2011. I added a socket, so I could save the in circuit debug and just gave it a trial on the Launchpad. To get a reasonable VCC for the 430 I changed the tap to 2 cells. My code switches off the plates ~10Minutes after switching them on. I'll have the kids test it tomorrow ;-) This was really a great idea to put a 430 in there. I didn't think of it being that easy. Thanks! roadrunner84 1 Quote Link to post Share on other sites
roadrunner84 466 Posted February 22, 2013 Author Share Posted February 22, 2013 Nice fit, very quick too! I think the original behaviour was way less than 10 minutes, so you'll probably burn your batteries quite fast. I see you didn't alter the resistors around the transistors, did it illuminate just as well? I also see you skipped out on the capacitor on the reset pin, is that stable enough? Quote Link to post Share on other sites
GG430 53 Posted February 23, 2013 Share Posted February 23, 2013 It works perfekt, even though the LEDs seem much brighter now. Do you still have the original setup? I'd be curious if there was a PWM on the LEDs. Now I measured ~17mA per plate. Guess you are right on the time. I didn't know it switched off automatically before. I always thought the kids left it on all the time, that's why the batteries died so fast. Probably a minute would do just as good. At least the huge standby current of the original is gone The reset is OK in this minimalistic approach, if it would go to production I'd recommend to use it roadrunner84 1 Quote Link to post Share on other sites
roadrunner84 466 Posted February 23, 2013 Author Share Posted February 23, 2013 I would measure the signals coming out of the old chip if I'd have a scope lying around I also would like to measure current before opening up the thing, so I can do some benchmarking on how much better it has become. I might be able to do some measurements next friday... Did you use the code I provided, or did you modify it, or made your own? Since my current code does only allow for 22second timeout, I might change it into a software WDT and reset after X counts. Did you do button debouncing in software? I found this article on debouncing buttons, quite interesting. Quote Link to post Share on other sites
GG430 53 Posted February 23, 2013 Share Posted February 23, 2013 I got the XH8815A back working on a breadboard. It does PWM the LED outputs indeed. I measured the current and it's ~2mA @ 5V in idle and when the ports are on. :shock: Not a big surprise the batteries drained that quickly. :? I made a new code, it's below. The debounce is just a short loop after the ISR gets called. I'll change my code to have the PWM too. The LEDs are way too bright now and the current is also way too high. #include <msp430f2012.h> #define LED1 BIT4 #define LED2 BIT5 #define KEY1 BIT7 #define KEY2 BIT6 unsigned int time; #define Version 0x0100 #define VersionLocation 0x0FFFF-RESET_VECTOR-3 __root static const int x@VersionLocation = Version; int main(void) { WDTCTL = WDTPW + WDTHOLD; P1OUT = 0; P1DIR = BIT0+BIT1+BIT2+BIT3+LED1+LED2; P1IES = KEY1+KEY2; P1IFG = 0; P1IE = KEY1+KEY2; P2SEL = 0; P2REN = BIT6+BIT7; if(CALBC1_1MHZ != 0xFF) { BCSCTL1 = 0; BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; } BCSCTL3 |= LFXT1S_2; //VLO 2 ACLK IFG1 &= ~WDTIFG; IE1 |= WDTIE; __enable_interrupt(); while(1) { __low_power_mode_4(); } } /******************************************************************************/ // Interrupt Routines /******************************************************************************/ #pragma vector=WDT_VECTOR __interrupt void ISR_WDT(void) { IFG1 &= ~WDTIFG; // Clear WDT interrupt flag time++; if(time>=200) // Actual seconds is roughly time x 3 { time=0; _BIS_SR_IRQ(OSCOFF); WDTCTL = WDTPW + WDTHOLD; P1OUT &= ~(LED1+LED2); } } #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { for(unsigned int i=0;i<2;i++){for(unsigned int j=0;j<0xFFFF;j++){}} //Debounce if(P1IFG == KEY1) { P1OUT ^= LED1; } else { P1OUT ^= LED2; } P1IFG = 0; if(P1OUT == LED1 | LED2) { WDTCTL = WDTPW + WDTTMSEL + WDTCNTCL + WDTSSEL; // watchdog counter mode, ACLK, /32768 _BIC_SR_IRQ(OSCOFF); } } roadrunner84 1 Quote Link to post Share on other sites
roadrunner84 466 Posted February 23, 2013 Author Share Posted February 23, 2013 10.23ms sounds a lot like a 10 bit timer The 30% duty cycle sounds weird though. What's that magic you're preforming with Version location? It looks like some kind of bootloader thing. One comment though; you should set time to 0 when the port1 interrupt is serviced as well, otherwise turning a plate on, then off, wait 50 seconds, turn on would turn the plates off in less then 10 seconds. GG430 1 Quote Link to post Share on other sites
GG430 53 Posted February 23, 2013 Share Posted February 23, 2013 Think I got it, looks much better now, no sunglasses required any more when looking at the plates ;-) Good point with the time, I added it to the P1 ISR. Small drawback of the bit-banged PWM is that it gets interrupted when pushing the other button. But rewiring to the timer outputs is too much change on the original board, but might make sense if you do a new PCB. The VersionLocation is just a version marker I like to be placed one work above the interrupt vectors. I do it in all my codes. Once in a while it comes in handy when downloading the code from a unit later. That's a memory dump for example: FFD0 FFFF FFFF FFFF FFFF FFFF FFFF FFFF 0101FFE0 FFFF FFFF E4F8 FFFF FFFF FFFF FFFF FFFFFFF0 FFFF FFFF 64F9 FFFF FFFF FFFF FFFF 00F8 #include <msp430f2012.h> #define LED1 BIT4 #define LED2 BIT5 #define KEY1 BIT7 #define KEY2 BIT6 #define ON 1 #define OFF 0 unsigned char LEDstate1; unsigned char LEDstate2; unsigned int time; #define Version 0x0101 #define VersionLocation 0x0FFFF-RESET_VECTOR-3 __root static const int x@VersionLocation = Version; int main(void) { WDTCTL = WDTPW + WDTHOLD; P1OUT = 0; P1DIR = BIT0+BIT1+BIT2+BIT3+LED1+LED2; P1IES = KEY1+KEY2; P1IFG = 0; P1IE = KEY1+KEY2; P2SEL = 0; P2REN = BIT6+BIT7; if(CALBC1_1MHZ != 0xFF) { BCSCTL1 = 0; BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; } BCSCTL3 |= LFXT1S_2; //VLO 2 ACLK IFG1 &= ~WDTIFG; IE1 |= WDTIE; __enable_interrupt(); while(1) { __low_power_mode_4(); __no_operation(); while(1) { if(LEDstate1 == ON) { P1OUT |= LED1; } if(LEDstate2 == ON) { P1OUT |= LED2; } for(unsigned int j=0;j<0x250;j++){} if(LEDstate1 == ON) { P1OUT &= ~LED1; } if(LEDstate2 == ON) { P1OUT &= ~LED2; } for(unsigned int j=0;j<0x500;j++){} if((time>=100) || ((LEDstate1 == OFF) && (LEDstate2 == OFF))) // Actual seconds is roughly time x 3 { time=0; WDTCTL = WDTPW + WDTHOLD; LEDstate1 = OFF; LEDstate2 = OFF; P1OUT &= ~(LED1+LED2); break; } } } } /******************************************************************************/ // Interrupt Routines /******************************************************************************/ #pragma vector=WDT_VECTOR __interrupt void ISR_WDT(void) { IFG1 &= ~WDTIFG; // Clear WDT interrupt flag time++; } #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { for(unsigned int i=0;i<2;i++){for(unsigned int j=0;j<0xFFFF;j++){}} //Debounce if(P1IFG & KEY1) { LEDstate1 ^= 1; P1OUT &= ~LED1; } if(P1IFG & KEY2) { LEDstate2 ^= 1; P1OUT &= ~LED2; } P1IFG = 0; time=0; if(1 == LEDstate1 | LEDstate2) { WDTCTL = WDTPW + WDTTMSEL + WDTCNTCL + WDTSSEL; // watchdog counter mode, ACLK, /32768 _BIC_SR_IRQ(OSCOFF+CPUOFF+SCG1+SCG0); } } JK2308 1 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.