mbed Clock Control / Benchmarks

I wrote a few small functions to control the clock and PLL frequency, and I made a few discoveries along the way.

Update (1/26): Note that these tests are with the PHY on and an Ethernet cable plugged in. See http://mbed.org/users/no2chem/notebook/mbed-power-controlconsumption/ for more information on power draw by the PHY. Essentially, you can subtract about 76mA from the current readings.

I ported CoreMark (http://www.coremark.org) to the mbed LPC1768 and ran some tests. You can see the demonstration program here:

ClockControl

The demo app isn't certified as I made a wrapper to call CoreMark's main() from my main(). The tests below are run from a "certified" version of CoreMark, however. The code to read the clock speed comes verbatim from Simon Ford's post: http://mbed.org/forum/mbed/topic/229/?page=1#comment-1225

Benchmark

Method

As with the previous power control tests, I ran the mbed on an Agilent E3615A power supply at 5.0V (NB: Last calibration 2002). I realized this time, however, that the current reading from my DMM is more precise than the power supply (mA range), so current readings are off a Protek 6300 DMM (NB: NOT calibrated). The mbed was disconnected from USB during the power reading and the power supply was connected to VIN on the mbed. The reading was taken while the mbed was waiting for input via scanf (more precisely, the Run CoreMark (Y/N)? line.)

Results

 
Table 1. Performance and current draw at different frequencies. ERROR means that no performance reading could be made. M and N are multipliers and dividers for the PLL multiplier and divider, respectively.


Figure 1. Frequency vs CoreMark. A slope of 1.5849 CoreMarks per MHz was obtained. The data is completely linear.


Figure 2. Frequency vs Current. A slope of 0.4118 mA per MHz was obtained. The data is almost completely linear.

Discussion

It appears the LPC1768 part is quite capable of performing at the ~120 MHz range, so perhaps overclocking might be a better option than using the LPC1769 "120MHz" operation part. Then again, perhaps I got lucky with my LPC1768, or NXP might be selling the higher quality chips as 1769s. Operation above 128MHz caused sporadic errors, although I was able to get serial output, the timer function was severely broken.

Lowering the frequency to 48MHz will be beneficial to low power operation at a 11.39% power savings, and USB should be able to work directly off a 48MHz clock on PLL0. I didn't test any peripherals, so I can't attest to their operation, other than proper emission of serial output.

Overcloking to 128MHz resulted in a 33.35% performance increase, at a cost of 7.34% power. This might be beneficial for demanding operations, or intense bit-banging. Given the problems with operation at 132 and 133 MHz, stability will have to monitored.

Issues

I experienced problems with serial output after changing clock frequencies. I resolved that issue by calling the constructor of the serial function again after frequency change - Serial pc(USBTX, USBRX);. This probably reinitializes the UART to the new clock frequency. Other peripherals will probably have to be reinitialized too, so clock frequency changes are best done at startup.

The other issue was with the clock() function, which seemed to have major skew issues after clock frequency changes. I don't think there's a way to reset this function besides a hard reset, which you can call via NVIC_SystemReset(). Fortunately, the clock function doesn't start ticking until the first time you call it, so just call it AFTER you're done with all the frequency changes.

Library

Usage

It's not really a "library" a clock change function essentially taken out of CMSIS's init routine, and a wrapper for change the clock of the MCU. For M and N values, see table above as well as NXP's datasheet.

Functions

unsigned int setSystemFrequency(unsigned char clkDivider, unsigned char clkSrc, unsigned short M, unsigned char N); 

Sets the system clock frequency with the target parameters. Also updates SystemCoreClock value. Returns the current clock speed. (NB: don't printf the clockspeed without reinit of the serial - store the result in a variable, reinit the serial, then print the clock speed).

void setPLL0Frequency(unsigned char clkSrc, unsigned short M, unsigned char N);

Set the frequency of PLL0 with the target parameters.

void setPLL1Frequency(unsigned char clkSrc, unsigned short M, unsigned char N);

Set the frequency of PLL1 with the target parameters.


9 comments

24 Jan 2010

Try calling SystemCoreClockUpdate() after changing clock settings, that might help.

24 Jan 2010
Igor Skochinsky wrote:

Try calling SystemCoreClockUpdate() after changing clock settings, that might help.

I do call it in setSystemFrequency, still need to call Serial(USBTX,USBRX) to fix garbage though -individual peripherals probably just need to be reinit'd to the new clock speed.

24 Jan 2010

Hi Michael,

Great work!

Couple of comments:

  • The mbed Library for peripherals don't explicitly cope with the frequency changing on the fly; as you identified, you can reconstruct the peripherals (as they are calculated based on the clock frequency), but not ideal IMO. I've not really come up with the "right" way of doing this yet. It seem like the options are something like peripherals registering for a callback on a change (but not really compatible with the CMSIS setSystemFrequency() unless extended to know about this, or we require another function call), or them checking each time if the freq has changed (seems a bit of an overhead). So any ideas welcome! Some use cases would be good if people are seeing them.
  • The power you are measuring includes the regulators/mbed interface etc, so the 1768 MCU on it's own would be lower power; you could probably work out the approximate "+ C" overhead for this in your setup which might be interesting.

We've been avoiding fiddling with the mbed library to give people a chance to play and see where the concepts work (and don't work!), but I think we've got enough users now that we can look at a spec upgrade to add/fix concepts, so any thoughts on requirements around clocks etc would be great.

Simon

25 Jan 2010
Simon Ford wrote:

Hi Michael,

Great work!

Couple of comments:

  • The mbed Library for peripherals don't explicitly cope with the frequency changing on the fly; as you identified, you can reconstruct the peripherals (as they are calculated based on the clock frequency), but not ideal IMO. I've not really come up with the "right" way of doing this yet. It seem like the options are something like peripherals registering for a callback on a change (but not really compatible with the CMSIS setSystemFrequency() unless extended to know about this, or we require another function call), or them checking each time if the freq has changed (seems a bit of an overhead). So any ideas welcome! Some use cases would be good if people are seeing them.
  • The power you are measuring includes the regulators/mbed interface etc, so the 1768 MCU on it's own would be lower power; you could probably work out the approximate "+ C" overhead for this in your setup which might be interesting.

We've been avoiding fiddling with the mbed library to give people a chance to play and see where the concepts work (and don't work!), but I think we've got enough users now that we can look at a spec upgrade to add/fix concepts, so any thoughts on requirements around clocks etc would be great.

