G120 Power Saving Tests 150mA to 24mA

G120 Power Tests

I really need a descent low power state for my application. I was hoping that the last Firmware drop would provide something useful, but alas no luck. In desperation I have been conducting some experiments to try and reduce the power to the as much as possible. I haven’t played with the hardware Deep Sleep modes yet as I was concerned that NETMF might not recover. So far my results seem promising, but I would still really like to get down to the microAmp sleep level.

WARNING:- Do not try any of this unless you are prepared to brick your module. I expect some of the changes here to interfere with various parts of NETMF and cause stability problems for your application. Also I advise putting a Thread.Sleep(5000); at the start of your code to make it easier to recover.

[em]Fresh firmware flash 4.2.11.0

Lets measure the idle current.[/em]
Current = 152mA

Now the current under load.

a = System.Math.Sin(1.1f);	//Infinite loop

Current = 161mA

Power.EthernetOscillatorEnable(false);

Current = 140mA //But seems to cause crash

[em]Scrub that. We can turn it off using the PCONP register anyway.
[/em]
Hibernate

[em]Lets See what hibernate does[/em]

Debug.Print("Hibernating");
Thread.Sleep(100);
Power.Hibernate(Power.WakeUpInterrupt.InterruptInputs);	  //Only mode that seems to work

Current = 106mA

Peripheral Control

[em]Note:- some of the changes below cause problems with debugging. You may need to press reset before you load your application. Other than that it seems totally reversible.

Lets see how much we can save by turning various peripherals off. Im going to do it in blocks to save time.

First lets create the PCONP register.[/em]

Register PCONP = new Register(0x400fc0c4);

[em]Default PCONP = 0xFFFEFFFF. In other words everything is on bar SPI Flash(PCSPIFI)
[/em]
Current = 152mA

[em]Now we will start turning some stuff off[/em]

PCONP.ClearBits(0x40000000);//Turn Off Ethernet
Current = 147mA

PCONP.ClearBits(0x00001000);//Turn Off ADC

Current = 147mA

PCONP.ClearBits(0x0Cf00000);//Turn Off PCI2S PCIC2 PCTIM3 PCTIM2 PCSSP0 PCSSP2

Current = 145mA

PCONP.ClearBits(0x000f0000);//Turn Off PCI2C1 PCQEI PCMCPWM PCSPIFI

Current = 143mA

PCONP.ClearBits(0x0000f000);//Turn Off PCGPIO PCCAN2 PCCAN1 PCADC
Current = 135mA

PCONP.ClearBits(0x00000700);//Turn Off not(PCEMC) PCSSP1 PCRTC PCUART4

Current = 133mA
[em]All these seem to cause problems with deploying unless a hard reset is pressed.[/em]

PCONP.ClearBits(0x000000E0);//Turn Off PCI2C0 PCPWM1 PCPWM0 NOT(PCUART1)

Current = 131mA

PCONP.ClearBits(0x00000004);//Turn Off NOT(PCUART0) PCTIM1 NOT(PCTIM0)    NOT(PCLCD)

Current = 131mA

[em]PC Timer 0 seems to be needed for G120 to run. It doesnt take less than a mA anyway. It later turns out that all the PCTIM seem important so dont turn them off.[/em]

[em]PCONP.ClearBits(0x00000001);//Turn Off PCLCD[/em]
Current = 121mA

[em]The LCD controller is a big power draw. According to the release notes for this update the LCD should be off anyway, but it doesnt appears so.
[/em]

[em]Turn off the last 2 UARTS[/em]

PCONP.ClearBits(0x03000000);//Turn Off PCUART3 PCUART2

Current = 119mA

PCONP.ClearBits(0x20000000);//Turn Off PCGPDMA

Current = 108mA

[em]Ok, with all that done lets try the hibernate function again.[/em]

Debug.Print("Hibernating");
Thread.Sleep(100);
Power.Hibernate(Power.WakeUpInterrupt.InterruptInputs);	  //Only mode that seems to work

Current = 59mA

CPU Clock etc

PCONP = 90C00F1E
Initial current = 111mA


