linux內核給了一個spi驅動的實例。
driver/spi/spidev.c
1 spi_driver.c
1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/ioctl.h> 4 #include <linux/fs.h> 5 #include <linux/device.h> 6 #include <linux/err.h> 7 #include <linux/list.h> 8 #include <linux/errno.h> 9 #include <linux/mutex.h> 10 #include <linux/slab.h> 11 #include <linux/compat.h> 12 #include <linux/of.h> 13 #include <linux/of_device.h> 14 15 #include <linux/spi/spi.h> 16 #include <linux/spi/spidev.h> 17 18 #include <asm/uaccess.h> 19 20 #define SPIDEV_MAJOR 153 //spidev主設備號 21 #define N_SPI_MINORS 32 /* ... up to 256 */ 22 static DECLARE_BITMAP(minors, N_SPI_MINORS); //聲明次設備位圖 23 #define SPI_MODE_MASK (SPI_CPHA|SPI_CPOL|SPI_CS_HIGH|SPI_LSB_FIRST|SPI_3WIRE|SPI_LOOP|SPI_NO_CS|SPI_READY) 24 25 struct spidev_data { 26 dev_t devt; //設備號 27 spinlock_t spi_lock; //自旋鎖 28 struct spi_device *spi; //spi設備結構體 29 struct list_head device_entry; 30 struct mutex buf_lock; //互斥鎖 31 unsigned users; //使用者計數 32 u8 *buffer; //緩沖區 33 }; 34 35 static LIST_HEAD(device_list); //聲明spi設備鏈表 36 static DEFINE_MUTEX(device_list_lock); //定義互斥鎖 37 static unsigned bufsiz = 4096; //最大傳輸緩沖區大小 38 module_param(bufsiz, uint, S_IRUGO); 39 MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message"); 40 41 static void spidev_complete(void *arg) 42 { 43 complete(arg); //調用complete 44 } 45 46 static ssize_t spidev_sync(struct spidev_data *spidev, struct spi_message *message) 47 { 48 DECLARE_COMPLETION_ONSTACK(done); 49 int status; 50 51 message->complete = spidev_complete; //設置spi消息的complete方法 回調函數 52 message->context = &done; 53 54 spin_lock_irq(&spidev->spi_lock); 55 if (spidev->spi == NULL) //判斷是否有指定對應的spi設備 56 status = -ESHUTDOWN; 57 else 58 status = spi_async(spidev->spi, message); //spi異步同步 59 spin_unlock_irq(&spidev->spi_lock); 60 61 if (status == 0) { 62 wait_for_completion(&done); //等待傳輸完成 63 status = message->status; //獲取spi消息傳輸事務狀態 64 if (status == 0) 65 status = message->actual_length; //status等於傳輸的實際長度 66 } 67 return status; //返回實際傳輸長度 68 } 69 70 static inline ssize_t spidev_sync_write(struct spidev_data *spidev, size_t len) 71 { 72 struct spi_transfer t = { 73 .tx_buf = spidev->buffer, //發送緩沖區 74 .len = len, //發送數據長度 75 }; 76 struct spi_message m; 77 78 spi_message_init(&m); //初始化spi消息(初始化spi傳遞事務隊列) 79 spi_message_add_tail(&t, &m); //添加spr傳遞到該隊列 80 return spidev_sync(spidev, &m); //同步讀寫 81 } 82 83 static inline ssize_t spidev_sync_read(struct spidev_data *spidev, size_t len) 84 { 85 struct spi_transfer t = { 86 .rx_buf = spidev->buffer, //接收緩沖區 87 .len = len, //接收數據長度 88 }; 89 struct spi_message m; 90 91 spi_message_init(&m); //初始化spi消息(初始化spi傳遞事務隊列) 92 spi_message_add_tail(&t, &m); //添加spr傳遞到該隊列 93 return spidev_sync(spidev, &m); //同步讀寫 94 } 95 96 static ssize_t spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) 97 { 98 struct spidev_data *spidev; 99 ssize_t status = 0; 100 101 if (count > bufsiz) //傳輸數據大於緩沖區容量 102 return -EMSGSIZE; 103 spidev = filp->private_data; //從文件私有數據指針獲取spidev_data 104 mutex_lock(&spidev->buf_lock); //上互斥鎖 105 status = spidev_sync_read(spidev, count); //同步讀,返回傳輸數據長度 106 if (status > 0) { 107 unsigned long missing; //丟失的數據個數 108 missing = copy_to_user(buf, spidev->buffer, status); //內核空間復制到用戶空間 109 if (missing == status) //丟失的數據個數等於要傳輸的數據個數 110 status = -EFAULT; 111 else 112 status = status - missing; //傳輸成功的數據個數 113 } 114 mutex_unlock(&spidev->buf_lock);//解互斥鎖 115 return status; //返回讀取成功的數據個數 116 } 117 118 static ssize_t spidev_write(struct file *filp, const char __user *buf,size_t count, loff_t *f_pos) 119 { 120 struct spidev_data *spidev; 121 ssize_t status = 0; 122 unsigned long missing; 123 124 if (count > bufsiz) //傳輸數據大於緩沖區容量 125 return -EMSGSIZE; 126 spidev = filp->private_data; //從文件私有數據指針獲取spidev_data 127 mutex_lock(&spidev->buf_lock); //上互斥鎖 128 missing = copy_from_user(spidev->buffer, buf, count); //用戶空間復制到內核空間 129 if (missing == 0) { //傳輸失敗個數為0 130 status = spidev_sync_write(spidev, count); //同步寫,返回傳輸數據長度 131 } 132 else 133 status = -EFAULT; 134 mutex_unlock(&spidev->buf_lock);//解互斥鎖 135 return status; //返回寫數據的實際個數 136 } 137 138 static int spidev_message(struct spidev_data *spidev,struct spi_ioc_transfer *u_xfers, unsigned n_xfers) 139 { 140 struct spi_message msg; 141 struct spi_transfer *k_xfers; 142 struct spi_transfer *k_tmp; 143 struct spi_ioc_transfer *u_tmp; 144 unsigned n, total; 145 u8 *buf; 146 int status = -EFAULT; 147 148 spi_message_init(&msg); //初始化spi消息(初始化spi傳遞事務隊列) 149 k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL); //分配spi傳輸指針內存 150 if (k_xfers == NULL) 151 return -ENOMEM; 152 buf = spidev->buffer; //獲取spidev_data的緩沖區 153 total = 0; 154 //n=xfers為spi_ioc_transfer個數,u_tmp = u_xfers為要處理的spi_ioc_transfer指針 155 for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;n;n--, k_tmp++, u_tmp++) { 156 k_tmp->len = u_tmp->len; //設置傳輸信息的長度 157 total += k_tmp->len; //累加傳輸信息的總長度 158 if (total > bufsiz) { //信息量超過bufsiz緩沖區最大容量 159 status = -EMSGSIZE; 160 goto done; 161 } 162 if (u_tmp->rx_buf) { //接收緩沖區指針不為空 163 k_tmp->rx_buf = buf; //緩沖區指向buf 164 if (!access_ok(VERIFY_WRITE, (u8 __user *)(uintptr_t) u_tmp->rx_buf,u_tmp->len)) 165 goto done; 166 } 167 if (u_tmp->tx_buf) { //發送緩沖區指針不為空 168 k_tmp->tx_buf = buf; //緩沖區指針指向buf 169 if (copy_from_user(buf, (const u8 __user *)(uintptr_t) u_tmp->tx_buf,u_tmp->len)) //用戶空間復制數據到buf 170 goto done; 171 } 172 buf += k_tmp->len; //緩沖區指針移動一個傳輸信息的長度 173 k_tmp->cs_change = !!u_tmp->cs_change; //設置cs_change 174 k_tmp->bits_per_word = u_tmp->bits_per_word; //設置bits_per_word 一個字多少位 175 k_tmp->delay_usecs = u_tmp->delay_usecs; //設置delay_usecs 毫秒級延時 176 k_tmp->speed_hz = u_tmp->speed_hz; //設置speed_hz 速率 177 #ifdef VERBOSE 178 dev_dbg(&spidev->spi->dev," xfer len %zd %s%s%s%dbits %u usec %uHz\n", 179 u_tmp->len,u_tmp->rx_buf ? "rx " : "",u_tmp->tx_buf ? "tx " : "",u_tmp->cs_change ? "cs " : "", 180 u_tmp->bits_per_word ? : spidev->spi->bits_per_word,u_tmp->delay_usecs,u_tmp->speed_hz ? : spidev->spi->max_speed_hz); 181 #endif 182 spi_message_add_tail(k_tmp, &msg); //添加spr傳遞到該隊列 183 } 184 //for循環的作用是將spi_ioc_transfer批量轉換為spi傳遞結構體spi_transfer,然后添加進spi傳遞事務隊列 185 status = spidev_sync(spidev, &msg); //同步讀寫 186 if (status < 0) 187 goto done; 188 buf = spidev->buffer; //獲取spidev_data緩沖區指針 189 for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) { //批量從內核空間復制spi_ioc_transfer到用戶空間 190 if (u_tmp->rx_buf) { //判斷是否存在接收緩沖區 191 if (__copy_to_user((u8 __user *)(uintptr_t) u_tmp->rx_buf, buf,u_tmp->len)) { 192 status = -EFAULT; 193 goto done; 194 } 195 } 196 buf += u_tmp->len; //buf指針位置調整指向下一個spi_ioc_transfer 197 } 198 status = total; //status等於實際傳輸的數據長度 199 done: 200 kfree(k_xfers); //釋放k_xfers 201 return status; //返回實際傳輸的數據長度 202 } 203 204 static long spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 205 { 206 int err = 0; 207 int retval = 0; 208 struct spidev_data *spidev; 209 struct spi_device *spi; 210 u32 tmp; 211 unsigned n_ioc; 212 struct spi_ioc_transfer *ioc; 213 214 if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC) //判斷控制命令的類型 215 return -ENOTTY; 216 if (_IOC_DIR(cmd) & _IOC_READ) //判斷控制命令的方向是否為讀read 217 err = !access_ok(VERIFY_WRITE,(void __user *)arg, _IOC_SIZE(cmd)); //判斷傳輸數據大小 218 if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE) //判斷控制命令的方向是否為寫write 219 err = !access_ok(VERIFY_READ,(void __user *)arg, _IOC_SIZE(cmd)); //判斷傳輸數據大小 220 if (err) 221 return -EFAULT; 222 223 spidev = filp->private_data; //從文件私有數據中獲取spidev_data 224 spin_lock_irq(&spidev->spi_lock); //上自旋鎖 225 spi = spi_dev_get(spidev->spi); //獲取spi設備 226 spin_unlock_irq(&spidev->spi_lock); //解自旋鎖 227 if (spi == NULL) //獲取spi設備失敗 228 return -ESHUTDOWN; //則返回錯誤 229 mutex_lock(&spidev->buf_lock); //上互斥鎖 230 231 switch (cmd) { 232 case SPI_IOC_RD_MODE: //設置spi讀模式 (此處原作者的理解與我不同,這里應該是應用程序獲取數據) 233 retval = __put_user(spi->mode & SPI_MODE_MASK,(__u8 __user *)arg); 234 break; 235 case SPI_IOC_RD_LSB_FIRST: //設置spi讀最低有效位 (此處原作者的理解與我不同,這里應該是應用程序獲取數據) 236 retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0,(__u8 __user *)arg); 237 break; 238 case SPI_IOC_RD_BITS_PER_WORD: //設置spi讀每個字含多個個位 (此處原作者的理解與我不同,這里應該是應用程序獲取數據) 239 retval = __put_user(spi->bits_per_word, (__u8 __user *)arg); 240 break; 241 case SPI_IOC_RD_MAX_SPEED_HZ: //設置spi讀最大速率 (此處原作者的理解與我不同,這里應該是應用程序獲取數據) 242 retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg); 243 break; 244 case SPI_IOC_WR_MODE: //設置spi寫模式 245 retval = __get_user(tmp, (u8 __user *)arg); 246 if (retval == 0) { 247 u8 save = spi->mode; //獲取spi設備模式 248 249 if (tmp & ~SPI_MODE_MASK) { 250 retval = -EINVAL; 251 break; 252 } 253 254 tmp |= spi->mode & ~SPI_MODE_MASK; 255 spi->mode = (u8)tmp; 256 retval = spi_setup(spi); //配置spi設備 257 if (retval < 0) 258 spi->mode = save; 259 else 260 dev_dbg(&spi->dev, "spi mode %02x\n", tmp); 261 } 262 break; 263 case SPI_IOC_WR_LSB_FIRST: //設置spi寫最低有效位 264 retval = __get_user(tmp, (__u8 __user *)arg); 265 if (retval == 0) { 266 u8 save = spi->mode; //獲取spi設備模式 267 268 if (tmp) 269 spi->mode |= SPI_LSB_FIRST; 270 else 271 spi->mode &= ~SPI_LSB_FIRST; 272 retval = spi_setup(spi); //配置spi設備 273 if (retval < 0) 274 spi->mode = save; 275 else 276 dev_dbg(&spi->dev, "%csb first\n",tmp ? 'l' : 'm'); 277 } 278 break; 279 case SPI_IOC_WR_BITS_PER_WORD: //設置spi寫每個字含多個個位 280 retval = __get_user(tmp, (__u8 __user *)arg); //用戶空間獲取數據 281 if (retval == 0) { 282 u8 save = spi->bits_per_word; //獲取spi設備 每個字含多少位 283 284 spi->bits_per_word = tmp; //更新新的spi設備 每個字含多少位 285 retval = spi_setup(spi); //配置spi設備 286 if (retval < 0) //配置失敗 287 spi->bits_per_word = save; //還原spi設備 每個字含多少位 288 else 289 dev_dbg(&spi->dev, "%d bits per word\n", tmp); 290 } 291 break; 292 case SPI_IOC_WR_MAX_SPEED_HZ: //設置spi寫最大速率 293 retval = __get_user(tmp, (__u32 __user *)arg); //用戶空間獲取數據 294 if (retval == 0) { 295 u32 save = spi->max_speed_hz; //獲取spi設備最大速率 296 297 spi->max_speed_hz = tmp; //更新新的spi設備最大速率 298 retval = spi_setup(spi); //配置spi設備 299 if (retval < 0) //配置失敗 300 spi->max_speed_hz = save; //還原spi設備最大速率 301 else 302 dev_dbg(&spi->dev, "%d Hz (max)\n", tmp); 303 } 304 break; 305 306 default: 307 //命令必須為寫方向的命令,且傳輸數據必須是SPI_IOC_MESSAGE()修飾的命令 308 if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))|| _IOC_DIR(cmd) != _IOC_WRITE) { 309 retval = -ENOTTY; 310 break; 311 } 312 313 tmp = _IOC_SIZE(cmd); //計算傳輸數據大小 314 if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) { //判斷是否為spi_ioc_transfer對齊 315 retval = -EINVAL; 316 break; 317 } 318 n_ioc = tmp / sizeof(struct spi_ioc_transfer); //計算出spi_ioc_transfer數據的個數 319 if (n_ioc == 0) 320 break; 321 322 ioc = kmalloc(tmp, GFP_KERNEL); //分配spi_ioc_transfer指針ioc內存 323 if (!ioc) { 324 retval = -ENOMEM; 325 break; 326 } 327 if (__copy_from_user(ioc, (void __user *)arg, tmp)) { //從用戶空間復制到內核空間 328 kfree(ioc); //復制失敗則釋放ioc內存 329 retval = -EFAULT; 330 break; 331 } 332 333 retval = spidev_message(spidev, ioc, n_ioc); //spidev消息處理 334 kfree(ioc); //釋放ioc內存 335 break; 336 } 337 338 mutex_unlock(&spidev->buf_lock); //解互斥鎖 339 spi_dev_put(spi); //增加spi設備的引用計數 340 return retval; 341 } 342 343 static int spidev_open(struct inode *inode, struct file *filp) 344 { 345 struct spidev_data *spidev; 346 int status = -ENXIO; 347 348 mutex_lock(&device_list_lock); //上互斥鎖 349 list_for_each_entry(spidev, &device_list, device_entry) { //遍歷device_list 350 if (spidev->devt == inode->i_rdev) { //判斷設備號找到對應的設備 351 status = 0; //設置狀態為0 352 break; 353 } 354 } 355 if (status == 0) { //找得到對應的設備 356 if (!spidev->buffer) { //spidev_data緩沖區為空 357 spidev->buffer = kmalloc(bufsiz, GFP_KERNEL); //則分配內存 358 if (!spidev->buffer) { //還空 359 dev_dbg(&spidev->spi->dev, "open/ENOMEM\n"); //申請內存失敗 360 status = -ENOMEM; 361 } 362 } 363 if (status == 0) { //找得到對應的設備 364 spidev->users++; //spidev_data使用者計數++ 365 filp->private_data = spidev; //spidev_data放在文件的私有數據里 366 nonseekable_open(inode, filp); //設置文件的打開模式(文件讀寫指針不會跟隨讀寫操作移動) 367 } 368 } 369 else 370 pr_debug("spidev: nothing for minor %d\n", iminor(inode)); 371 mutex_unlock(&device_list_lock); //接互斥鎖 372 return status; 373 } 374 375 static int spidev_release(struct inode *inode, struct file *filp) 376 { 377 struct spidev_data *spidev; 378 int status = 0; 379 380 mutex_lock(&device_list_lock); 381 spidev = filp->private_data; //獲取spidev_data 382 filp->private_data = NULL; //清除文件的私有數據指針 383 spidev->users--; //使用者個數-- 384 if (!spidev->users) { //如果使用者個數為0 385 int dofree; 386 kfree(spidev->buffer); //釋放spidev_data的緩沖區內存 387 spidev->buffer = NULL; //清除spidev_data緩沖區指針 388 spin_lock_irq(&spidev->spi_lock); //上自旋鎖 389 dofree = (spidev->spi == NULL); //判斷spi設備是否與spidev_data解綁了 390 spin_unlock_irq(&spidev->spi_lock); //解自旋鎖 391 if (dofree) //沒有捆綁的spi設備 392 kfree(spidev); //則是否spidev_data內存 393 } 394 mutex_unlock(&device_list_lock); 395 return status; 396 } 397 398 static const struct file_operations spidev_fops = { //文件操作函數集 399 .owner = THIS_MODULE, 400 .write = spidev_write, //寫write 401 .read = spidev_read, //讀read 402 .unlocked_ioctl = spidev_ioctl, //控制ioctl 403 .open = spidev_open, //打開open 404 .release = spidev_release, //釋放release 405 .llseek = no_llseek, //文件指針移動 no_llseek表示沒有移動 406 }; 407 408 static struct class *spidev_class; 409 410 static int __devinit spidev_probe(struct spi_device *spi) 411 { 412 struct spidev_data *spidev; 413 int status; 414 unsigned long minor; 415 416 spidev = kzalloc(sizeof(*spidev), GFP_KERNEL); //分配spidev_data內存 417 if (!spidev) 418 return -ENOMEM; 419 spidev->spi = spi; //設置spidev_data->spi(spi設備) 420 spin_lock_init(&spidev->spi_lock); 421 mutex_init(&spidev->buf_lock); 422 INIT_LIST_HEAD(&spidev->device_entry); //初始化spidev_data入口鏈表 423 mutex_lock(&device_list_lock); 424 minor = find_first_zero_bit(minors, N_SPI_MINORS); //查找次設備位圖分配次設備號 425 if (minor < N_SPI_MINORS) { 426 struct device *dev; 427 spidev->devt = MKDEV(SPIDEV_MAJOR, minor); //計算出設備號 428 //創建設備/dev/spidev%d.%d(spidev總線號.片選號) 429 dev = device_create(spidev_class, &spi->dev, spidev->devt,spidev, "spidev%d.%d",spi->master->bus_num, spi->chip_select); 430 status = IS_ERR(dev) ? PTR_ERR(dev) : 0; 431 } 432 else { 433 dev_dbg(&spi->dev, "no minor number available!\n"); 434 status = -ENODEV; 435 } 436 if (status == 0) { //分配設備號成功 437 set_bit(minor, minors); //更新次設備位圖 438 list_add(&spidev->device_entry, &device_list); //添加進設備鏈表 439 } 440 mutex_unlock(&device_list_lock); 441 442 if (status == 0) 443 spi_set_drvdata(spi, spidev); //spi->dev->p->driver_data=spidev 444 else 445 kfree(spidev); 446 447 return status; 448 } 449 450 static int __devexit spidev_remove(struct spi_device *spi) 451 { 452 struct spidev_data *spidev = spi_get_drvdata(spi); //根據spi設備獲取spidev_data 453 spin_lock_irq(&spidev->spi_lock); //上自旋鎖 454 spidev->spi = NULL; //清空spidev_data->spi指針 455 spi_set_drvdata(spi, NULL); //spi->dev->p->driver_data=NULL 456 spin_unlock_irq(&spidev->spi_lock); //解自旋鎖 457 mutex_lock(&device_list_lock); //上互斥鎖 458 list_del(&spidev->device_entry); //刪除spidev_data入口鏈表 459 device_destroy(spidev_class, spidev->devt); //銷毀/dev/spidev%d.%d 460 clear_bit(MINOR(spidev->devt), minors); //清除次設備位圖對應位 461 if (spidev->users == 0) //使用者個數為0 462 kfree(spidev); //釋放spidev_data內存 463 mutex_unlock(&device_list_lock); //解互斥鎖 464 return 0; 465 } 466 467 static struct spi_driver spidev_spi_driver = { //spi設備驅動 468 .driver = { 469 .name = "spidev", 470 .owner = THIS_MODULE, 471 }, 472 .probe = spidev_probe, //spidev的probe方法(當注冊了modalias域為"spidev"的spi設備或板級設備,則會調用probe方法) 473 .remove = __devexit_p(spidev_remove), //spidev的remove方法 474 }; 475 476 static int __init spidev_init(void) //spidev接口初始化 477 { 478 int status; 479 BUILD_BUG_ON(N_SPI_MINORS > 256); 480 //注冊字符設備,主設備號SPIDEV_MAJOR=153,捆綁的設備操作函數集為spidev_fops 481 status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops); 482 if (status < 0) 483 return status; 484 spidev_class = class_create(THIS_MODULE, "spidev"); //創建設備類spidev_class 485 if (IS_ERR(spidev_class)) { 486 unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name); 487 return PTR_ERR(spidev_class); 488 } 489 status = spi_register_driver(&spidev_spi_driver); //注冊spi設備驅動spidev_spi_driver 490 if (status < 0) { 491 class_destroy(spidev_class); 492 unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name); 493 } 494 return status; 495 } 496 module_init(spidev_init); //聲明初始化入口 497 498 static void __exit spidev_exit(void) //spidev接口銷毀 499 { 500 spi_unregister_driver(&spidev_spi_driver); //注銷spi設備驅動spidev_spi_driver 501 class_destroy(spidev_class); //注銷設備類spidev_class 502 unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name); //注銷字符設備 503 } 504 module_exit(spidev_exit); //聲明初始化出口 505 506 MODULE_AUTHOR("Andrea Paterniani, "); 507 MODULE_DESCRIPTION("User mode SPI device interface"); 508 MODULE_LICENSE("GPL"); 509 MODULE_ALIAS("spi:spidev");
2 spi_test.c
1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 11 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 12 13 static void pabort(const char *s) 14 { 15 perror(s); 16 abort(); 17 } 18 19 static const char *device = "/dev/spidev1.1"; 20 static uint8_t mode; 21 static uint8_t bits = 8; 22 static uint32_t speed = 500000; 23 static uint16_t delay; 24 25 static void transfer(int fd) 26 { 27 int ret; 28 uint8_t tx[] = { //要發送的數據數組 29 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 30 0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 31 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 32 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 33 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 34 0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD, 35 0xF0, 0x0D, 36 }; 37 uint8_t rx[ARRAY_SIZE(tx)] = {0, }; //接收的數據數據 38 struct spi_ioc_transfer tr = { //聲明並初始化spi_ioc_transfer結構體 39 .tx_buf = (unsigned long)tx, 40 .rx_buf = (unsigned long)rx, 41 .len = ARRAY_SIZE(tx), 42 .delay_usecs = delay, 43 .speed_hz = speed, 44 .bits_per_word = bits, 45 }; 46 //SPI_IOC_MESSAGE(1)的1表示spi_ioc_transfer的數量 47 ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); //ioctl默認操作,傳輸數據 48 if (ret < 1) 49 pabort("can't send spi message"); 50 51 for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { //打印接收緩沖區 52 if (!(ret % 6)) //6個數據為一簇打印 53 puts(""); 54 printf("%.2X ", rx[ret]); 55 } 56 puts(""); 57 } 58 59 static void print_usage(const char *prog) //參數錯誤則打印幫助信息 60 { 61 printf("Usage: %s [-DsbdlHOLC3]\n", prog); 62 puts(" -D --device device to use (default /dev/spidev1.1)\n" 63 " -s --speed max speed (Hz)\n" 64 " -d --delay delay (usec)\n" 65 " -b --bpw bits per word \n" 66 " -l --loop loopback\n" 67 " -H --cpha clock phase\n" 68 " -O --cpol clock polarity\n" 69 " -L --lsb least significant bit first\n" 70 " -C --cs-high chip select active high\n" 71 " -3 --3wire SI/SO signals shared\n"); 72 exit(1); 73 } 74 75 static void parse_opts(int argc, char *argv[]) 76 { 77 while (1) { 78 static const struct option lopts[] = { //參數命令表 79 { "device", 1, 0, 'D' }, 80 { "speed", 1, 0, 's' }, 81 { "delay", 1, 0, 'd' }, 82 { "bpw", 1, 0, 'b' }, 83 { "loop", 0, 0, 'l' }, 84 { "cpha", 0, 0, 'H' }, 85 { "cpol", 0, 0, 'O' }, 86 { "lsb", 0, 0, 'L' }, 87 { "cs-high", 0, 0, 'C' }, 88 { "3wire", 0, 0, '3' }, 89 { "no-cs", 0, 0, 'N' }, 90 { "ready", 0, 0, 'R' }, 91 { NULL, 0, 0, 0 }, 92 }; 93 int c; 94 95 c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL); 96 97 if (c == -1) 98 break; 99 100 switch (c) { 101 case 'D': //設備名 102 device = optarg; 103 break; 104 case 's': //速率 105 speed = atoi(optarg); 106 break; 107 case 'd': //延時時間 108 delay = atoi(optarg); 109 break; 110 case 'b': //每字含多少位 111 bits = atoi(optarg); 112 break; 113 case 'l': //回送模式 114 mode |= SPI_LOOP; 115 break; 116 case 'H': //時鍾相位 117 mode |= SPI_CPHA; 118 break; 119 case 'O': //時鍾極性 120 mode |= SPI_CPOL; 121 break; 122 case 'L': //lsb 最低有效位 123 mode |= SPI_LSB_FIRST; 124 break; 125 case 'C': //片選高電平 126 mode |= SPI_CS_HIGH; 127 break; 128 case '3': //3線傳輸模式 129 mode |= SPI_3WIRE; 130 break; 131 case 'N': //沒片選 132 mode |= SPI_NO_CS; 133 break; 134 case 'R': //從機拉低電平停止數據傳輸 135 mode |= SPI_READY; 136 break; 137 default: //錯誤的參數 138 print_usage(argv[0]); 139 break; 140 } 141 } 142 } 143 144 int main(int argc, char *argv[]) 145 { 146 int ret = 0; 147 int fd; 148 149 parse_opts(argc, argv); //解析傳遞進來的參數 150 151 fd = open(device, O_RDWR); //打開設備文件 152 if (fd < 0) 153 pabort("can't open device"); 154 155 /* 156 * spi mode //設置spi設備模式 157 */ 158 ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); //寫模式 159 if (ret == -1) 160 pabort("can't set spi mode"); 161 162 ret = ioctl(fd, SPI_IOC_RD_MODE, &mode); //讀模式 163 if (ret == -1) 164 pabort("can't get spi mode"); 165 166 /* 167 * bits per word //設置每個字含多少位 168 */ 169 ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); //寫 每個字含多少位 170 if (ret == -1) 171 pabort("can't set bits per word"); 172 173 ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); //讀 每個字含多少位 174 if (ret == -1) 175 pabort("can't get bits per word"); 176 177 /* 178 * max speed hz //設置速率 179 */ 180 ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); //寫速率 181 if (ret == -1) 182 pabort("can't set max speed hz"); 183 184 ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); //讀速率 185 if (ret == -1) 186 pabort("can't get max speed hz"); 187 //打印模式,每字多少位和速率信息 188 printf("spi mode: %d\n", mode); 189 printf("bits per word: %d\n", bits); 190 printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); 191 192 transfer(fd); //傳輸測試 193 194 close(fd); //關閉設備 195 196 return ret; 197 }
3 ioctl的命令:
SPI_IOC_RD_MODE //讀 模式 SPI_IOC_RD_LSB_FIRST //讀 LSB SPI_IOC_RD_BITS_PER_WORD //讀 每字多少位 SPI_IOC_RD_MAX_SPEED_HZ //讀 最大速率 SPI_IOC_WR_MODE //寫 模式 SPI_IOC_WR_LSB_FIRST //寫 LSB SPI_IOC_WR_BITS_PER_WORD //寫 每字多少位 SPI_IOC_WR_MAX_SPEED_HZ //寫 最大速率 SPI_IOC_MESSAGE(n) //傳輸n個數據包
參考博文:http://dainh.blog.chinaunix.net/uid-26765074-id-3510490.html