콘텐츠로 바로가기

now0930 일지

이런저런 생각

  • 홈
  • 비공개
  • 강좌
  • 잔여 작업 조회
  • 위치

timer 실습

kernel timer를 실습했다. callback 함수 argrument로 timer를 가지고 있는 구조체 데이터를 전달할 수 있다. work queue와 같은 방식이다. 커널 특정 버전부터 이런 식으로 변경되었는 듯 하다. 타이머가 만료되면 다시 등록하도록 했다.

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>     //GPIO


#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/fcntl.h>

#include <linux/timer.h>
#include <linux/jiffies.h>

#define GPIO_10_OUT (10)
#define DEVICE_DATA_MAX 256

unsigned int GPIO_irqNumber;

/*\uc0ac\uc6a9\uc790 \ub370\uc774\ud130 \ubd80\ubd84*/
static struct my_device_data{
	struct cdev cdev;
	int index;
	char my_string[DEVICE_DATA_MAX];
	struct timer_list simple_timer;
} my_data1;


void timer_action_fn(struct timer_list *t);

void timer_action_fn(struct timer_list *t)
{
	struct my_device_data *ptr1;
	pr_info("%ld: timer function was activated\n", jiffies);
	ptr1=from_timer(ptr1, t, simple_timer);
	ptr1->index++;
	pr_info("index is %d\n", ptr1->index);
	mod_timer(&my_data1.simple_timer, jiffies+msecs_to_jiffies(1000));


}


static int init_timer(void){
	timer_setup(&my_data1.simple_timer, timer_action_fn, 0);
	pr_info("%ld: timer was setup\n", jiffies);
	mod_timer(&my_data1.simple_timer, jiffies+msecs_to_jiffies(1000));
	return 0;

}

static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
{
	/*Scheduling work queue*/
	return IRQ_HANDLED;

}


//device driver \uc791\uc131 \ubd80\ubd84.
/*************\ub4dc\ub77c\uc774\ubc84 \ud568\uc218 ******************/
static int mydriver_open(struct inode *inode, struct file *file);
static int mydriver_release(struct inode *inode, struct file *file);
static ssize_t mydriver_read(struct file *flip,
		char *buf, size_t len, loff_t *off);
static ssize_t mydriver_write(struct file *flip,
		const char *buf, size_t len, loff_t *off);
/********************************************/



//file operation structure

static struct file_operations fops = 
{
	.owner = THIS_MODULE,
	.read = mydriver_read,
	.write = mydriver_write,
	.open = mydriver_open,
	.release = mydriver_release,
};

static int mydriver_open(struct inode *inode, struct file *file)
{
	pr_info("Deviced file was opend.\n");
	return 0;

}

static int mydriver_release(struct inode *inode, struct file *file)
{
	pr_info("Deviced file was closed.\n");
	return 0;
}


static int mydriver_read(struct file *file,
		char *buf, size_t len, loff_t *off)
{
	pr_info("read\n");
	return 0;
}


static int mydriver_write(struct file *flip,
		const char *buf, size_t len, loff_t *off)
{
	return 0;

}

dev_t dev = 0;
static struct cdev my_cdev;
static struct class *dev_class;
static int __init init_hw(void)
{
	//\ub514\ubc14\uc774\uc2a4 \ub4f1\ub85d
	if(( alloc_chrdev_region(&dev, 0, 1, "test_device") < 0))
	{
		pr_err("[!]character device was not allocated\n");
		goto r_unreg;

	}
	pr_info("[=]%d-%d, was allocated\n", MAJOR(dev), MINOR(dev));


	//\ucd08\uae30\ud654
	cdev_init(&my_cdev, &fops);
	pr_info("[=]driver was initialized\n");


	//\uc2dc\uc2a4\ud15c\uc5d0 \ucd94\uac00
	if((cdev_add(&my_cdev, dev, 1)) < 0)
	{
		pr_err("[!]cannot add device to kernel\n");
		goto r_del;

	}


	//class \ub9cc\ub4e6.
	if((dev_class=class_create(THIS_MODULE, "my_class")) == NULL)
	{
		pr_err("[!]cannot add class\n");
		goto r_class;
	}


	if((device_create(dev_class, NULL, dev, NULL, "my_device")) == NULL)
	{

		pr_err("[!]cannot create device\n");
		goto r_device;
	}


	//gpio 10\ubc88\uc744 \uc0ac\uc6a9.
	//export\ud558\uc5ec \uac04\ub2e8\ud788 \uc0ac\uc6a9.
	//\uc785\ub825\uc740 \uac12\uc744 \uc368 \ub123\uc744 \uc218 \uc5c6\uc74c. \ucd9c\ub825\uc73c\ub85c \uc124\uc815.
	GPIO_irqNumber = gpio_to_irq(GPIO_10_OUT);
	pr_info("[=]irq %d was assinged\n",GPIO_irqNumber);

	//interrupt \ub4f1\ub85d \ud544\uc694
	if (request_irq(GPIO_irqNumber,
				(void*)gpio_irq_handler,
				IRQF_TRIGGER_RISING,
				"my_device",
				NULL))
	{
		pr_err("[!]my_device: cannot register IRQ\n");
		goto r_gpio;
	}
	pr_info("[=]module was installed\n");

	//timer setup
	init_timer();
	return 0;
r_gpio:
	gpio_free(GPIO_10_OUT);
r_device:
	device_destroy(dev_class,dev);

r_class:
	class_destroy(dev_class);
r_del:
	cdev_del(&my_cdev);

r_unreg:
	unregister_chrdev_region(dev,1);

	return -1;
}

