Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cpu/stm32f4: Add LPM implementation #2246

Merged
merged 1 commit into from
Feb 11, 2015
Merged

Conversation

fnack
Copy link
Member

@fnack fnack commented Jan 6, 2015

This PR provides an implementation for the low power mode lpm_arch interface for the STM32F4 series.

The current mapping of STM's power modes on RIOT's lpm_modes is:
RUN --> LPM_ON
SLEEP --> LPM_IDLE
STOP --> LPM_SLEEP
STANDBY --> LPM_POWERDOWN/LPM_OFF

An example application for quick testing is provided in the second commit. It configures a wakeup GPIO pin (User Button 1 for stm32f4discovery/msbiot) and sets the low power modes one after another. The user has to create a LH change on the wakeup GPIO pin after each entry into a lpm. To wake up the board from LPM_POWERDOWN/LPM_OFF the reset gpio pin has to be used (User Button 1 for stm32f4discovery, User Button 2 for msbiot). The application will be removed before merging, as it is only stm32f4 specific.

Please be aware that when using st-util there might be issues flashing the board after the MCU once entered a low power mode. This is a known issue. In most cases you then need to:

  1. Short the BOOT0 pin with VDD
  2. Reset the board
  3. sudo st-flash erase
    Please see the following issue reports for more information and on regaining control of the board:
    [reset] st-flash does not work when CPU is in sleep mode stlink-org/stlink#62
    STM32F4 Discovery - unknown chip id! 0xe0042000 stlink-org/stlink#107

@fnack fnack added Type: new feature The issue requests / The PR implemements a new feature for RIOT Platform: ARM Platform: This PR/issue effects ARM-based platforms labels Jan 6, 2015
@fnack
Copy link
Member Author

fnack commented Jan 6, 2015

I opened a new issue report for further interface clarification: #2247.

Ping @haukepetersen. Here's the pull request we talked about yesterday.

@PeterKietzmann
Copy link
Member

I'll have a look at this at the Hack'n'ACK event this evening

@haukepetersen
Copy link
Contributor

I think I would prefer to move your example application to tests. Any other opinions on this?

@fnack
Copy link
Member Author

fnack commented Jan 6, 2015

The example application is supposed to be removed! It is only valid for STM32F4 series MCU's and therefore poses no greater value to RIOT's master branch.

}