Register PBOOST = new Register(0x400FC1B0);
PBOOST.ClearBits(3);//POWER BOOST OFF TOP CPU CLOCK 100MHz Saves a few mA

Current = 102mA

[em]Now try and underclock the G120 to 60MHz[/em]

Register PLL0CFG = new Register(0x400FC084);   //Default to 9 //MSEL=9,PSEL=0   
Debug.Print("PLL0CFG = " + PLL0CFG.Read().ToString());
PLL0CFG.Write(0x24);  //Set MSEL=4,M= 5,PSEL = 1(div by 2) CLK = 5*12/= 60MHz
            
Register PLL0FEED = new Register(0x400FC08C);//Need to write AA55 here to commit change
PLL0FEED.Write(0xAA);
PLL0FEED.Write(0x55);//Make it happen
Debug.Print("PLL0CFG = " + PLL0CFG.Read().ToString());

Current = 68mA


PLL0CFG.Write(0x23);  //Set MSEL=3,M=4,PSEL=1(div by 2) CLK=4*12/=48MHz

Current = 60mA

PLL0CFG.Write(0x60);  //Set MSEL=0,M= 1,PSEL=3(div by 8) CLK = 1*12/= 12MHz  

Current = 39mA

[em]Other CPU speed settings are as follows:-[/em]

PLL0CFG.Write(0x09);  //Set MSEL=6, M=5,PSEL = 0(div by 1) CLK = 10*12/= 120MHz 
PLL0CFG.Write(0x06);  //Set MSEL=6, M=7,PSEL = 0(div by 1) CLK = 7*12 = 84MHz
PLL0CFG.Write(0x25);  //Set MSEL=5, M=6,PSEL = 1(div by 2) CLK = 6*12/= 72MHz
PLL0CFG.Write(0x24);  //Set MSEL=4, M=5,PSEL = 1(div by 2) CLK = 5*12/= 60MHz
PLL0CFG.Write(0x23);  //Set MSEL=3, M=4,PSEL = 1(div by 2) CLK = 4*12/= 48MHz
PLL0CFG.Write(0x41);  //Set MSEL=1, M=2,PSEL = 2(div by 4) CLK = 2*12/= 24MHz     PLL0CFG.Write(0x60);  //Set MSEL=0, M=1,PSEL = 3(div by 8) CLK = 1*12/= 12MHz  

[em]Note:- I havent tried running any applications while running at these clock rates. I have noticed that it slows down the Thres.Sleep() timer. I assume this converts milliseconds into CPU ticks internally.

Now hibernating while at 12MHz[/em]
Current = 24mA

[em]I have also tested recovering from this low power mode and getting back to the full power state. Obviously you need the GPIO enabled to give you an interrupt to get out of hibernate. This seems to work reliably. [/em]

PLL0CFG.Write(0x09);  //Set MSEL = 6, M = 5,PSEL = 0(div by 1) CLK = 10*12/= 120MHz  PLL0FEED.Write(0xAA);
PLL0FEED.Write(0x55);//Make it happen
PCONP.Write(0xFFFEFFFF);//Back to normal
5 Likes

Glad to see you are digging right into the CPU registers. What you are doing is fine and will not brick your module.

We still need to look into power modes on our end but with register access you can do some magic, like you just did.

Thanks for sharing this.

Much of the details are beyond me, but you’ve explained concepts very well!

It’s pretty simple. All the registers are documented in the NXP User Manual (Google UM10470).

Start by turning off the peripherals that you are not going to use. E.g if your application doesn’t use the SD card turn it off.

Some things can cause problems. E.g don’t turn of the External Memory Controller as that is definitely used by the system. Also the Timers seem to cause issues and don’t really consume much power anyway.

Some things I’m not sure about yet, such as the Direct Memory Access Register(PCGPDMA). This can be used to pipe data directly from peripherals to the memory without using up CPU cycles. Personally I doubt it’s implemented in NETMF.

That depends on implementation. I have seen certain solutions in Porting Kit use DMA.

You can find details of the peripheral power consumption here http://www.nxp.com/documents/data_sheet/LPC178X_7X.pdf on page 77. This lines up pretty well with my measurements.

