在S3C6410開發板上的LED驅動程序

這兩天寫了個LED驅動程序,網上也看了好多的帖子。

開始思路很清晰了,就是先看電路圖,發現LED燈是接在GPM埠上的,

然後看S3C6410數據手冊,先向GPMCON口寫命令字,讓GPM0-5設置為輸出,再向GPMDAT口寫數據字,在GPM0-5引腳拉低或拉高電平,

從而控制LED的亮滅。

1、電路圖

很顯然LED燈是接在GPM口引腳下面的

2、數據手冊

3、LED驅動程序

[cpp] view plaincopy

  1. #include<linux/module.h>
  2. #include<linux/kernel.h>
  3. #include<linux/fs.h>
  4. #include<linux/uaccess.h>/*copy_to_user,copy_from_user*/
  5. #include<linux/io.h>/*inl(),outl()*/
  6. #include<linux/miscdevice.h>
  7. #include<linux/pci.h>
  8. staticlongS3C64XX_GPMCON=0xF4500820;/*這裡是虛擬地址,物理地址可以再S3C6410數據手冊上找到。也可以根據物理地址,ioremap()獲得虛擬地址。*/
  9. staticlongS3C64XX_GPMDAT=0xF4500824;
  10. #defineLED_MAJOR240/*主設備號*/
  11. intled_open(structinode*inode,structfile*file)
  12. {
  13. unsignedtmp;
  14. tmp=inl(S3C64XX_GPMCON);
  15. printk("thepreGPMCONis%x",tmp);
  16. tmp=inl(S3C64XX_GPMDAT);
  17. printk("thepreGPMDATis%x",tmp);
  18. outl(0x00111111,S3C64XX_GPMCON);/*向GPMCON命令埠寫命令字,設置GPM0-5為output口*/
  19. printk("#############open#############");
  20. return0;
  21. }
  22. staticssize_tled_read(structfile*file,char__user*buf,size_tcount,loff_t*f_pos)
  23. {
  24. unsignedtmp=inl(S3C64XX_GPMDAT);
  25. intnum=copy_to_user(buf,&tmp,count);
  26. if(num==0)
  27. printk("copysuccessfully");
  28. elseprintk("sorrycopyfailly");
  29. printk("theGPMDATis%x.",tmp);
  30. returncount;
  31. }
  32. staticssize_tled_write(structfile*file,constchar__user*buf,size_tcount,loff_t*f_pos)/*我是通過write()來控制LED燈的,也可以通過ioctl()來控制*/
  33. {
  34. charkbuf[10];
  35. printk("###########write###########");
  36. intnum=copy_from_user(kbuf,buf,count);
  37. if(num==0)
  38. printk("copysuccessfully");
  39. elseprintk("sorrycopyfailly");
  40. printk("##thekbufis%c",kbuf[0]);
  41. switch(kbuf[0])
  42. {
  43. case0://off
  44. outl(0xff,S3C64XX_GPMDAT);/*拉高GPMDAT[0:5]的引腳,使LED燈滅,因為LED是低電平有電流通過*/
  45. break;
  46. case1://on
  47. outl(0x00,S3C64XX_GPMDAT);/*拉低GPMDAT[0:5]的引腳,使LED燈亮*/
  48. break;
  49. default:
  50. break;
  51. }
  52. returncount;
  53. }
  54. intled_release(structinode*inode,structfile*file)
  55. {
  56. printk("#######release##########");
  57. return0;
  58. }
  59. structfile_operationsled_fops={
  60. .owner=THIS_MODULE,
  61. .open=led_open,
  62. .read=led_read,
  63. .write=led_write,
  64. .release=led_release,
  65. };
  66. int__initled_init(void)
  67. {
  68. intrc;
  69. printk("Testleddev
    ");
  70. rc=register_chrdev(LED_MAJOR,"led",&led_fops);
  71. if(rc<0)
  72. {
  73. printk("register%schardeverror
    ","led");
  74. return-1;
  75. }
  76. printk("OK!
    ");
  77. return0;
  78. }
  79. void__exitled_exit(void)
  80. {
  81. unregister_chrdev(LED_MAJOR,"led");
  82. printk("moduleexit
    ");
  83. }
  84. module_init(led_init);
  85. module_exit(led_exit);

寫好源碼後,寫Makefile

[cpp] view plaincopy

  1. obj-m:=led_driver.o
  2. KDIR:=/home/tmp/linux2.6.28
  3. all:
  4. make-C$(KDIR)M=$(shellpwd)modulesCROSS_COMPILE=/usr/local/arm/4.4.1/bin/arm-linux-

/*之前make,出現一些問題,比如說缺少什麼頭文件啦之類,原來是沒有建立內核樹,到內核源碼目錄裡面make一下就好了*/

寫好驅動源代碼和Makefile文件後就在本目錄下make

之後生成了led_driver.ko文件,下載到開發板上

4、測試驅動程序

[cpp] view plaincopy

  1. #include<stdio.h>
  2. #include<sys/types.h>
  3. #include<sys/stat.h>
  4. #include<fcntl.h>
  5. /*#include<unistd.h>*/
  6. intmain()
  7. {
  8. printf("helloleddevice.");
  9. charbuf[10]={0,1,0,1};
  10. intfd=open("/dev/led",2,0777);
  11. if(fd<0){
  12. printf("can"topenleddevice");
  13. return-1;
  14. }
  15. printf("opentheleddevicesuccessfully.");
  16. while(1)
  17. {
  18. intnum=write(fd,&buf[0],1);
  19. if(num<0)
  20. printf("wesettheledfailly.");
  21. elseprintf("wesettheledoff");
  22. sleep(1);
  23. write(fd,&buf[1],1);
  24. printf("wesettheledon");
  25. sleep(1);
  26. }
  27. close(fd);
  28. printf("byeleddevice.");
  29. return0;
  30. }

arm-linux-gcc -o led_test.o led_test.c

編譯好後,把led_test.o文件下載到開發板上

5、具體操作步驟

本人的OK6410開發板之前已裝好linux-2.6.18內核的Linux系統,然後輸shell命令

insmod led_driver.ko //載入led_driver.ko驅動到內核

mknod /dev/led c 240 0 //把led設備文件掛載到/dev/led上,c 代表字元設備 ,240 是主設備號 , 0 是次設備號

./led_test.o //啟動測試程序,點亮LED燈

注意:

在PC機上寫ARM開發板的驅動程序,需要在PC(俗稱上位機)上配置交叉編譯工具鏈 arm-linux-

開始想不通過驅動程序,通過iopl(3);提升許可權,直接操作硬體的,發現在ARM開發板上不能這麼做。

原來以為只能寫驅動程序的方式控制寄存器的,後來發現,mmap()那個「/dev/mem」文件系統也可以的。

開始在開發板上調試,cat /var/log/messages 查看printk的輸出,發現什麼也沒有,原來需要輸入shell命令 klogd 來開啟日誌功能。

祝大家在開發板上玩的愉快。


推薦閱讀:

製作一款Arduino酒精檢測儀的設計
使用Arduino+MPU6050感測器DIY傾角儀
Arduino UNO開發板硬體設計全解析

TAG:程序 | 開發板 | 驅動程序 |