STM32MP157 Linux Character Device Driver Development Guide

Project Directory Structure

Key project directories for STM32MP157 development:

  • Buildroot root filesystem: /home/developer/projects/stm32mp157/rootfs
  • NFS root fliesystem: /home/developer/projects/nfs/rootfs
  • Linux source code: /home/developer/projects/linux-5.4.31
  • Device tree: /home/developer/projects/linux-5.4.31/arch/arm/boot/dts/stm32mp157-atk.dts
  • TFTP server: /home/developer/projects/tftpboot

Network Booting with U-Boot

To boot Linux using TFTP and NFS:

  1. Place uImage and stm32mp157-atk.dtb in /home/developer/projects/tftpboot
  2. Configure network settings on host:
sudo ifconfig eth0 192.168.1.100
  1. Set U-Boot environment variables:
setenv ipaddr 192.168.1.101
setenv gatewayip 192.168.1.1
setenv netmask 255.255.255.0
setenv serverip 192.168.1.100
saveenv
  1. Download and boot:
tftp 0xc2000000 uImage
tftp 0xc4000000 stm32mp157-atk.dtb
setenv bootargs 'console=ttySTM0,115200 root=/dev/nfs nfsroot=192.168.1.100:/home/developer/projects/nfs/rootfs,proto=tcp rw ip=192.168.1.101:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off'
boot

Character Device Driver API Reference

Key header files and structures for character device drivers:

#include <linux/types.h>
dev_t;  // Device number type

int MAJOR(dev_t dev);
int MINOR(dev_t dev);
dev_t MKDEV(unsigned int major, unsigned int minor);

#include <linux/fs.h>
int register_chrdev_region(dev_t first, unsigned int count, char *name);
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
void unregister_chrdev_region(dev_t first, unsigned int count);

struct file_operations {
    struct module *owner;
    ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
    int (*open)(struct inode *, struct file *);
    int (*release)(struct inode *, struct file *);
};

#include <linux/cdev.h>
struct cdev *cdev_alloc(void);
void cdev_init(struct cdev *dev, struct file_operations *fops);
int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
void cdev_del(struct cdev *dev);

Network Configuration for Development

Configure host for NFS and TFTP:

  1. Install required packages:
sudo apt-get install nfs-kernel-server tftpd-hpa xinetd
  1. Create NFS directory:
mkdir -p /home/developer/projects/nfs/rootfs
chmod 777 /home/developer/projects/nfs/rootfs
  1. Configure exports:
echo "/home/developer/projects/nfs 192.168.1.0/24(rw,sync,no_root_squash)" >> /etc/exports
sudo /etc/init.d/nfs-kernel-server restart

LED Driver Implementation

LED driver for STM32MP157 using GPIOI0:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/fs.h>

#define LED_DRIVER_MAJOR 201
#define LED_DEVICE_NAME "led_driver"

/* Register addresses */
#define GPIO_BASE (0x5000A000)
#define GPIO_MODER (GPIO_BASE + 0x00)
#define GPIO_OTYPER (GPIO_BASE + 0x04)
#define GPIO_OSPEEDR (GPIO_BASE + 0x08)
#define GPIO_PUPDR (GPIO_BASE + 0x0C)
#define GPIO_BSRR (GPIO_BASE + 0x18)

static void __iomem *gpio_moder;
static void __iomem *gpio_otyper;
static void __iomem *gpio_ospeedr;
static void __iomem *gpio_pupdr;
static void __iomem *gpio_bsrr;

static void led_control(int state) {
    u32 value = readl(gpio_bsrr);
    if (state == 1) {
        value |= (1 << 0);  // Set bit 0
    } else {
        value |= (1 << 16); // Set bit 16
    }
    writel(value, gpio_bsrr);
}

static int led_open(struct inode *inode, struct file *file) {
    return 0;
}

static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) {
    char state;
    if (copy_from_user(&state, buf, 1) != 0)
        return -EFAULT;
    
    led_control(state);
    return 1;
}

static int led_release(struct inode *inode, struct file *file) {
    return 0;
}

static struct file_operations led_fops = {
    .owner = THIS_MODULE,
    .open = led_open,
    .write = led_write,
    .release = led_release,
};

static int __init led_init(void) {
    int ret;
    u32 reg_val;
    
    /* Map registers */
    gpio_moder = ioremap(GPIO_MODER, 4);
    gpio_otyper = ioremap(GPIO_OTYPER, 4);
    gpio_ospeedr = ioremap(GPIO_OSPEEDR, 4);
    gpio_pupdr = ioremap(GPIO_PUPDR, 4);
    gpio_bsrr = ioremap(GPIO_BSRR, 4);
    
    /* Enable GPIOI clock */
    reg_val = readl(gpio_moder);
    reg_val |= (1 << 8);
    writel(reg_val, gpio_moder);
    
    /* Configure GPIOI0 as output */
    reg_val = readl(gpio_moder);
    reg_val &= ~(0x3 << 0);
    reg_val |= (0x1 << 0);
    writel(reg_val, gpio_moder);
    
    /* Set output type as push-pull */
    reg_val = readl(gpio_otyper);
    reg_val &= ~(1 << 0);
    writel(reg_val, gpio_otyper);
    
    /* Set speed to high */
    reg_val = readl(gpio_ospeedr);
    reg_val &= ~(0x3 << 0);
    reg_val |= (0x2 << 0);
    writel(reg_val, gpio_ospeedr);
    
    /* Set pull-up */
    reg_val = readl(gpio_pupdr);
    reg_val &= ~(0x3 << 0);
    reg_val |= (0x1 << 0);
    writel(reg_val, gpio_pupdr);
    
    /* Turn off LED initially */
    led_control(0);
    
    ret = register_chrdev(LED_DRIVER_MAJOR, LED_DEVICE_NAME, &led_fops);
    if (ret < 0)
        return ret;
        
    return 0;
}

static void __exit led_exit(void) {
    iounmap(gpio_moder);
    iounmap(gpio_otyper);
    iounmap(gpio_ospeedr);
    iounmap(gpio_pupdr);
    iounmap(gpio_bsrr);
    unregister_chrdev(LED_DRIVER_MAJOR, LED_DEVICE_NAME);
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Embedded Systems Team");

Driver Testing Application

Application to control the LED driver:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

#define LED_ON 1
#define LED_OFF 0

int main(int argc, char *argv[]) {
    int fd;
    char buffer[2];
    
    if (argc != 3) {
        printf("Usage: %s <device> <state>\\n", argv[0]);
        printf("State: 0 = off, 1 = on\\n");
        return 1;
    }
    
    fd = open(argv[1], O_RDWR);
    if (fd < 0) {
        perror("open");
        return 1;
    }
    
    buffer[0] = atoi(argv[2]);
    write(fd, buffer, 1);
    close(fd);
    
    return 0;
}

Tags: STM32MP157 Linux kernel character device drivers gpio U-Boot

Posted on Thu, 17 Sep 2026 16:09:48 +0000 by shane07