I have also been testing some additional low power modes. The best success I have had is by activating SLEEPDEEP before hibernate.


            Register SCR = new Register(0xe000ed10);
            Register PCON = new Register(0x400fC0C0);  //Power Mode Control Register
            //Clear Flags So we can see what happened when we wake
            PCON.Write(0x00000100);//Clear SMFLAG
            PCON.Write(0x00000200);//Clear DSFLAG
            PCON.Write(0x00000400);//Clear PDFLAG

            SCR.SetBits(0x00000004); //SET DEEP SLEEP MODE  
            Thread.Sleep(100);

            Power.Hibernate(Power.WakeUpInterrupt.InterruptInputs);

            Thread.Sleep(1000);
            uint PCONval = PCON.Read();//Store it as we need to reconnect via MFDEPLOY to see debug

            while (true)
            {
                Thread.Sleep(1000);
                Debug.Print("PCON REG after hibernate = " + PCONval.ToString("X8"));  //Defaults to 0x00000100 =  SMFLAG=1//Should = 0x200 if SLEEPDEEP worked
            }

This lowers the Hibernate current to about 14mA. I’m not sure what the remaining power is as it should be about 550uA. I am guessing the DRAM is taking some power to keep refreshed.


Register SCR = new Register(0xe000ed10);
Register PCON = new Register(0x400fC0C0);  //Power Mode Control Register

Are these register locations set in stone? Meaning, does the GHI firmware change the address at all?

For example there are Ethernet/Non-Ethernet versions of the Cerb firmware.

I would imagine that the registers live at level below the firmware.

Thanks for sharing,
It would be great if you can create a class once you feel your code is in beta phase so we can all try it and report any issues :slight_smile:

Yes, they are hard-wired into the chip. On later firmware I imagine that these settings will be overridden when you call hibernate.

You can all try it now if you like. Make sure you start your code with a sleep(5000) and you shouldn’t have to reflash the firmware too often.

I will report back once i’ve integrated some of this into my application and proved it is stable is, but i doubt i’ll get time to make a nice class for it that others can tailor to their own specific needs.

Any news or updates on the stability of this?

thanks for sharing…
Jay.

Not yet sorry. I’ve been working on my PCB and various other projects. I haven’t had time to get much further on the software side yet. I’m half hoping ghi will sort out some official low power modes before I get to it.

Low power and hibernate are essential for what I’m doing so I will get back to it.

great to know thanks…

In my first tests I have discovered that the UART causes errors when the CPU is underclocked. Works fine with Boost turned off.

I’ll do some more investigating of potential fixes. Need to try hardware handshaking and look at where the UART gets it’s clock from. I might just need to fake an adjusted baud rate.

Update

I now have the under-clocking working fairly reliably. The correct way to do this is to switch the CPU clock over to the internal RC oscillator before messing with the PLL and switching back once it’s locked. I was unable to do this through the managed code so ended up writing an RLP routine to do it for me.

The UART issue I was having seems to be easily solved by just changing the baud rate e.g. for 9600 baud when clocked at 60MHz I set the baud rate to 19200.

fakeBaud = TrueBaud * 120 / Freq

I will post the RLP and a wrapper class including some peripheral power control once it’s cleaned up a bit.

5 Likes

Great. Looking forward.

https://www.ghielectronics.com/community/codeshare/entry/876

2 Likes

@ hagster -

Thank you too much!
Your way is applied, and RTC Alarm is also added (G120)

Just wondering why I don’t see UART problem, even whenI don’t need to switch to internal RC oscillator? :think:

1 Like

@ Dat - Can you elaborate on that? What exactly was done and how should we access these features?

1 Like

@ Dat - are you saying you have the RTC alarm working? Care to share how?

Presuming you are changing the PLL clock rate, the UART is not really a problem as long as you scale the baud rate appropriately. E.g for 9600 baud at 60MHz set it to 19200.

Glad you find it useful.

[quote=“iamin”]@ Dat - Can you elaborate on that? What exactly was done and how should we access these features?
[/quote]

  • power consumption is reduced in hibernation mode.
  • RTC Alarm is added

Next release, you can use these features

2 Likes