static void __exit exit_hw(void) {
	free_irq(GPIO_irqNumber, NULL);
	gpio_free(GPIO_10_OUT);
	//flush_work(struct work_struct *work);
	device_destroy(dev_class,dev);
	//class_unregister(dev_class);
	class_destroy(dev_class);
	cdev_del(&my_cdev);
	unregister_chrdev_region(dev,1);
	//timer delete
	del_timer(&my_data1.simple_timer);
	printk(KERN_INFO "module was removed\n");
}


module_init(init_hw);
module_exit(exit_hw);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("noname");
MODULE_DESCRIPTION("Hello, world!");
[146685.757495] [=]236-0, was allocated
[146685.757504] [=]driver was initialized
[146685.757960] [=]irq 54 was assinged
[146685.757984] [=]module was installed
[146685.757991] 14638325: timer was setup
[146686.818385] 14638432: timer function was activated
[146686.818398] index is 1
[146687.858398] 14638536: timer function was activated
[146687.858402] index is 2
[146688.898415] 14638640: timer function was activated
[146688.898428] index is 3
[146689.938432] 14638744: timer function was activated
[146689.938445] index is 4
[146690.978452] 14638848: timer function was activated
[146690.978457] index is 5
[146692.018469] 14638952: timer function was activated
[146692.018483] index is 6
[146693.058494] 14639056: timer function was activated
[146693.058500] index is 7
[146694.098512] 14639160: timer function was activated
[146694.098548] index is 8
[146695.138529] 14639264: timer function was activated
[146695.138563] index is 9
[146696.178545] 14639368: timer function was activated
[146696.178573] index is 10
[146697.218575] 14639472: timer function was activated
[146697.218607] index is 11
[146698.258571] 14639576: timer function was activated
[146698.258587] index is 12
https://c2plabs.com/blog/2019/06/09/linux-kernel-timer-usage-example-simple-module/

https://embetronicx.com/tutorials/linux/device-drivers/using-kernel-timer-in-linux-device-driver/

https://stackoverflow.com/questions/14953871/how-to-pass-custom-argument-to-linux-timers-function

이 글 공유하기:

  • Tweet
발행일 2021-07-21글쓴이 이대원
카테고리 생활코딩 태그 linux, raspberry, timer, 임베디드 리눅스

댓글 남기기응답 취소

이 사이트는 Akismet을 사용하여 스팸을 줄입니다. 댓글 데이터가 어떻게 처리되는지 알아보세요.

글 내비게이션

이전 글

workqueue 실습

다음 글

spinlock, mutex 실습

2025 5월
일 월 화 수 목 금 토
 123
45678910
11121314151617
18192021222324
25262728293031
4월    

최신 글

  • common mode, differential mode 2025-05-11
  • signal conditioner, 신호 처리기 2025-05-10
  • strain gage 2025-05-09
  • 칼만 필터 2025-05-01
  • positioner(I/P) 2025-04-26

카테고리

  • 산업계측제어기술사
  • 삶 자국
    • 책과 영화
    • 투자
  • 생활코딩
    • LEGO
    • ROS
    • tensorflow
  • 전기기사
  • 피아노 악보

메타

  • 로그인
  • 엔트리 피드
  • 댓글 피드
  • WordPress.org

페이지

  • 소개
  • 잔여 작업 조회
    • 작업 추가
    • 작업의 사진 조회
    • 작업 수정 페이지
  • 사진
    • GPS 입력된 사진
    • 사진 조회
  • 위치
    • 하기 휴가 방문지
    • 해외 출장

태그

android bash c docker driver FSM gps java kernel LEGO linux mysql network program opcua open62541 plc programmers python raspberry reinforcementLearning ros state space system program tensorflow transfer function 경제 미국 민수 삼국지 세계사 실기 에너지 역사 유전자 일본 임베디드 리눅스 전기기사 조선 중국 채윤 코딩 테스트 통계 한국사 한국어

팔로우하세요

  • Facebook
now0930 일지
WordPress로 제작.
 

댓글 로드중...