Using: MSP430F5308 (48QFP)
I stripped down my program to a simple bootup (setting core voltage and 20MHz oscillator, etc) and then an infinite while loop which toggles p6.0 high for 10ms and then low for 10ms.
Note: P6.0 is disconnected (I desoldered the pin off the PCB and bent it up).
During the high state current consumption is 5.58mA for 10ms (20MHz crystal) and during the low state its 4.70mA (thats 0.88mA).
Can someone verify if they get the same thing with a similar controller ?
I've tried 3 different chips (same kind), and they all do the same thing..
Other disconnected pins also consume current when high (logic high).
Am I missing something here ? are they suppose to consume this much when driven high ?
Thanks ...
I decided to use the sample code provided by TI : MSP430F530x_UCS_10.c, with very little modification, seen below:I'm using a 20MHz XTAL instead, however, I decided to keep the core voltage at level 3 --> SetVcoreUp (0x03)
================================================================
This code consumes a fairly steady 7.20mA average (min: 7.18mA 7.22mA max) while(1) { P6OUT ^= BIT0; // Toggle P6.0 __delay_cycles(200000); // Delay 10ms (20MHz XTAL) }
However! this code consumes a much more varying current swing ???
During high state =7.48mA, during low state = 5.76 ( average of two states 6.67mA)
while(1) { P6OUT |=BIT0; __delay_cycles(200000); // 10ms P6OUT &=~BIT0; __delay_cycles(200000); }
Anyone have any idea why this is happening ?
(by the way, P6.0 remains disconnected from any circuit)
I give up...
I have changed the program to an infinite while loop with nothing in it === while(1) { } === just to measure CPU current draw. At 20MHz XTAL current draw is ~5.26mA, which is fairly close to the maximum listed value in the datasheet 5.06mA (perhaps other things are turned on be default).
Toggling a port at low speed 10ms software PWM will vary the power consumption by ~1.0mA above and below the average listed number, which is very strange.
Originally, I thought toggling output ports should not have a "major" effect on power (assuming no load), but the truth is it does, and it depends on the state of the port (High or Low, again assuming no load).
rfengrNote: P6.0 is disconnected (I desoldered the pin off the PCB and bent it up).
So by toggling the pin high and low, you're charging and discharging the parasitic pin capacitance, and also the gate capacitances of the port pins internal driving circuit.
In case of P6.0 of this MSP, there's also the analog input for ADC10 and COMPB, which also add to capacitance, even if the switches are not closed.
Besides this, i don't know your code. maybe there are other factors which also add to the current consumption, unnoticed by you.
_____________________________________Before posting bug reports or ask for help, do at least quick scan over this article. It applies to any kind of problem reporting. On any forum. And/or look here.If you cannot discuss your problem in the public, feel free to start a private conversation: click on my name and then 'start conversation'. But please do so only if you really cannot do it in a public thread, as I usually read all threads. And I prefer to answer where others can profit from it (or contribute to it) too.
Jens-Michael, thank you for your reply and interest..
I wish you were right, but I simply don't think that the internal capacitance would consume steady-DC current (I would understand if it was a minor peak).
I wish I could have figured it out, but after about a day and a half ... I gave up, and accepted the current increase :(
Please see current consumption measurement below:
This is the corresponding code (slightly modified from sample code "MSP430F530x_UCS_10.c"):
===================================================================
#include <msp430f5308.h>void SetVcoreUp (unsigned int level);void main(void){ volatile unsigned int i; WDTCTL = WDTPW+WDTHOLD; // Stop WDT // Increase Vcore setting to level3 to support fsystem=25MHz // NOTE: Change core voltage one level at a time.. SetVcoreUp (0x01); SetVcoreUp (0x02); SetVcoreUp (0x03); UCSCTL3 = SELREF_2; // Set DCO FLL reference = REFO UCSCTL4 |= SELA_2; // Set ACLK = REFO __bis_SR_register(SCG0); // Disable the FLL control loop UCSCTL0 = 0x0000; // Set lowest possible DCOx, MODx UCSCTL1 = DCORSEL_7; // Select DCO range 50MHz operation UCSCTL2 = FLLD_1 + 762; // Set DCO Multiplier for 25MHz // (N + 1) * FLLRef = Fdco // (762 + 1) * 32768 = 25MHz // Set FLL Div = fDCOCLK/2 __bic_SR_register(SCG0); // Enable the FLL control loop // Worst-case settling time for the DCO when the DCO range bits have been // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx // UG for optimization. // 32 x 32 x 25 MHz / 32,768 Hz ~ 780k MCLK cycles for DCO to settle __delay_cycles(782000); // Loop until XT1,XT2 & DCO stabilizes - In this case only DCO has to stabilize do { UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); // Clear XT2,XT1,DCO fault flags SFRIFG1 &= ~OFIFG; // Clear fault flags }while (SFRIFG1&OFIFG); // Test oscillator fault flag P6DIR |= BIT0; while(1) { P6OUT |= BIT0; // Toggle P6.0 __delay_cycles(600000); // Delay P6OUT &= ~BIT0; __delay_cycles(600000); // Delay }}void SetVcoreUp (unsigned int level){ // Open PMM registers for write PMMCTL0_H = PMMPW_H; // Set SVS/SVM high side new level SVSMHCTL = SVSHE + SVSHRVL0 * level + SVMHE + SVSMHRRL0 * level; // Set SVM low side to new level SVSMLCTL = SVSLE + SVMLE + SVSMLRRL0 * level; // Wait till SVM is settled while ((PMMIFG & SVSMLDLYIFG) == 0); // Clear already set flags PMMIFG &= ~(SVMLVLRIFG + SVMLIFG); // Set VCore to new level PMMCTL0_L = PMMCOREV0 * level; // Wait till new level reached if ((PMMIFG & SVMLIFG)) while ((PMMIFG & SVMLVLRIFG) == 0); // Set SVS/SVM low side to new level SVSMLCTL = SVSLE + SVSLRVL0 * level + SVMLE + SVSMLRRL0 * level; // Lock PMM registers for write access PMMCTL0_H = 0x00;}
here is a current measurement that just increments a variable in the while loop instead (notice how its steady):
//P6DIR |= BIT0; // leave as default while(1) { //P6OUT |= BIT0; // Toggle P6.0 //__delay_cycles(600000); // Delay //P6OUT &= ~BIT0; //__delay_cycles(600000); // Delay j++; }
here is a current measurement that sets p6.0 high before entering the previous loop (no p6.0 toggles here!):
__delay_cycles(2400000); //delay ~100ms to be able to notice on current graph P6DIR |= BIT0; P6OUT |= BIT0; while(1) { //P6OUT |= BIT0; // Toggle P6.0 //__delay_cycles(600000); // Delay //P6OUT &= ~BIT0; //__delay_cycles(600000); // Delay j++; }
here is the assembly code for the code above:
I hope this will help you ... in order to help me
Thanks again ... awaiting your input...
I figured out half the problem, but its not pretty ...
The increase in current draw ~0.8-1.0 mA is not due to port toggling. Two empty for-loops also produces a train-like pattern in current draw:
while(1) { for(j=0;j<60000;j++) { } for(j=0;j<60000;j++) { } }
The assembly code is given below:
I hope you can make sense of this Jens-Michael !
My idea with the parasitic current was because you wrote you toggle the pin. However, I didn't see that it was a 10ms period, which is only 100Hz and not in the MHz range of a constant toggle.
About your demo code, well, I have an idea.
The 5x family has 32bit flash. There is a 32bit cache on flash reads. if your loop code is DWORD aligned, it has one flash read less per loop then when it is not.
Loop1:C072C074/C076C078/C07A (prefetch)3*32 bit access per loop
Loop 2C07C/C07EC080/C082C084/C086 (with prefetch)3*32 bit access per loop.
Well, good idea, but proven wrong. :(It would only make sense if the cache were 16 bytes large and not 4 bytes (as the second loop goe across a 16 byte border)
The only thing I see is that the second loop has a conditional and an unconditional jump, the first only one conditional jump. (the unconditional is before the loop)So the second loop is slower (as you can see in the diagram) but also uses one additional operation, the unconditional jump. It is possible that this instruction requires significantly more current than than the compare and increment instructions. Which sounds logical because anything that deals with the PC requires additional logic. It breaks the prefetch mechanism etc.I didn't expect ti to be that much, but the fact that different instructions require different current is as old as computers are. On the old C64, you could 'hear' what code was executing by listening to the current-ripple-induced sdistortions in the audio output. In fact, it was clearly audible if a basic program was in a 'press any key' loop, in a calculation loop or in straight code.I'm pretty sure you can figure out a specific 'charge' required for the execution of a certain instruction. And in theory, by measuring the current consumption you might be able to do a rough analysis of the executed program. In theory :)
However, I didn't expect the effect to be that large.This leaves space for some nice experiments (on assembly-level)
Yeah, I had the same exact thought about figuring out MCU executions based on current consumption patterns or signatures, but its a wild idea that can potentially have a huge error margin.
I still can't believe the huge difference in current draw...
I wish someone from TI can comment on this or even try it in lab ? (It still doesn't make much sense to me)
Thanks so much Jens-Michael ... You always have the heart and mind to help others. I appreciate that.
rfengrI still can't believe the huge difference in current draw...
rfengrYou always have the heart and mind to help others.
So thank you for this nice riddle. And I'd like to see an 'official' comment too.I think we got it, but the result is so surprising...
This is just a wild guess, but since the second for loop has two jumps close to each other (separated only by a single word), maybe it would result in extra work for the prefetcher since it has to "flush" and "fill" the buffer twice? Yes I know it sounds crazy, "cache" misses on MSP430...
The theory can be verified if the same code is run in SRAM instead, and the power consumption differential between the two for loops is less than that when running from flash, since a "flush and fill" with flash would be much more power intensive.
Again just idle speculation. :)
Tony
If you guys give me a code snippet, I'll be happy to try it out and post the corresponding current consumption pattern ...
Try this one on for size (although JMG likely won't approve of my abuse of function pointers ;) :
//#define TEST_IN_RAM //#define TEST_IN_FLASH typedef void (*pointer_to_func)(); unsigned int ram_test[] = { 0x430a, 0x3c01, 0x531a, 0x903a, 0xea60, 0x2bfc, 0x430a, 0x903a, 0xea60, 0x2ff6, 0x531a, 0x3ffb, 0x4303 }; const unsigned int flash_test[] = { 0x430a, 0x3c01, 0x531a, 0x903a, 0xea60, 0x2bfc, 0x430a, 0x903a, 0xea60, 0x2ff6, 0x531a, 0x3ffb, 0x4303 }; int main(void) { #if defined(TEST_IN_RAM) && !defined(TEST_IN_FLASH) ((pointer_to_func)ram_test)(); #elif defined(TEST_IN_FLASH) && !defined(TEST_IN_RAM) ((pointer_to_func)flash_test)(); #else #error "Uncomment one of TEST_IN_RAM or TEST_IN_FLASH" #endif }
Let me know what you find, or if it actually runs at all :)
Rfengr,I do not have a F5308. I suggest that you make a few modifications to the code you posted on Fri, May 4 2012 5:38 AM and measure the current again.(1) In your code, all port pins other than P1.0 are in the BOR default-state. If some of them are connected to analog signals, please set up those pins as analog input (but do not use them). If some of them are pulled up/down or driven by external circuits, it is okay to leave them as digital input. All others (this include floating pins and pins that are not actively pulling or driving by external circuits), please set up those pins as digital input with internal pull up/down.(2) Please make sure that XT1 and XT2 oscillators are not only not used, but also disabled and not oscillating.(3) Please disable FLL and use DCO to generate ACLK, MCLK and SMCLK at about 20 MHz.Regards,OCY
sorry, I wont be able to try anything for another 2 weeks due to a pressing deadline.
However, last thing I noticed is that the problem is instruction type dependent and frequency dependent. A lower frequency has a less severe current draw, but exhibits the same current pattern.
Old cow yellow, thank you for your input. I did try to put all other pins as output, and low, but with no noticeable difference.. I will try to set them as inputs next time.
I wish someone can try this at work or in lab, and see if they notice this "current pattern" effect ?
I have a sophisticated DAQ setup using Labview to measure current draw (has very high input impedance in the G-ohms), but you can do the same with an oscilloscope. I'm using a 10 ohm resistor in series with the power source (high side), use one of the oscilloscope probes in a differential mode across the resistor. A 1.0mA current draw will only vary the voltage source by 10mV (10ohm*1.0mA=10mV), so depending on your oscilloscope range, you might need to slightly scale your resistor value.
If someone can try this real quick, and let us all know what you get ??? ...it would be a great help to solve this mystery :(
Thank you all again ... will be back in 2 weeks ...