Simon

Hi Simon,

I think perhaps the best way is just have a "reinit" function for each device based on a clock, and force the user to manually call it if the clock is changed... any other way requires a bit of complicated overhead. The other thing is to have the clock change function cycle through PCONP to figure out which peripherals are ON, and reconfigure the clocks as necessary... Second method is more transparent, but a bit more work...

About the overhead, we're looking at ~120mA in deep power-off mode, and I'd expect the 1768 to be drawing power in the uA range here... So we have about 120 mA overhead to work with. Doesn't really change the above stuff though.. but take my suggestion on putting the mbed mcu and status light to sleep into consideration! =).

26 Jan 2010

Another option would be to maintain a table of the active peripherals, check and reinitialise any active peripherals that are clock dependant during the SystemCoreClockUpdate function.

26 Jan 2010

Andrew Harpin wrote:

Another option would be to maintain a table of the active peripherals, check and reinitialise any active peripherals that are clock dependant during the SystemCoreClockUpdate function.

Technically, PCONP maintains a table of all the active = 'powered on' peripherals, so we can just do that. The only thing you'd have to worry about are initialized peripherals that are powered off, but... I think since you have to call the destructor to power off a peripheral anyways, it shouldn't be a problem....

I'll look into adding this into the next version of the library... After I rewrite the Ethernet library... =).

26 Jan 2010

 

Michael Wei wrote:
After I rewrite the Ethernet library... =)

Interesting - you too... what do you plan to change? I'm curious since I was looking into some issues in it. My itch is 1) very long start time when unplugged (DHCP needs to timeout), and no way of non-DHCP fallback and 2) I still have very often dropouts, and think LWIP needs to be updated to the latest upstream version.

 

26 Jan 2010
Ilya I wrote:

 

Michael Wei wrote:
After I rewrite the Ethernet library... =)

Interesting - you too... what do you plan to change? I'm curious since I was looking into some issues in it. My itch is 1) very long start time when unplugged (DHCP needs to timeout), and no way of non-DHCP fallback and 2) I still have very often dropouts, and think LWIP needs to be updated to the latest upstream version.

 

Link LED, mainly, and DHCP takes forever, yes...

I made a new class, EthernetAdvanced that is a drop-in replacement for the Ethernet class.... looking at how the mbed ethernet class works though... the problem might stem from only being able to read one frame at a time, and having a second buffer involved, so we might be able to accelerate lwip a bit by giving it direct access to the buffer...

26 Jan 2010 . Edited: 26 Jan 2010

Michael,

I'm interested in your EthernetAdvanced class.

I did some experiments around link LED. I tried 2 distinct approaches, but both don't work well enough. 1st approach was to run a ticker that verifies eth.link() state and 2nd approach was to run a ticker that copies input from PHY LEDs (wired to MBED pins) to output. These PHY LED pins have link and speed states, but PHY is not programmed to show activity. I also tried activity monitoring by doing HTTPHandler class that blinks an LED for activity. This had shortcomings of not detecting any non-HTTP activity because it is too high-level when packets are already filtered. I think there is one of the implementations in my pub_iva2k_ethsntp. Best approach would probably be to combine low-level state from ethernet class and use PHY leds for speed indication.

Maybe we should put this discussion into different thread.

--

Ilya

You need to log in to post a comment