Firefly开源社区

12
发表新贴
打印 上一主题 下一主题

spi驱动初试,在linux下实现的spiflash驱动

433

积分

3

威望

0

贡献

技术达人

Rank: 2

积分
433

spi驱动初试,在linux下实现的spiflash驱动

发表于 2017-7-12 14:28:20      浏览:20515 | 回复:15        打印      只看该作者   [复制链接] 楼主
rk3288上还留有一个可以外接设备的spi0,所以我使用的是spi0,设备树文件如下,设备树中我没有指定CPOL和CPHA,在probe里手动赋值的

  1. static int flash_spi_probe(struct spi_device *spi)
  2. {
  3.         struct spidev_data        *spidev;
  4.         struct device_node  *np = spi->dev.of_node;   /*Get device tree node*/
  5.         int                                         status;
  6.         unsigned long                 minor;
  7.         int                  ret;
  8.         
  9.         printk("%s \n", __FUNCTION__);

  10.         /* Allocate driver data */
  11.         spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
  12.         if (!spidev)
  13.                 return -ENOMEM;

  14.         /* Initialize the driver data */
  15.         spi->mode = 1;
  16.         spi->max_speed_hz = 1000 * 1000 *10;
  17.         spi->bits_per_word = 8;
  18.         spidev->spi = spi;

  19.         /*inin lock*/
  20.         spin_lock_init(&spidev->spi_lock);
  21.         mutex_init(&spidev->buf_lock);

  22.         
  23.         /*Reset register condition*/
  24.         At45db_nrst = of_get_named_gpio(np, "At45db_nrst", 0);

  25.         ret = gpio_request(At45db_nrst, "At45db_nrst");
  26.         if (ret)
  27.                 return -ENODEV;
  28.         gpio_direction_output(At45db_nrst, GPIO_LOW);
  29.         gpio_direction_output(At45db_nrst, GPIO_HIGH);

  30.         /*Turn off write protect*/
  31.         At45db_nwp = of_get_named_gpio(np, "At45db_nwp", 0);
  32.         ret = gpio_request(At45db_nwp, "At45db_nwp");
  33.         if (ret)
  34.                 return -ENODEV;

  35.         //At45db_flash_init(spidev);

  36.         INIT_LIST_HEAD(&spidev->device_entry);

  37.         /* If we can allocate a minor number, hook up this device.
  38.          * Reusing minors is fine so long as udev or mdev is working.
  39.          */
  40.         mutex_lock(&device_list_lock);
  41.         minor = find_first_zero_bit(minors, N_SPI_MINORS);
  42.         if (minor < N_SPI_MINORS) {
  43.                 struct device *dev;

  44.                 spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
  45.                 dev = device_create(spiflash_cls, &spi->dev, spidev->devt,
  46.                                     spidev, "spidev%d.%d",
  47.                                     spi->master->bus_num, spi->chip_select);
  48.                 status = PTR_RET(dev);
  49.         } else {
  50.                 dev_dbg(&spi->dev, "no minor number available!\n");
  51.                 status = -ENODEV;
  52.         }
  53.         if (status == 0) {
  54.                 set_bit(minor, minors);
  55.                 list_add(&spidev->device_entry, &device_list);
  56.         }
  57.         mutex_unlock(&device_list_lock);

  58.         if (status == 0)
  59.                 spi_set_drvdata(spi, spidev);
  60.         else
  61.                 kfree(spidev);

  62.         return status;
  63. }
复制代码
  1. 和设备树匹配的代码,基本都是这个套路,匹配compatible就行了
复制代码
flash_spi.rar (3.24 KB, 下载次数: 44, 售价: 1 灯泡)

AT45DB041D.rar (707.62 KB, 下载次数: 32, 售价: 1 灯泡)







回复

使用道具 举报

433

积分

3

威望

0

贡献

技术达人

Rank: 2

积分
433
发表于 2017-7-12 14:36:24        只看该作者  沙发
本帖最后由 z3j6w9 于 2017-7-12 14:38 编辑

在probe中修改了max_frequence,是因为执行写操作报warning
spi_master spi0: DW SPI: Status keeps busy for 1000us after a read/write!
其实就是频率有点快,调慢点就行了

