ublo
bogdan's (micro)blog

bogdanel » wixel PM3 low power sleep mode (CC2511F32)

10:18 pm on Sep 22, 2012 | #more | tags:

don't know if you have any idea what this is, but i love the wixel. it's a CC2511F32 based device that works basically like every arduino except that it has a embed wireless transceiver. i got mine from watterott. the wixel is a nifty little device, good for connecting sensors to a PC, both wired and wireless. the problem for the wireless approach is that the device is power hungry 30mA is quite a lot for a battery powered app. but luckily, CC2511F32 is made by texas instruments that addressed this issue: it has a sleep mode in which it consumes less than 1uA.

here's a small code i've wrote to test this sleep mode, based on blink led. it blinks the led 10 times, then powers down and waits for a falling edge on P1_0 (remember to connect this pin with a resistor to 3V3 in order to make the device sleep, otherwise P1_0 is quite sensitive).

#include <wixel.h>
#include <usb.h>
#include <usb_com.h>
#include <stdio.h>

int32 CODE param_blink_period_ms = 500;
int32 CODE param_count = 20; // counting 20 changes of the red led state, then go to sleep
uint32 count = 0; // the actual counter

uint32 lastToggle = 0;

/* catch interrupts on P1INT					*/
ISR (P1INT, 0) {
	/* clearing the CPU interrupt registers			*/
	/* 1. first the general interrupt register, IRCON2	*/
	IRCON2 &= ~0x08;				// clear IRCON2.P1IF
	/* 2. followed by the P1 interrupt register, P1IFG	*/
	P1IFG &= ~0x01;					// clear P1IF0
	/* not related to the interrupt itself, but to the	*/
	/* sleep mode: clear SLEEP.MODE flag			*/
	SLEEP &= ~0x03;					// clear SLEEP.MODE
	/* disable interrupt only for P1_0			*/
	P1IEN &= ~0x01;					// clear P1_0IEN
	/* wait, disabling interrupts on P1 also 🙂		*/
	IEN2 &= ~0x10;					// clear IEN2.P1IE
	}

/* the function that puts the system to sleep			*/
/* i've chosen PM3 as i don't need a timer wake-up event	*/
void putToSleep () {
	/* make the P1_0 a input pin				*/
	P1DIR &= ~0x01;					// P1_0DIR = 0 -> input
	/* clear any interrupt flags. see above for details	*/
	IRCON2 &= ~0x08;				// clear IRCON2.P1IF
	P1IFG &= ~0x01;					// clear P1IF0
	/* set the interrupt enable flag on P1_0		*/
	P1IEN |= 0x01;					// P1_0IEN = 1;
	/* set the type of interrupt: 0=rising edge; 1=falling	*/
	PICTL &= ~0x02;					// PICTL.P1ICON = 0
	/* set the interrupt enable flag for the entire P1	*/
	IEN2 |= 0x10;					// IEN2.P1IE = 1;
	/* enable global interrupts				*/
	IEN0 |= 0x80;					// IEN0.EA = 1;
	/* the sleep mode i've chosen is PM3			*/
	SLEEP |= 0x03;					// SLEEP.MODE = PM3
	/* idling the CPU - required in the manual		*/
	if (SLEEP & 0x03) PCON |= 0x01;	// PCON.IDLE = 1;
	}

void updateLeds()
{
    usbShowStatusWithGreenLed();

    LED_YELLOW(0);

    if (getMs() - lastToggle >= param_blink_period_ms/2)
    {
        LED_RED(!LED_RED_STATE);
        lastToggle = getMs();
		/* the piece of code that counts and if the counter	*/
		/* hits the limit, puts the system to sleep		*/
		count++;
		if (count == param_count) {
			count = 0;
			/* here the blinking freezes, waiting for a	*/
			/* falling edge on P1_0				*/
			putToSleep();
			}
    }
}

void main()
{
    systemInit();
    usbInit();
	
    while(1)
    {
        boardService();
        updateLeds();
        usbComService();
    }
}