天天看點

利用GPIO自定協定完成資料傳輸

數模轉換器DAC081S101是一款8位數字到模拟的微小功耗的轉換器,通過對DAC子產品中8位資料寄存器的控制來實作對DA子產品功率的控制。

DAC子產品的電路示意圖如下圖:

利用GPIO自定協定完成資料傳輸
利用GPIO自定協定完成資料傳輸

DAC晶片中資料傳輸具有自己的傳輸協定。由一個時鐘信号線,一個使能線SYNC,一個資料線來完成資料的正确傳輸。

利用GPIO自定協定完成資料傳輸
利用GPIO自定協定完成資料傳輸

時鐘周期信号的最大周期可達到30MHZ,在SYNC使能時,以每個周期的下降沿取資料線上的資料,高電平=1 低電平=0。DAC的模式位2位,資料位為8位。以16個周期為一完整資料傳輸周期。總工16位資料,前兩位和後四位沒有意義。

利用GPIO自定協定完成資料傳輸

現在通過ARM上的GPIO引腳,模仿時鐘信号和使能信号來完成資料的傳輸。閑話少說,直接上驅動代碼:

/************************************************************************************************/
/* PROJECT:  				AT91SAM9260 DAC DRIVER  for Linux						            */
/* DATE:					2017-09-06															*/
/* author:					fluency									  							*/
/*																								*/
/************************************************************************************************/
#include 
   
    
#include 
    
     
#include 
     
      
#include 
      
           //包含管腳操作的相關函數