enum lpm_mode lpm_arch_get(void)
{
/* TODO */
return 0;
return current_mode;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is current_mode initialized with a value before any other function is called? Otherwise would it make sense to do so with LPM_UNKNOWN ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're probably right. Grepping through RIOT's code, lpm_init (which is defined as lpm_arch_init) is currently not called initially. I'll initialize it with LPM_UNKNOWN.

@fnack
Copy link
Member Author

fnack commented Jan 6, 2015

Adressed your initialization comment.

@PeterKietzmann
Copy link
Member

The code looks good to me. Also it seems to work for the stm32f4discovery board. This is what I get when executing the example:

Start:

2015-01-06 17:50:16,721 - INFO # kernel_init(): jumping into first task...
2015-01-06 17:50:16,723 - INFO # LPM example application
2015-01-06 17:50:16,725 - INFO # Entering LPM_IDLE

Press button B1 first time:

2015-01-06 17:50:47,469 - INFO # Successfully awoke from LPM_IDLE

Release button B1:

2015-01-06 17:54:01,895 - INFO # Entering LPM_SLEE�Successfully awoke from LPM_SLEEP

Press button B1 second time:

2015-01-06 17:55:00,821 - INFO # Entering LPM_POWERDOWkernel_init(): This is RIOT! (Version: 2014.05-1929-gc475-hacknack_stm32f4_lpm)
2015-01-06 17:55:00,825 - INFO # kernel_init(): jumping into first task...
2015-01-06 17:55:00,827 - INFO # LPM example application
2015-01-06 17:55:00,829 - INFO # LPM tests successful

Is this what is expected?

@PeterKietzmann
Copy link
Member

Generally I think it's a good thing to have an example (or a test) application for a functionality

@fnack
Copy link
Member Author

fnack commented Jan 6, 2015

Ackording your results: Normally releasing the button should not trigger wakeup from LPM_SLEEP. The interrupt is configured for a rising edge of the signal (button push). Could you test this again?
Everything else looks good. Wakeup from LPM_POWERDOWN is only possible with a RESET, that's why the application starts again. Afterwards inside the application a flag from the stm32f4's power csr register is read, which signals whether the MCU awoke from STANDBY mode (the flag is not reset on system reset).

Do you use st-util and did you experience any problems flashing the device after running the application?

According your second comment:
In general I agree with you, but for the huge variety of existing power modes and wakeup modalities for different MCUs, I don't see a way to provide a good general test application that is useful (mine is definitely not valid for this purpose). I'd also argue that this is not in the scope of this Pull Request.

@PeterKietzmann
Copy link
Member

According to the "press/release-button-problem" I think it's possible that 1.we should not trust the button on the stm32f4discovery OR 2. there is some kind of timing problem. Aren't there deadtimes? Cause the test sometimes behaves as I described above and somtimes as you said (as it should).

@PeterKietzmann
Copy link
Member

According to the flashing problem: Yes I experienced the same :-(

@PeterKietzmann
Copy link
Member

According to the tests-discussion I agree that this exceeds the scope of this PR. Generally one should think about a universal thing for different behaving boards.

@fnack
Copy link
Member Author

fnack commented Jan 6, 2015

Then I would probably not trust the button 100% as the test behaves as expected for my MSB-IoT with STM32F415RG.

Considering the flashing problem, maybe we should completely finalize this PR but wait with merging for this one:
#2074

@PeterKietzmann
Copy link
Member

Did you try flashing with openocd after this application ran?

@fnack
Copy link
Member Author

fnack commented Jan 6, 2015

No, don't want to change my setup currently. But it is reported in the st-util issues as a st-flash specific problem.

@PeterKietzmann
Copy link
Member

Ok let's wait for #2074 and try to to keep this in mind :-) !

@PeterKietzmann
Copy link
Member

@fnack #2074 is merged!

@PeterKietzmann
Copy link
Member

The above described issues disappear when using openocd (which was merged with #2074)

@PeterKietzmann
Copy link
Member

PS: You sometimes have to reset the board 2-3 times to successfully flash it again

@PeterKietzmann
Copy link
Member

@fnack. I didn't go into detail regarding the low power modes, but still the test seems to behave strange. Do you have the same behavior?

Starting the application

kernel_init(): This is RIOT! (Version: 2014.05-2152-g55181-test_stm32f4_lpmmode)
kernel_init(): jumping into first task...
LPM example application
Entering LPM_IDLE

Current is ~13,6mA.
Pressing B1 first time (I toggled a pin with another board and connected it to GPIO_0 on stm32f4discovery)

Successfully awoke from LPM_IDLE

Current is ~0,8mA.
Pressing B1 second time

�Successfully awoke from LPM_SLEEP
Entering LPM_POWERDOWkernel_init(): This is RIOT! (Version: 2014.05-2152-g55181-test_stm32f4_lpmmode)
kernel_init(): jumping into first task...
LPM example application
LPM tests successful

Current is ~13,6mA again.
The test behaves a bit different when executing after a reset without reflashing or taking away from power. I assume this has to do with the LPM_POWERDOWN mode from the first execution.
The measured values do not seem to correspond to the aimed modes (or printfs). Also the interrupts seem to crash something. Everything feels like a timing problem. Did you had a look at needed delays after a mode change?

@fnack
Copy link
Member Author

fnack commented Jan 30, 2015

I currently don't have time to analyze the problem, as I have to hand in my master thesis next week. I promise to look into it afterwards.

But what is obiousvly wrong with the application is that there should be a short waiting time between a puts("Bla") and going into a low power mode. That's why the output lines seem to be wrong. If you put a short waiting time before every low power mode setting in the application, I assume the output should look better!

@PeterKietzmann
Copy link
Member

Not that easy... I already tried something like this but it seemed to get stuck then. Would be nice if you have a look at it after handing your thesis. Wish you success!

@fnack
Copy link
Member Author

fnack commented Feb 7, 2015

Are you sure you are testing it correctly? I adapted the application with vtimer sleeps and as I expected the output lines now are completely correct.

Example run:
Starting the application

2015-02-07 16:10:25,910 - INFO # kernel_init(): This is RIOT! (Version: 2014.05-2190-g41363-fabian-ThinkPad-L412-stm32f4_lpm)
2015-02-07 16:10:25,912 - INFO # kernel_init(): jumping into first task...
2015-02-07 16:10:25,913 - INFO # LPM example application
2015-02-07 16:10:25,914 - INFO # Entering LPM_IDLE

Now, we've entered the first low power mode and the board waits for an interrupt to wake up. For the MSB-IoT, the application has configured GPIO_8 to produce an interrupt on the rising edge. GPIO_8 is PB13 which is the first user button of the board. Pushing the button the board awakes and changes to the next low power mode:

2015-02-07 16:10:38,914 - INFO # Successfully awoke from LPM_IDLE
2015-02-07 16:10:38,915 - INFO # Entering LPM_SLEEP

I have no equipment to test energy consumption but now you should see less consumption than for the IDLE power mode. For this power mode, the mcu can still be awaken by an interrupt from a normal GPIO pin, so we can use the first user button again. Pressing the user button awakes the mcu and reconfigures the clock system (because this is necessary after the controller was in the stm stop mode). We see the following output:

2015-02-07 16:10:44,125 - INFO # Successfully awoke from LPM_SLEEP
2015-02-07 16:10:44,126 - INFO # Entering LPM_POWERDOWN

Now, we are in the deepest power mode. A normal GPIO interrupt will no longer wake up the mcu so pressing the first user button now has no effect. But when LPM_POWERDOWN was entered, the WKUP pin was enabled which can recover the board from this mode. The wkup pin is PA0, which is connected with the second user button on the MSB-IoT. Pressing it restarts the board (because that is needed after being in the deepest power mode) and we see an application restart. Restarting the board in this way does not reset all registers. Some are kept. One of them is the PWR->CSR register which contains a flag that signals whether the board awoke from the deepest power mode. This flag is checked at the beginning and because now at the application restart it is set, we see a different output from the application:

2015-02-07 16:10:49,597 - INFO # kernel_init(): This is RIOT! (Version: 2014.05-2190-g41363-fabian-ThinkPad-L412-stm32f4_lpm)
2015-02-07 16:10:49,598 - INFO # kernel_init(): jumping into first task...
2015-02-07 16:10:49,599 - INFO # LPM example application
2015-02-07 16:10:49,600 - INFO # LPM tests successful

I tested it several times and it always behaved like expected. Maybe you are confused because the STM32F4Discovery board only has one user button which is connected to PA0 and therefore in the example application can be used to wake up the mcu from all three power modes (because PA0 is the wkup pin as well)?

@PeterKietzmann
Copy link
Member

I will test this with an ammeter tomorrow. Now the example runs better, but still I have the strange behavior that I don't stay in LPM_POWERDOWN mode. It seems like the reset is done automatically. However, when the currents correlate to the states we're not far from ACKing.


# Define default pin mappings for some boards:
ifneq (,$(filter stm32f4discovery,$(BOARD)))
export WKUP_GPIO ?= GPIO_0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change this to GPIO_2

@PeterKietzmann
Copy link
Member

Ok with the above proposed change I got it running with:
LPM_IDLE: ~16mA
LPM_SLEEP: ~3mA
LPM_POWERDOWN: ~0,5mA
Please adapt the change and squash. Then we can go...

@fnack
Copy link
Member Author

fnack commented Feb 10, 2015

Good to see that it is working! But you are confusing me again. I thought we did agree that the application I provided is only there for testing purposes and will not be merged into the master branch? The application is completely STM32F4 MCU specific and therefore from my point of view should not be included in RIOTs master. That's why I named these commits [rem later] for "remove later" ;)

puts("LPM tests successful");
PWR->CR |= PWR_CR_CSBF;
return 0;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there anything other than this which is CPU specific in the example?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, but this example application has absolutely no value without this part.

@haukepetersen
Copy link
Contributor

@PeterKietzmann what hardware did you use for measuring the current consumption of the F4discovery board?

@PeterKietzmann
Copy link
Member

@fnack, sorry I forgot that you wanted to remove the example code. Still I feel a bit uncertain to leave a test for the modes out, but ok...
@haukepetersen I just took my multimeter/ammeter (AMPROBE 37XR-A). If you have an oscilloscope you can also try to measure the volage over a shunt resistor connected at jumper position JP1.

@haukepetersen
Copy link
Contributor

@PeterKietzmann thx for the info. I am aware of the shunt option (though I was always too lazy to set something up), but the multimeter approach seems easy enough, maybe time to invest :-)

@fnack
Copy link
Member Author

fnack commented Feb 11, 2015

Rebased, squashed and kicked the application out. If someone has a good idea for a general test application and wants to use my application as a starting point it can be found here.

@PeterKietzmann
Copy link
Member

Fine let's go then. Maybe #2247 comes along with a solution for a test anytime. ACK

@PeterKietzmann
Copy link
Member

&go

PeterKietzmann added a commit that referenced this pull request Feb 11, 2015
cpu/stm32f4: Add LPM implementation
@PeterKietzmann PeterKietzmann merged commit d5efb32 into RIOT-OS:master Feb 11, 2015
@fnack fnack deleted the stm32f4_lpm branch March 13, 2015 13:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Platform: ARM Platform: This PR/issue effects ARM-based platforms Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants