RaspberryPi/DeviceDriver

Raspberry Pi – Linux Device Driver 만들어 보기-6 ( PWM Driver )

변화의 물결 2022. 11. 16. 15:07

 

 

안녕하세요.

 

 이번 내용은 기존의 GPIO에서 발전된 PWM 기능을 사용해보려고 합니다. 예전 내용에도 PWM 제어가 있지만, Driver 차원이 아니라, 응용프로그램 단에서 사용해본 것이었습니다. PWM의 경우에도 하드웨어서 지원하느냐, 소프트웨어상 구현하느냐에 따라서 주기 등 차이가 발생하기도 합니다. 여기서는 하드웨어에서 PWM 지원해주는 핀을 이용해서 작동시키는 것을 테스트합니다.


1. 사전 준비

  - 기존의 GPIO4 내용을 복사해서 사용합니다.

  

 - Makefile 파일에서 파일 수정

pi@raspberrypi:~/DriverStudy/day6_pwm $ vim Makefile

2. 소스 수정

1) 소스 수정에 필요한 PWM 함수 확인

  (1) struct pwm_device * pwm_request ( int pwm, const char * label);  // PWM 장비 요청

    - pwm : PWM 장비 인덱스(PWM 하드웨어 인덱스 라즈베리파이에서는 pwm0과 pwm1로 2개 제공해주고 있습니다.)

     - label : 사용자 정의 이름 지정

     - Returns : pwm 장치의 포인터

     - 이 함수 설명에 보면 deprecated로 나오고, pwm_get을 사용하라고 합니다.

  

  (2) int pwm_config ( struct pwm_device * pwm, int duty_ns, int period_ns);  // PWM 설정 값을 변경

     - pwm :   PWM 장비 인덱스

     - duty_ns :  On 시간(켜져 있는 시간), nanoseconds

     - period_ns :   한 사이클 간 시간(한 주기), nanoseconds

     - Returns :  0은 성공, 음수는 실패

 

  (3) int pwm_enable (struct pwm_device * pwm);  // PWM 출력하거나 켜기

      - Returns :  0은 성공, 음수는 실패

 

  (4) void pwm_disable (struct pwm_device * pwm);  // PWM 출력하거나 끄기

     - Returns :  값없음

 

  (5) void pwm_free (struct pwm_device * pwm);  // PWM 장치 해제

     - Returns :  값없음

     - 이 함수 설명에 보면 deprecated로 나오고, pwm_put을 사용하라고 합니다.

 

 

2) pwm_driver.c 수정

  - 간단한 설명 부분, 장치 파일명, 헤더 파일을 수정합니다.

#include <linux/pwm.h>  // <- #include <linux/gpio.h>
MODULE_DESCRIPTION(“A Simple driver to access the Hardware PWM PIN”);
// ... 기존 코드 중간 생략

#define DRIVER_NAME  “testPWM_driver”

//전역 변수로 PWM 설정에 필요한 변수를 선언해줍니다.
//Variables for PWM
struct pwm_device *pwm0 = NULL;
u32 pwm_on_time = 500000000;
...

  

  - write() 함수 수정

 

// 기존 switch(value) ... 삭제

 

// Set PWM on Time 문자열을 1 ~9까지 받아서 100ms ~ 900ms의 On 시간을 만들기 위한 로직

// 0 = 0x30, 1 = 0x31... : = 0x3A

if(value < ‘1’ || value > ‘:’)
           printk(“Invalid Value\n”);
else
           pwm_config(pwm0, 100000000 * (value – ‘0’), 1000000000);

 - __init ModuleInit(void)  함수 수정

// 기존 GPIO 소스 삭제
// 추가 내용
  pwm0 = pwm_request(0, “rpi-pwm0”);

if(pwm0 == NULL) {
           printk(“Could not get PWM0!\n”);
           goto AddError;
}

pwm_config(pwm0, pwm_on_time, 1000000000);
pwm_enable(pwm0);

 

 -  read() 함수 제거

  // file_operations 의  .read = driver_read 부분 삭제

  

 - __exit ModuleExit(void)  함수 수정

// 기존 소스 삭제
// gpio_set_value(14, 0 );  // 삭제...

// 추가 내용
pwm_disable(pwm0);
pwm_free(pwm0);

 3. 컴파일 및 실행

  - 컴파일 문제가 없이 진행했다면 ko 파일이 만들어집니다. 그리고 insmod 하면 아래와 같이 에러가 나타날 수 있습니다.

  이유는 하드웨어 핀에 대한 기본 설정 외 설정이 필요하기 때문입니다. 디바이스 트리를 사용해서 설정을 해주어야 합니다. 디바이스 트리는 하드웨어 구성을 노드들의 계층으로 표현하는 것이라고 합니다. 그래서 인자 값을  변경하려면 별도로 추가적인 공부가 필요해 보입니다. 상세한 내용은 하단의 “13 디바이스 트리, 오버레이, 파라미터” 사이트를 참고하시면 도움이 될 거라 생각됩니다.

 

 

  - 추가 핀 설정(에러 해결 방법)

pi@raspberrypi:~/DriverStudy/day6_pwm $ sudo vim /boot/config.txt

 

dtoverlay=pwm-2chan,pin=12,func=4,pin2=13,func2=4

 - 입력 내용을 저장하고 재부팅을 한번 해줍니다.

 

pi@raspberrypi:~/DriverStudy/day6_pwm $ sudo insmod pwm_driver.ko
pi@raspberrypi:~/DriverStudy/day6_pwm $ sudo chmod 666 /dev/testPWM_driver

//1 : On Time 100ms  9 : On Time 900ms
pi@raspberrypi:~/DriverStudy/day6_pwm $ echo 1 > /dev/testPWM_driver
pi@raspberrypi:~/DriverStudy/day6_pwm $ echo 9 > /dev/testPWM_driver

 

 

 4.  동작확인

  - echo 1, echo 9 일 때  On시간이 다른 것을 확인할 수 있습니다.

 

  마지막으로 이전 내용을 소스파일에 추가하면서 수정하고 있지만, 글로 보기에는 소스를 중간에 삭제하고 추가하고 있기 때문에 따라 하기가 힘들 수 있습니다. 그래서 이전 파일과 현재 소스파일을 비교하면서 보시면 이해가 조금 쉽지 않을까 합니다. 

 

 감사합니다.

 

 

<참고사이트>

1. Let's code a Linux Driver - 6: PWM Driver

https://www.youtube.com/watch?v=yLm4EDVNceo&list=PLCGpd0Do5-I3b5TtyqeF1UdyD4C-S-dMa&index=7

2. Raspberry Pi Pinout

https://pinout.xyz/

3. Chapter 13. Pulse-Width Modulation (PWM)

https://linuxtv.org/downloads/v4l-dvb-internals/device-drivers/API-pwm-config.html

4. 아스키코드

https://namu.wiki/w/%EC%95%84%EC%8A%A4%ED%82%A4%20%EC%BD%94%EB%93%9C 

5. 13. 디바이스 트리, 오버레이, 파라미터

https://wikidocs.net/3205   

day6_pwm.zip
0.00MB