#include 
       
         //包含建立裝置檔案的相關函數 #include 
        
          //子產品加載頭檔案 #include 
         
           //核心頭檔案 #include 
          
            //核心初始化和退出函數 #include 
           
             //uint8_t 的頭檔案 #include 
            
              // udelay 的頭檔案 MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("DAC_driver for AT91SAM9260"); #define DAC_MAJOR 233 #define DAC_MINOR 0 #define DAC_NAME "dac_dev" #define DAC_SCLK AT91_PIN_PA4 #define DAC_SYNC AT91_PIN_PA5 #define DAC_DATA AT91_PIN_PA6 #define DELAY (1) #define DELAYTEST 500 static int debug = 1; #define DBG(format, args...) \ do { \ if (debug >= 1) \ printk(format, ##args); \ } while (0) static int dac_drv_release(struct inode *inode,struct file *file) { DBG("dac driver release!\n"); return 0; } //=================================================== // 初始化GPIO 端口方向 //=================================================== void init_DAC_port(void) { printk("init_dac_driver\r\n"); //clk引腳 設定為外部輸出 初始為低 v16 at91_set_GPIO_periph(DAC_SCLK, 1); at91_set_gpio_output(DAC_SCLK, 0); //sync引腳 設定為外部輸出 初始為高 v15 at91_set_GPIO_periph(DAC_SYNC, 1); at91_set_gpio_output(DAC_SYNC, 1); //資料引腳 設定為外部輸出 初始為0 v14 at91_set_GPIO_periph(DAC_DATA, 1); at91_set_gpio_output(DAC_DATA, 0); //調試引腳 v13 at91_set_GPIO_periph(AT91_PIN_PC11, 1); at91_set_gpio_output(AT91_PIN_PC11, 1); } //========================================================= // .open 具體執行函數 //========================================================= static int dac_open(struct inode *inode,struct file *file) { printk("dac dac_open\r\n"); return 0; } //============================================================================ // .unlocked_ioctl 具體執行函數 // 參數2 cmd : 具體指令類型 // 參數3 arg : 具體資料類型 //============================================================================ static long dac_ioctl(struct file * file,unsigned int cmd,unsigned long arg) { int i; uint8_t data; printk("cmd==%d arg==%ld\r\n", cmd, arg); data = ( uint8_t)arg; printk("data==0x%02x\r\n", data); at91_set_gpio_value(DAC_SCLK, 0); //clk 拉低 at91_set_gpio_value(DAC_SYNC, 1); //sync 拉高 //sync 拉低 資料傳輸開始标志 at91_set_gpio_value(DAC_SYNC, 0); //sync 拉低 //時鐘 at91_set_gpio_value(DAC_SCLK, 1); //clk 拉高 udelay(DELAY); at91_set_gpio_value(DAC_SCLK, 0); //clk 拉低 udelay(DELAY); at91_set_gpio_value(DAC_SCLK, 1); //clk 拉高 udelay(DELAY); at91_set_gpio_value(DAC_SCLK, 0); //clk 拉低 udelay(DELAY); //寫模式 00 at91_set_gpio_value(DAC_SCLK, 1); //clk 拉高 at91_set_gpio_value(DAC_DATA, 0); //data 0 udelay(DELAY); at91_set_gpio_value(DAC_SCLK, 0); //clk 拉低 udelay(DELAY); at91_set_gpio_value(DAC_SCLK, 1); //clk 拉高 at91_set_gpio_value(DAC_DATA, 0); //data 0 udelay(DELAY); at91_set_gpio_value(DAC_SCLK, 0); //clk 拉低 udelay(DELAY); for (i = 7; i >= 0; i--) { at91_set_gpio_value(DAC_SCLK, 1); //clk 拉高 if ((data >> i) & 0x1) //先寫高位 at91_set_gpio_value(DAC_DATA, 1); //data 1 else at91_set_gpio_value(DAC_DATA, 0); //data 0 udelay(DELAY); at91_set_gpio_value(DAC_SCLK, 0); //clk 拉低 udelay(DELAY); } at91_set_gpio_value(DAC_SCLK, 1); //clk 拉高 at91_set_gpio_value(DAC_DATA, 0); //資料 拉低 讓資料位保持是0 udelay(DELAY); at91_set_gpio_value(DAC_SCLK, 0); //clk 拉低 udelay(DELAY); at91_set_gpio_value(DAC_SCLK, 1); //clk 拉高 udelay(DELAY); at91_set_gpio_value(DAC_SCLK, 0); //clk 拉低 udelay(DELAY); at91_set_gpio_value(DAC_SCLK, 1); //clk 拉高 udelay(DELAY); at91_set_gpio_value(DAC_SCLK, 0); //clk 拉低 udelay(DELAY); at91_set_gpio_value(DAC_SCLK, 1); //clk 拉高 udelay(DELAY); at91_set_gpio_value(DAC_SCLK, 0); //clk 拉低 //sync 拉高 資料傳輸結束标志 at91_set_gpio_value(DAC_SYNC, 1); //sync 拉高 return 0; } //======================================================== //定義file_operations 結構體 //======================================================== static struct file_operations io_drv_fops={ .owner = THIS_MODULE, .open = dac_open, .unlocked_ioctl = dac_ioctl, .release = dac_drv_release, }; //======================================================================================================= // 聲明裝置及注冊 //======================================================================================================= struct cdev *my_cdev; struct class *my_class; static int __init dac_drv_init(void) { int err, devno = MKDEV(DAC_MAJOR, DAC_MINOR); //将主裝置号與次裝置号轉換成dev_t類型 my_cdev = cdev_alloc(); //申請一個cdev記憶體 cdev_init(my_cdev, &io_drv_fops); //初始化cdev成員,建立cdev與file_operations之間的連接配接 my_cdev->owner = THIS_MODULE; err = cdev_add(my_cdev, devno, 1); //添加字元裝置 if (err != 0) { printk("sleep dac device register failed!\n"); } my_class = class_create(THIS_MODULE, "sleep_class"); //為此裝置建立一個類 if(IS_ERR(my_class)) { printk("Err: failed in creating class.\n"); return -1; } init_DAC_port(); //IO 初始化 device_create(my_class, NULL, devno, NULL, DAC_NAME "%d", DAC_MINOR ); //注冊字元裝置 return 0; } //======================================================== // 登出裝置 //======================================================== static void __exit dac_drv_exit(void) { cdev_del(my_cdev); device_destroy(my_class, MKDEV(DAC_MAJOR, DAC_MINOR)); class_destroy(my_class); } module_init(dac_drv_init); //注冊裝置 module_exit(dac_drv_exit); //登出裝置 
            
           
          
         
        
       
      
     
    
   
           

使用Logic分析儀來抓取模仿的信号圖:

利用GPIO自定協定完成資料傳輸
利用GPIO自定協定完成資料傳輸

文筆很差,望各位遊客見諒!

繼續閱讀