{"id":116,"date":"2018-02-05T15:33:19","date_gmt":"2018-02-05T23:33:19","guid":{"rendered":"https:\/\/sysprogs.com\/tutorials\/?p=116"},"modified":"2020-04-03T15:08:18","modified_gmt":"2020-04-03T22:08:18","slug":"creating-a-basic-led-driver-for-raspberry-pi","status":"publish","type":"post","link":"https:\/\/sysprogs.com\/VisualKernel\/tutorials\/raspberry\/leddriver\/","title":{"rendered":"Creating a Basic LED Driver for Raspberry Pi"},"content":{"rendered":"<p>This tutorial demonstrates how to develop and debug a basic hardware driver for Raspberry PI. It will demonstrate the following techniques:<\/p>\n<ul>\n<li>Controlling the BCM2708\/BCM2835 peripherals by accessing their hardware registers<\/li>\n<li>Creating a\u00a0<strong>sysfs\u00a0<\/strong>device object to provide user-mode control interface<\/li>\n<li>Using software timers provided by Linux Kernel<\/li>\n<\/ul>\n<p>We will create a kernel module that will make an LED connected to the Raspberry Pi blink with a specified period. The user-mode applications will be able to modify the period via a\u00a0<strong>sysfs\u00a0<\/strong>interface. Note that the Raspberry Pi kernel already comes with a GPIO driver that allows user-mode applications to control the GPIO pins (and LEDs connected to them) directly, however we will not reuse it and will build our driver from scratch to demonstrate direct hardware access.<\/p>\n<ol>\n<li>First of all, create a basic kernel module project for Raspberry Pi by following\u00a0<a href=\"http:\/\/sysprogs.com\/VisualKernel\/legacy_tutorials\/raspberry\/basicmodule\/\">this tutorial<\/a>. Ensure that you can build and debug your module.<\/li>\n<li>Connect an LED to one of the GPIO pins not involved in JTAG debugging. In this example we will use the GPIO_GEN1 signal that corresponds to pin 12 on P1 and GPIO18:<img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/sysprogs.com\/VisualKernel\/legacy_tutorials\/raspberry\/leddriver\/img\/01-layout.png\" width=\"686\" height=\"509\" \/><\/li>\n<li>According to the\u00a0<a href=\"http:\/\/www.raspberrypi.org\/wp-content\/uploads\/2012\/02\/BCM2835-ARM-Peripherals.pdf\">BCM2835 peripheral description<\/a>, the GPIO pins can be controlled by first configuring them as output by writing to one of GPFSELx registers and then writing to GPFSETx\/GPFCLRx registers. We will define a structure describing the GPIO registers and provide functions for controlling GPIO pins using it:\n<pre class=\"code \">struct\u00a0GpioRegisters\r\n{\r\n\u00a0\u00a0\u00a0 uint32_t GPFSEL[6];\r\n\u00a0\u00a0\u00a0 uint32_t Reserved1;\r\n\u00a0\u00a0\u00a0 uint32_t GPSET[2];\r\n\u00a0\u00a0\u00a0 uint32_t Reserved2;\r\n\u00a0\u00a0\u00a0 uint32_t GPCLR[2];\r\n};\r\n\r\nstruct\u00a0GpioRegisters *s_pGpioRegisters;\r\n\r\nstatic\u00a0void\u00a0SetGPIOFunction(int\u00a0GPIO,\u00a0int\u00a0functionCode)\r\n{\r\n\u00a0\u00a0\u00a0\u00a0int\u00a0registerIndex = GPIO \/ 10;\r\n\u00a0\u00a0\u00a0\u00a0int\u00a0bit = (GPIO % 10) * 3;\r\n\r\n\u00a0\u00a0\u00a0\u00a0unsigned\u00a0oldValue = s_pGpioRegisters-&gt; GPFSEL[registerIndex];\r\n\u00a0\u00a0\u00a0\u00a0unsigned\u00a0mask = 0b111 &lt;&lt; bit;\r\n\u00a0\u00a0\u00a0 printk(\"Changing function of GPIO%d from %x to %x\\n\",\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 GPIO,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 (oldValue &gt;&gt; bit) &amp; 0b111,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 functionCode);\r\n\r\n\u00a0\u00a0\u00a0 s_pGpioRegisters-&gt; GPFSEL[registerIndex] =\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 (oldValue &amp; ~mask) | ((functionCode &lt;&lt; bit) &amp; mask);\r\n}\r\n\r\nstatic\u00a0void\u00a0SetGPIOOutputValue(int\u00a0GPIO,\u00a0bool\u00a0outputValue)\r\n{\r\n\u00a0\u00a0\u00a0\u00a0if\u00a0(outputValue)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 s_pGpioRegisters-&gt;GPSET[GPIO \/ 32] = (1 &lt;&lt; (GPIO % 32));\r\n\u00a0\u00a0\u00a0\u00a0else\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 s_pGpioRegisters-&gt;GPCLR[GPIO \/ 32] = (1 &lt;&lt; (GPIO % 32));\r\n}<\/pre>\n<\/li>\n<li>Now we need to set\u00a0<strong>s_pGpioRegisters<\/strong>\u00a0to the address of the GPIO registers in memory. Include the\u00a0<span class=\"string\">&lt;asm\/io.h&gt;<\/span>\u00a0and\u00a0<span class=\"string\">&lt;mach\/platform.h&gt;<\/span>\u00a0files and add the following line to your init() function:\n<pre class=\"code\">s_pGpioRegisters = (struct\u00a0GpioRegisters *)__io_address(GPIO_BASE);<\/pre>\n<p>The GPIO_BASE is the base address of the GPIO registers defined in\u00a0<strong>platform.h<\/strong>.<\/li>\n<li>Now we will make the LED blink with a given period (1 second in this example). If we were writing a user-mode application, we could just make an infinite loop with a call to\u00a0<strong>sleep()<\/strong>\u00a0inside it. However if we do that in our init() function, we will lock up the kernel and prevent other modules from being loaded until init() returns. Thankfully, the kernel provides an easy mechanism to work around this &#8211; timers. All we need to do is create a timer and set it to fire one second from &#8216;now&#8217;. Once it fires, we toggle the state of our LED and set it to fire in a second again. The timer will consist of a timer object and a timer callback that will be invoked every second:\n<pre class=\"\">struct\u00a0GpioRegisters\r\n{\r\n\u00a0\u00a0\u00a0 uint32_t GPFSEL[6];\r\n\u00a0\u00a0\u00a0 uint32_t Reserved1;\r\n\u00a0\u00a0\u00a0 uint32_t GPSET[2];\r\n\u00a0\u00a0\u00a0 uint32_t Reserved2;\r\n\u00a0\u00a0\u00a0 uint32_t GPCLR[2];\r\n};\r\n\r\nstruct\u00a0GpioRegisters *s_pGpioRegisters;\r\n\r\nstatic\u00a0void\u00a0SetGPIOFunction(int\u00a0GPIO,\u00a0int\u00a0functionCode)\r\n{\r\n\u00a0\u00a0\u00a0\u00a0int\u00a0registerIndex = GPIO \/ 10;\r\n\u00a0\u00a0\u00a0\u00a0int\u00a0bit = (GPIO % 10) * 3;\r\n\r\n\u00a0\u00a0\u00a0\u00a0unsigned\u00a0oldValue = s_pGpioRegisters-&gt; GPFSEL[registerIndex];\r\n\u00a0\u00a0\u00a0\u00a0unsigned\u00a0mask = 0b111 &lt;&lt; bit;\r\n\u00a0\u00a0\u00a0 printk(\"Changing function of GPIO%d from %x to %x\\n\",\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 GPIO,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 (oldValue &gt;&gt; bit) &amp; 0b111,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 functionCode);\r\n\r\n\u00a0\u00a0\u00a0 s_pGpioRegisters-&gt; GPFSEL[registerIndex] =\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 (oldValue &amp; ~mask) | ((functionCode &lt;&lt; bit) &amp; mask);\r\n}\r\n\r\nstatic\u00a0void\u00a0SetGPIOOutputValue(int\u00a0GPIO,\u00a0bool\u00a0outputValue)\r\n{\r\n\u00a0\u00a0\u00a0\u00a0if\u00a0(outputValue)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 s_pGpioRegisters-&gt; GPSET[GPIO \/ 32] = (1 &lt;&lt; (GPIO % 32));\r\n\u00a0\u00a0\u00a0\u00a0else\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 s_pGpioRegisters-&gt; GPCLR[GPIO \/ 32] = (1 &lt;&lt; (GPIO % 32));\r\n}<\/pre>\n<\/li>\n<li>Finally we need to add code for setting up the timer in our init() function and code for deleting it in the<br \/>\nexit() function. We also need to configure the GPIO pin in the output mode before we start toggling it:<\/p>\n<pre class=\"code\">static\u00a0int\u00a0__init LedBlinkModule_init(void)\r\n{\r\n\u00a0\u00a0\u00a0 int result;\r\n\r\n\u00a0\u00a0\u00a0 s_pGpioRegisters =\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 (struct GpioRegisters *)__io_address(GPIO_BASE);\r\n\u00a0\u00a0\u00a0 SetGPIOFunction( LedGpioPin, 0b001);\u00a0\/\/Output\r\n\r\n\u00a0\u00a0\u00a0 setup_timer(&amp;s_BlinkTimer, BlinkTimerHandler, 0);\r\n\u00a0\u00a0\u00a0 result = mod_timer( &amp;s_BlinkTimer,\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 jiffies + msecs_to_jiffies( s_BlinkPeriod));\r\n\u00a0\u00a0\u00a0 BUG_ON(result &lt; 0);\r\n}\r\n\r\nstatic\u00a0void\u00a0__exit LedBlinkModule_exit(void)\r\n{\r\n\u00a0\u00a0\u00a0 SetGPIOFunction( LedGpioPin, 0);\u00a0\/\/Configure the pin as input\r\n\u00a0\u00a0\u00a0 del_timer(&amp;s_BlinkTimer);\r\n}<\/pre>\n<\/li>\n<li>Build your module and start debugging it. You can step through the initialization function to double-check that all necessary initialization succeeds:<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-245\" src=\"https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/init.png\" alt=\"\" width=\"1147\" height=\"709\" srcset=\"https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/init.png 1147w, https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/init-300x185.png 300w, https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/init-768x475.png 768w, https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/init-1024x633.png 1024w\" sizes=\"(max-width: 1147px) 100vw, 1147px\" \/><\/li>\n<li>Once you hit F5 to resume the Raspberry Pi kernel the LED will start blinking:<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-250\" src=\"https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/raspi3-1.jpg\" alt=\"\" width=\"1280\" height=\"1012\" srcset=\"https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/raspi3-1.jpg 1280w, https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/raspi3-1-300x237.jpg 300w, https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/raspi3-1-768x607.jpg 768w, https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/raspi3-1-1024x810.jpg 1024w\" sizes=\"(max-width: 1280px) 100vw, 1280px\" \/><\/li>\n<li>Now we will create a sysfs-based user-mode interface for changing the LED blinking frequency. This is accomplished in 3 steps:\n<ul>\n<li>Register a device class (e.g.\u00a0<strong>\/sys\/class\/LedBlink<\/strong>)<\/li>\n<li>Register a device object within the class (e.g.\u00a0<strong>\/sys\/class\/LedBlink\/LedBlink<\/strong>)<\/li>\n<li>Create a sysfs file for the device object (e.g.\u00a0<strong>\/sys\/class\/LedBlink\/LedBlink\/period<\/strong>)<\/li>\n<\/ul>\n<p>First of all we will define a function that will receive a string value, convert it to an integer and update the LED blinking period accordingly:<\/p>\n<pre class=\"code \">static\u00a0ssize_t set_period_callback(struct\u00a0device* dev,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0struct\u00a0device_attribute* attr,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const\u00a0char* buf,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0size_t\u00a0count)\r\n{\r\n\u00a0\u00a0\u00a0\u00a0long\u00a0period_value = 0;\r\n\u00a0\u00a0\u00a0\u00a0if\u00a0(kstrtol(buf, 10, &amp;period_value) &lt; 0)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return\u00a0-EINVAL;\r\n\u00a0\u00a0\u00a0\u00a0if\u00a0(period_value &lt; 10)\u00a0\/\/Safety check\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return\u00a0-EINVAL;\r\n\r\n\u00a0\u00a0\u00a0 s_BlinkPeriod = period_value;\r\n\u00a0\u00a0\u00a0\u00a0return\u00a0count;\r\n}\r\n\r\nstatic\u00a0DEVICE_ATTR(period, S_IWUSR | S_IWGRP,\u00a0NULL, set_period_callback);\r\n\r\nstatic\u00a0struct\u00a0class *s_pDeviceClass;\r\nstatic\u00a0struct\u00a0device *s_pDeviceObject;<\/pre>\n<\/li>\n<li>Create the class, device and file objects from the init() function:\n<pre class=\"code\">s_pDeviceClass = class_create(THIS_MODULE,\u00a0\"LedBlink\");\r\nBUG_ON( IS_ERR( s_pDeviceClass));\r\n\r\ns_pDeviceObject = device_create( s_pDeviceClass,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 NULL,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 NULL,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"LedBlink\");\r\nBUG_ON( IS_ERR( s_pDeviceObject));\r\n\r\nresult = device_create_file( s_pDeviceObject, &amp;dev_attr_period);\r\nBUG_ON(result &lt; 0);<\/pre>\n<\/li>\n<li>Finally add the cleanup code to the exit() function:\n<pre class=\"code\">device_remove_file( s_pDeviceObject, &amp;dev_attr_period);\r\ndevice_destroy( s_pDeviceClass, 0);\r\nclass_destroy( s_pDeviceClass);<\/pre>\n<p>You will need to switch the license of your module to GPL to be able to call\u00a0<strong>device_destroy()<\/strong>.<\/li>\n<li>Build your module and start debugging it. You can step through the initialization to re-check everything:<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-246\" src=\"https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/device.png\" alt=\"\" width=\"1147\" height=\"709\" srcset=\"https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/device.png 1147w, https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/device-300x185.png 300w, https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/device-768x475.png 768w, https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/device-1024x633.png 1024w\" sizes=\"(max-width: 1147px) 100vw, 1147px\" \/><\/li>\n<li>Connect to your Raspberry Pi over SSH and write the new period value to the\u00a0<strong>\/sys\/class\/LedBlink\/LedBlink\/period<\/strong>\u00a0file using the root terminal:<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-247\" src=\"https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/period.png\" alt=\"\" width=\"817\" height=\"407\" srcset=\"https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/period.png 817w, https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/period-300x149.png 300w, https:\/\/sysprogs.com\/tutorials\/wp-content\/uploads\/2018\/02\/period-768x383.png 768w\" sizes=\"(max-width: 817px) 100vw, 817px\" \/><br \/>\nYou will see how the LED blinking period will change. Note that if you write a value that is not a number, you will get an error (because\u00a0<strong>set_period_callback()<\/strong>\u00a0will return\u00a0<strong>-EINVAL<\/strong>).<\/li>\n<\/ol>\n<p>You can download the source code of the LED driver described in this tutorial\u00a0<a href=\"https:\/\/github.com\/sysprogs\/tutorials\/blob\/master\/visualkernel\/raspberry\/LEDBlink\/LEDBlink_main.c\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial demonstrates how to develop and debug a basic hardware driver for Raspberry PI. It will demonstrate the following<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[35],"tags":[36,20,37],"_links":{"self":[{"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/posts\/116"}],"collection":[{"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/comments?post=116"}],"version-history":[{"count":15,"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/posts\/116\/revisions"}],"predecessor-version":[{"id":438,"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/posts\/116\/revisions\/438"}],"wp:attachment":[{"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/media?parent=116"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/categories?post=116"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sysprogs.com\/tutorials\/wp-json\/wp\/v2\/tags?post=116"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}