AI Vision Solutions &
Embedded Systems Engineering

Controlling Servo Motors on Raspberry Pi 4 via Direct Register Access

raspberry pi 4



In this section, we will explore how to control servo motors on the Raspberry Pi 4 using direct register access, bypassing high-level libraries such as pigpio or wiringPi.



This approach allows for precise timing control and a deeper understanding of how the PWM hardware operates at the register level.

We have the following devices:
Raspberry Pi 4 Model B running Raspberry Pi OS (64-bit)
servo motor WK-P0025

First, let's examine the Raspberry Pi pinout — connector J8:
raspberry pi 4 header pinout


Connect the servo motor according to the following wiring diagram:
• Servo motor GND (black) → J8.34 (GND)
• Servo motor VCC (red) → J8.2 (5V)
• Servo motor signal (white) → J8.32 (GPIO12)

To control the servo motor, we need a PWM signal with a 20 ms period.
Duty cycle 1ms: 0 degree
Duty cycle 1.5ms: 90 degree
Duty cycle 2ms: 180 degree


servo motor schema


Next, we proceed to write a simple C program to control the servo motor.

1) We will obtain access to the physical memory of the device 

if ((mem_fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
   perror("can't open /dev/mem");
   return -1;
}


2) We will map the control register regions into the application's virtual memory space.
For this, we need the following:

#define GPIO_BASE 0xFE200000
#define PWM_BASE 0xFE20C000

gpio_map = mmap(NULL, BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, GPIO_BASE);
pwm_map = mmap(NULL, BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, PWM_BASE);

gpio = (volatile uint32_t *)gpio_map;
pwm = (volatile uint32_t *)pwm_map;



3) Configure GPIO12 to use Alternate Function 0 (PWM)

#define GPFSEL1 (0x04 / 4)
gpio[GPFSEL1] &= ~(7 << 6); // clear bits
gpio[GPFSEL1] |= (4 << 6); // ALT0 = 100 (PWM0)



4) Enable PWM on GPIO12

#define PWM_RNG1 (0x10 / 4)
#define PWM_DAT1 (0x14 / 4)

// pwm settings
pwm[PWM_RNG1] = 1000000; // T=20ms
pwm[PWM_DAT1] = 50000; // 1ms
pwm[PWM_CTL] = 0x81; // PWEN1 | MSEN1



5) We will loop to move the servo horn from 0° to 180°
while (1){
   pwm[PWM_DAT1] = 50000; // 1ms
   sleep(2);
   pwm[PWM_DAT1] = 100000; // 2ms
  sleep(2);
}


Note: In newer versions of Raspberry Pi OS, to enable PWM, you need to open /boot/firmware/config.txt and add the following at the end:
dtoverlay=pwm,pin=12,func=4

The complete source code can be obtained here

© 2019-2026. ATEH.tech — Engineering Team
AI Vision Solutions &
Embedded Systems Engineering

All rights reserved.
All trademarks are the property of their respective owners.

Georgia, Tbilisi
+995 (591) 93-83-18
[email protected]