Make your BeagleBone Black am355x magically turn itself on with the built-in alarm clock

bbbrtc.gif

The am335x ARM chip in the BeagleBone Black has a Real Time Clock hidden inside that you can use to have the board spontaneously turn itself on anytime in the next 100 years.

Here I present a new utility to manage that built-in clock from the Linux command line, and explain how to use it to keep time, shutdown, software power cycle, and more!

tldr;

Type these commands on your BBB running Debian and wait for about 10 seconds. You should see itself turn off… and then magically turn back on one minute later….

git clone https://github.com/bigjosh/bbbrtc
cd bbbrtc
make
i2cset -f -y 0 0x24 0x0a 0x00
sync
bbbrtc now 100
bbbrtc wake 115
bbbrtc sleep 110

Enter bbbrtc alone to see all the parameters.

Demo

Most interesting thing I learned

The Linux date command has a semi-documented, natural language processing, fuzzy logic expert system built-in.  You can ask it to figure out what day of the week it was 10 years and 4 hours ago….

root@beaglebone:~# date -d "now 10 years 4 hours ago" | cut -c1-3
Sun

…or when the next episode of Saturday Night Live will begin…

root@beaglebone:~# date -d "11:30pm next saturday"
Sat May 5 23:30:00 UTC 2018

The basic idea

The ARM processor chip in the BBB has a Real Time Clock (RTC) built-in. This RTC has connections to the Power Management IC (PMIC) that it can use to tell the PMIC to either shut off the power or turn it back on.

There are two “alarms” in the RTC that we can set. When these alarms go off, one will send the signal to the PMIC telling it to turn off, and the other alarm tells the PMIC to turn the power on.

Using an alarm to turn off makes sense, but how can the “on” alarm send a signal to the PMIC to tell it to turn on if the power is off!?

The PMIC has a bit called OFF, and if that bit is not set then it only mostly turns off the the power to the ARM, and there is a big different between mostly off and all off. In this state, the PMIC continues to supply the very low power LDO1 rail, and this rail is connected directly to dedicated pins on the ARM that power the RTC.

2018-05-04_20-38-10.png

To make all this work we just need a way to set the time and alarms on the RTC, and a way to clear the OFF bit in the PMIC.

The PMIC has an i2c connection, so that is easy to get to from the Linux command line using the i2cset command (shown below), but I could not find a good way to set the RTC registers, so I wrote…

The bbbrtc utility

This little utility makes it possible to set up all the necessary registers inside the RTC.

There are three times you can get and set inside the RTC…

now – the time right now. This increments each second.

sleep – the time we should go to sleep.

wake– the time we should wake up.

These times are specified using the standard “Unix time” system, which is the count of seconds since Jan 1, 1970.

Syntax

Running the bbbrtc utility without any params gives…

Usage:
   bbbrtc dump
   bbbrtc now 
   bbbrtc (sleep|wake) ({time}|never)

Where:
   'bbbrtc dump` dumps the contents of all registers to stdout
   if  is present and non-zero, then the specified time is set
   if never is specified with sleep or wake, the event is disabled (clock value is left the same)
   time is in seconds since epoch, parsed leniently
   prints existing or newly set the value of the specified time

Notes:   
   wake should always be later than sleep or you will sleep for 100 years
   if you sleep without setting a wake then you must push the power button to wake

Times:
   always specified in seconds since the epoch Jan 1, 1970
   never turns off the specified interrupt

Examples:
   set the rtc to the current system clock time...
      bbbrtc now $(date +%s)
   set the system clock to the current rtc time...
      date -s @$(bbbrtc now)
   set to sleep 10 seconds from now...
      bbbrtc sleep $[$(bbbrtc now)+10]
   set to wake 1 day after we go to sleep ...
       bbbrtc wake $(date +%s -d "$(date -d "@$(bbbrtc sleep)") + 1 day")
   start a bbbrtc party...
      bbbrtc now 946684770

Notes:
   If you want to be able to wake from sleeping, you must turn off the 'off' bit
   in the PMIC controller with this command before going to sleep..
   i2cset -f -y 0 0x24 0x0a 0x00

   The RTC doesn't know about timezones or DST, so best to use UTC time with it,
   but as long as you are consistent and set both all the times using the same base,
   then all relatives times should work.

   It looks like my Debian calls hwclock --systohc sometime during startup,
   even when Linux has no way of knowing what time it is (it is hardcoded to
   Jun15 2016). This sadly which clobbers the time stored in the RTC, which
   could otherwise be correct and used to set the linux clock.

Getting RTC times

You can see what any of these are currently set to by running bbbrtc and the name of the time, so…

bbbrtc now will print the time right now according to the RTC now clock.

bbbrtc sleep will print the time that is currently set to go to sleep.

Setting RTC times

