Raspberry Pi Startup Script Tutorial

Part 3: Pi Soft Power Controller, what to put on the Pi

raspberry pi startup script

The last couple of weeks I have been making progress and posts on my RetroPie build. I’m putting a Raspberry Pi inside of an actual SNES (well Super Famicom). Part 1 covered the schematic for a Soft Power Controller. In Part 2 I broke down the RPSPC state machine. This 3rd and final post of the series is a Raspberry Pi startup script tutorial. It covers how to make scripts run at startup and shutdown.

When I started researching how to make Raspbian run a script at startup and shutdown, I found a ton of links and questions asking for help. None of them helpful. Why? Because they were wrong. At least, they are now.

/etc/rc.d doesn’t matter!

It turns out, Raspbian Jessie does not use SysV for init (anymore). So it does not matter what you scripts you put in /etc/rc.d. Pretty simple but missed by many!

Here is a correct Raspberry Pi Startup Script Tutorial.

The Key is systemd

Once I started researching how to make systemd do what I wanted, new problems emerged. The syntax for systemd is not as straightforward as I first thought. Thanks to readers, I was pointed towards the RedHat systemd manual. After reviewing it, I was able to create a service that runs at startup and shutdown.

In the end, I was unable to prevent this process from running during reboot. There seem to be some more layers to make sure systemd knows the difference. In the end, I decided it was not necessary to avoid the reboot.

systemd configuration

There are two systemd services necessary for my RetroPie controller to work. First includes the Raspberry Pi startup script tutorial with one service that runs a script (or program) at startup and shutdown. Then I will explain one that runs in the background, watching a GPIO pin.

Raspberry Pi Startup Script Tutorial (that actually works)

Here is the systemd configuration file.

# Put this file in /etc/systemd/system
# then run sudo systemctl enable powercontrol-coms.service 
# on startup, GPIO signal will go high
# on shutdown/reboot, GPIO signal will go low

[Unit]
Description=Retropie Pi Power Controller
Before=network.target
After=umount.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/c-start
ExecStop=/usr/local/bin/c-stop
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

I called mine powercontrol-coms.service (click for GitHub version). Place it in the /etc/systemd/system directory. Once it is there run: sudo systemctl enable shutdown-gpio.service. I found you need to reboot before it works both during a startup and shutdown.

Here’s how the file works, as I understand it. (Feel free to correct me in the comments.)

[Unit]

[Unit]
Description=Retropie Pi Power Controller
Before=network.target
After=umount.target

The “Description” is just that, a text string to explain what this service does for the system. “Before” tells what unit to activate this service before. In other words, it defines a dependency. I picked network seems pretty early in the boot process. “After” is what unit must run before this service is called. In this case, I wanted to know when the filesystem had been unmounted. I knew it was safe to power down at that point.

Fun fact: The process should not be called ‘unmount.’ It took me a little bit to understand what it does. I mean, how could anything run after the root file system was unmounted? Well, it is because it is not. Instead, systemd (and even SysV) remounts the filesystem as read-only! (Totally makes sense, right?)

[Service]

[Service]
Type=oneshot
ExecStart=/usr/local/bin/c-start
ExecStop=/usr/local/bin/c-stop
RemainAfterExit=yes

This section took me some time to fully understand. The documentation is a bit more technical than necessary. Moreover, what I found is that most posts online do not understand it either. Quite a few people would say “try something like this” but not able to explain how it works.

I’m going to try to explain.

The “Type” says what kind of process are you about to call. The most common is “oneshot” with “simple” being another option. The “oneshot” type is popular because it means the process runs, exits, then other units can continue. My understanding is that if you use simple, other units might start at the same time.

The “ExecStart” parameter is what will run at startup, while the “ExecStart” parameter is what will run during shutdown (or reboot). “RemainAfterExit,” in this case, doesn’t seem to matter.

[Install]

[Install]
WantedBy=multi-user.target

The “WantedBy” create a weak dependency. However, multi-user.target is the most common target when booting with or without a GUI.

And that’s it. Enable that service and whatever you define in ExecStart and ExecStop runs at startup and then shutdown. Easy. (If you only want one or the other, replace the opposite Exec with /bin/true.)

In the case of the RetroPie, I have two simple compiled programs that toggle GPIO pin on the Raspberry Pi.

Shutdown Raspberry Pi with GPIO Pin

Over on the RPSPC GitHub repository, I have already written up instructions on how to compile c-start, c-stop, and c-watch. I’m not going go into detail on this post because I might cover wiringPi later in the future. However, I did want to show the code I’m using to detect an external signal to start the shutdown.

C-watch: Raspberry Pi C GPIO Program

#include <wiringPi.h>
#include <stdio.h>
#include <unistd.h>
#include <linux/reboot.h>

int ioPin = 7; // GPIO04, physical pin 7

int main (void) {
	wiringPiSetup ();
	pinMode (ioPin, INPUT);
	printf("c-watch v0 is now running.\n");
	while(1) {
		pullUpDnControl(ioPin, PUD_DOWN);
		if (!digitalRead(ioPin)) {
			printf("LOW\n");
			break;
		}
		delay(1000);
	}
	printf("Got signal, starting shutdown.\n");
	// Would like to change to dbus at some point
	system("shutdown -P now");
	delay(500);
	return 0;
}

I won’t cover this as a Line-by-Line tutorial. The basic concept is that wiringPi is an Arduino-like library for the Raspberry Pi. This library lets you write relatively simple C programs to control the Pi’s GPIO pins. In this case, I set a particular pin to INPUT and then read it in a loop until it toggles. Calls like delay() make use of sleep functions available in Linux, so a program like this uses almost no CPU time.

WiringPi is a brilliant library if you want a low-overhead way to control the Raspberry Pi GPIO pins.

Conclusionrpspc oshpark render

As of this post, OSHPark is making my boards. In a couple of weeks, I will know if the hat version of my RetroPie soft power controller works. This Raspberry Pi startup script tutorial already works on my prototype. But I’d like to get to a final version. As I tweak the board design, I will keep the RPSPC Repository updated.

Now it’s on to finishing the physical part of the build.

Long comments, URLs, and code tend to get flagged for spam moderation. No need to resubmit.

Leave a comment

2 thoughts on “Raspberry Pi Startup Script Tutorial

  1. This is so interesting; I find it hard to believe that there is no cut and dry way to reset a pi. I will keep this tutorial in mind as I am sure I will need to use something like this in the future.