spi flash读数据前都需要写命令,刚开始先发命令再调用read获取数据,怎么都调不对波形,后来参看了下韦东山写的spi flash的代码,写成如下的形式就ok了;韦东山的spi视频是要花钱的,不过就19块,有兴趣的可以看看,我最近比较懒,所以就没去买来看了。
  1. static inline ssize_t
  2. spidev_sync_read(struct spidev_data *spidev, FLASH_C *flash_c)
  3. {
  4.         struct spi_transfer        t[] = {
  5.                 {
  6.                         .tx_buf                = flash_c->cmd,
  7.                         .len                = flash_c->cmd_len,
  8.                 },
  9.                 {
  10.                         .rx_buf     = flash_c->read_buf,
  11.                         .len        = flash_c->read_buf_len,
  12.                 }
  13.         };
  14.         struct spi_message        m;

  15.         spi_message_init(&m);
  16.         spi_message_add_tail(&t[0], &m);
  17.         spi_message_add_tail(&t[1], &m);
  18.         return spidev_sync(spidev, &m);
  19. }
复制代码
回复

使用道具 举报

433

积分

3

威望

0

贡献

技术达人

Rank: 2

积分
433
发表于 2017-7-12 14:42:46        只看该作者  板凳
本帖最后由 z3j6w9 于 2017-7-12 14:48 编辑

在对spi进行操作之前需要获取下当前芯片的状态,在初始化过程中操作是没有回应的。还有就是,我一开始在初始化后就尝试获取状态,因为调用的是read函数,结果就在如下代码中挂掉了,程序状态直接变成了D+,而且不可中断,重启无数次。
  1. static ssize_t
  2. spidev_sync(struct spidev_data *spidev, struct spi_message *message)
  3. {
  4.         DECLARE_COMPLETION_ONSTACK(done);
  5.         int status;

  6. #if 1
  7.         message->complete = spidev_complete;
  8.         message->context = &done;
  9. #endif
  10.         spin_lock_irq(&spidev->spi_lock);
  11.         if (spidev->spi == NULL)
  12.                 status = -ESHUTDOWN;
  13.         else
  14.                 status = spi_async(spidev->spi, message);
  15.         spin_unlock_irq(&spidev->spi_lock);

  16.         if (status == 0) {
  17.                 wait_for_completion(&done);
  18.                 status = message->status;
  19.                 if (status == 0)
  20.                         status = message->actual_length;
  21.         }
  22.         return status;
  23. }
复制代码


后续就改成了在每次读写执行获取芯片状态,不在锁里面做,防止死掉挂掉的时候会提示hung task,分享个别人写的定位的博客,其实写代码的过程中遇到问题是好事,真的能学会很多
http://blog.chinaunix.net/xmlrpc ... 10&uid=14528823
回复

使用道具 举报

433

积分

3

威望

0

贡献

技术达人

Rank: 2