You can set any of the times by specifying the new value after the time name.

To set the now time in the RTC to one second past midnight on 1/1/1970, you could run…

bbbrtc now 1

…and it would print…

Setting NOW to 1...set.

Now if you wait for 15 seconds and then run…

bbbrtc now

…again you’ll see…

Reading NOW and printing to stdout...15

The RTC now thinks it is 00:00:15 1/1/1970, and will keep counting up from there.

Tips

  • If you want to be able to turn back on after you power down, you have to execute this command before power down…
    i2cset -f -y 0 0x24 0x0a 0x00
    This tells the PMIC to allow power-up based on the signal from the RTC. Otherwise it will wait for one of the power sources to turn on.
  • If a sleep alarm happens and you have not set a wake alarm, or the wake time is past now then you will have to press the power button on the board to turn back on.

The RTC

In section 20.3.2 of the 4,728 page technical reference manual, you will find a description of the on-board real-time clock…

2018-04-28 18_58_17-am335x_techref.pdf - Foxit Reader

This part of the chip is special- it has its own special power supply connection so it stay running even when the rest of the chip is powered down.

On the BBB, it also has connections to the Power Management IC that can let it turn power off and on remotely.  PMIC_POWER_EN is used to tell the PMIC to shutdown or turn on power…

2018-04-28 19_09_01-beaglebone_revA3.opj.png

Here is the state machine diagram for the PMIC…

2018-04-28 19_04_40-TPS65217x Single-Chip PMIC for Battery-Powered Systems datasheet (Rev. I).png

If you look at the ACTVE state, you can see we can get to SLEEP if OFF is 0 by setting PWR_EN to 0. Note that this is not the same as the sleep on the ARM chip – which lets you keep RAM intact. The sleep mode on the PMIC removes all power from the ARM except that special rail for the RTC.

OFF is a bit inside the PMIC chip, and we can set it to 0 over the i2c bus. The PMIC datasheet tells us that it is at address 0x24…

2018-04-30 14_30_12-TPS65217x Single-Chip PMIC for Battery-Powered Systems datasheet (Rev. I).png

…and the OFF bit is here…2018-04-30 14_31_49-TPS65217x Single-Chip PMIC for Battery-Powered Systems datasheet (Rev. I).png

…so we can clear it with this Linux command…

i2cset -f -y 0 0x24 0x0a 0x00

We need the -f because something in Linux is already using this i2c so we would get a busy error. I am too lazy to figure out what it is and how to get it too let go.

The RTC will make POWER_EN go low when ALARM2 goes off, and high when ALARM goes off if we set this bit…Snag_1f5889.png

We also have to enable the associated interrupts even though we do not want the actual interrupts to get fired (it really does not work if you skip this)…

Snag_202a9e.png

Thebbbrtc programs does these for you when you set either sleep or wake times.

FAQ

Q: How much power does the board use when off? 

A: About 40mA. I don’t know where this comes from since the ARM and PMIC should both be using much less than 1mA when in this state. There is a crapton of places this could be coming from on this board.  If you care about low power, then you should pick a different board. In fact, you should probably pick a different board anyway since this one has so many issues like this (see last FAQ question).

Please LMK if you figure out what is using this extra power.

Q: This is AWESOME, now I can have my BBB know what time it is when it powers up even without a network connection!

A:You should be able to do this in theory, but in practice Linux or uboot seems to insist on setting the RTC now time to sometime at the end of in 2015 on power up.

I tried doing this in ​/​etc/default/hwclock but it doesn’t seem to help…

# Set this to yes if it is possible to access the hardware clock,
# or no if it is not.
HWCLOCKACCESS=no

Please LMK if you figure out how to stop this from happening.

Q: What if I want to power down for more than 100 years?

A: The years register in the RTC is a two digit BCD number (WTF?) so the best you can do power down for 100 years, update some file in the file system (or one of the handy RTC scratch registers), and then set a new alarm and turn off again.

Q: Why didn’t you just use the built-in Linux stuff. 

A: I tried, but so much mess and so many patches I just could not figure out if linux can even do this, much less get it to work. As far as I can tell, it can read the now time from the RTC using the hwclock stuff, but can not  set the alarms or the important other registers you need for this stuff to happen.

Q: Why did you write ​bbbrtc when you could just use a million devmem2 commands?

A: I started with a million devemem2 commands, but it quickly got too hard to keep track of everything in BASH. Since almost all disros do not come with devmem2, and almost all do come with a C compiler I thought it would be easier to just make a short and clear C program.

Q: Why did you do this?

A: While I think it is cool that you can have a computer turn itself on, my only goal here was to find a way to drive the NRESET-INOUT line low from software- and this is the first way I found that can do that.

Q: Why do you want to drive the NRESET-INOUT line low so bad?

A: Tune in next time!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s