积分
433
发表于 2017-7-12 14:45:03        只看该作者  地板
本帖最后由 z3j6w9 于 2017-7-12 15:05 编辑


  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <assert.h>

  6. typedef struct TEST_Flash_Ctrl
  7. {         unsigned char *cmd;
  8.         unsigned char *read_buf;
  9.         unsigned char *w_data;
  10.         unsigned char  cmd_len;
  11.         unsigned char  read_buf_len;
  12.         unsigned char  w_len;
  13.         unsigned char  resv;
  14. }TEST_C;

  15. static int fd;
  16. static int write_to_flash(TEST_C *buf)
  17. {
  18.         return write(fd, buf, sizeof(TEST_C));
  19. }

  20. static int read_from_flash(TEST_C *buf)
  21. {
  22.         return read(fd, buf, buf->read_buf_len);
  23. }

  24. static int init_flash()
  25. {
  26.         /*erase before write*/
  27.         int ret ;
  28.         TEST_C buf;
  29.         unsigned char erase_cmd[] = {0xc7, 0x94, 0x80, 0x9a};

  30.         buf.cmd = erase_cmd;
  31.         buf.cmd_len = sizeof(erase_cmd);

  32.         ret = write_to_flash(&buf);
  33.         if (0 == ret)
  34.         {
  35.                 printf("%s: write err.\n ", __FUNCTION__);
  36.                 return ret;
  37.         }

  38.         return 0;
  39. }

  40. static int write_buffer(unsigned short addr, unsigned char* data, unsigned char len)
  41. {
  42.         unsigned char w_cmd[4];
  43.         unsigned char addr_u = (unsigned char)(addr >> 8);
  44.         unsigned char addr_v = (unsigned char)addr;
  45.         int ret;
  46.         TEST_C buf;

  47.         w_cmd[0] = 0x84;
  48.         w_cmd[1] = 0xff;
  49.         w_cmd[2] = addr_u;
  50.         w_cmd[3] = addr_v;

  51.         buf.cmd = w_cmd;
  52.         buf.cmd_len = sizeof(w_cmd);
  53.         buf.w_data = data;
  54.         buf.w_len  = len;

  55.         ret = write_to_flash(&buf);
  56.         if (0 == ret)
  57.         {
  58.                 printf("%s: write err.\n ", __FUNCTION__);
  59.                 return ret;
  60.         }

  61.         return 0;
  62. }

  63. static int read_buffer(unsigned short add, unsigned char *read_buf, unsigned char len)
  64. {

  65.         unsigned char r_cmd[5];
  66.         unsigned char addr_u;
  67.         unsigned char addr_v;
  68.         TEST_C test_c;
  69.         TEST_C buf;


  70.         addr_u = (unsigned char)(add >> 8);
  71.         addr_v = (unsigned char)add;

  72.         r_cmd[0] = 0xd4;
  73.         r_cmd[1] = 0xff;
  74.         r_cmd[2] = addr_u;
  75.         r_cmd[3] = addr_v;
  76.         r_cmd[4] = 0xff;

  77.         buf.cmd = r_cmd;
  78.         buf.cmd_len = sizeof(r_cmd);
  79.         buf.read_buf = read_buf;
  80.         buf.read_buf_len = len;

  81.         read_from_flash(&buf);
  82. }

  83. static unsigned char read_status()
  84. {
  85.         TEST_C buf;
  86.         unsigned char cmd[1];
  87.         unsigned char status = 0;
  88.         printf("Get status \n");

  89.         cmd[0] = 0xd7;

  90.         buf.cmd = cmd;
  91.         buf.cmd_len = 1;
  92.         buf.read_buf = &status;
  93.         buf.read_buf_len = 1;

  94.         read_from_flash(&buf);

  95.         return status;
  96. }

  97. int main(void)
  98. {
  99.         int ret = 0;
  100.         unsigned char buf_room[10];
  101.         unsigned char status;
  102.         unsigned short addr = 0x0;
  103.         unsigned char data[] = {0x00, 0xff, 0x0, 0xff, 0x0, 0xff};

  104.         fd = open("/dev/spidev0.0", O_RDWR);
  105.         if (fd < 0)
  106.         {
  107.                 printf("%s open device failed. \n", __FUNCTION__);
  108.                 return -1;
  109.         }
  110.         init_flash();
  111. #if 1
  112.         write_buffer(addr, data, sizeof(data));
  113.         read_buffer(addr, buf_room, 8);

  114.         printf("Data is %x \n", buf_room[0]);
  115.         printf("Data is %x \n", buf_room[1]);
  116.         printf("Data is %x \n", buf_room[2]);
  117. #endif
  118.         ret = close(fd);

  119.         return 0;
  120. }
复制代码

boxing.png (20.4 KB, 下载次数: 676)

boxing.png
回复

使用道具 举报

433

积分

3

威望

0

贡献

技术达人

Rank: 2

积分
433
发表于 2017-7-12 15:07:27        只看该作者  5#
上面的是接收的数据,下面这张是发送的波形

回复

使用道具 举报

433

积分

3

威望

0

贡献

技术达人

Rank: 2

积分
433
发表于 2017-7-12 15:09:09        只看该作者  6#
代码中只实现了对buffer的写/读,有兴趣研究嵌入式mcu开发的可以在论坛中私信我,大家私下一起交流技术
回复

使用道具 举报

126

积分

0

威望

0

贡献

技术小白

积分
126
发表于 2017-7-21 11:24:06        只看该作者  7#
请问自己新增一个档案当作driver,都需要修改dts档案吗??
回复

使用道具 举报

433

积分

3

威望

0

贡献

技术达人

Rank: 2

积分
433
发表于 2017-7-21 13:05:51        只看该作者  8#
aaaaa-ray 发表于 2017-7-21 11:24
请问自己新增一个档案当作driver,都需要修改dts档案吗??

dts中写的是硬件相关的信息,如果你需要用到的硬件信息设备树中已经有了,那就不需要修改设备树了。设备树的出现其实就是替代了以前驱动中的board_info注册,将通用的硬件信息给整合了起来,既方便阅读,也方便开发。
回复

使用道具 举报

126

积分

0

威望

0

贡献

技术小白

积分
126
发表于 2017-7-21 13:30:46        只看该作者  9#
z3j6w9 发表于 2017-7-21 13:05
dts中写的是硬件相关的信息,如果你需要用到的硬件信息设备树中已经有了,那就不需要修改设备树了。设备 ...

太感谢解答
回复

使用道具 举报

116

积分

0

威望

0

贡献

技术小白

积分
116
发表于 2017-7-25 14:24:55        只看该作者  10#
严重的感谢解答
回复

使用道具 举报

返回列表
12
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

友情链接 : 爱板网 电子发烧友论坛 云汉电子社区 粤ICP备14022046号-2
快速回复 返回顶部 返回列表