SPI Bit-banging方法的实现

前言

SPI(Serial Peripheral Interface)是一种应用广泛的通信总线,通常微处理器上会集成SPI模块以支持该通信协议,输出正确的信号的时序,并保证时序间同步,实现与外部SPI设备正常通信。当需要使用微处理器上SPI模块,但发现引脚被占用时,那么可以通过SPI Bit-banging这个方法,通过GPIO端口模拟SPI接口引脚(CS、MOSI、MISO、CLK)上的时序信号来实现SPI协议,与对应SPI设备进行通信。以下为MT7688芯片的SPI读写时序图。本文主要介绍如何在嵌入式linux发行版平台上实现SPI Bit-banging功能。

图片描述

设备树语法和格式


 
 
  1. 嵌入式linux系统引入了设备树(Device Tree)机制,采用这种数据结构将硬件信息组织成DTS(Device Tree source)文件用于描述板级设备。设备树由基本单元——节点(node)组织成树状结构,一个设备树只有一个根节点(root node),根节点中可包含若干子节点,每个子节点可以同时包含若干属性和下一级子节点,属性用于描述了节点的具体特征。
  2. 以下为.dts文件中最基本的树结构,“/”表示根节点,根节点下的两个子节点分别为“node1”和“node2”,“node1”和“node2”又各自包含了子节点,如“child-node1”和“child-node2”。文件中若干键-值对,为分散在设备树中的属性。
  3. / {
  4. node1 {
  5. a- string- property = "A string";
  6. a- string-list- property = "first string", "second string";
  7. a-byte-data- property = [ 0x01 0x23 0x34 0x56];
  8. child-node1 {
  9. first-child- property;
  10. second-child- property = < 1>;
  11. a- string- property = "Hello, world";
  12. };
  13. child-node2 {
  14. };
  15. };
  16. node2 {
  17. an- empty- property;
  18. a-cell- property = < 1 2 3 4>; /* each number (cell) is a uint32 */
  19. child-node1 {
  20. };
  21. };
  22. };

由于以上的.dts文件并没有描述任何硬件设备的特征,下面以openwrt发行版上的MT7628dts文件为例对设备树进行具体说明。每个节点以“<名称>[@<设备地址>]”形式命名,当该节点描述的设备存在设备地址时需在名称后加上主地址,同时节点中以reg=<地址1 长度1] [地址2 长度2] [地址3 长度3] ... >方式列出设备使用的地址范围,父节点的 #address-cells 和 #size-cells 属性声明reg中各字段的数量。节点中的compatible属性表示使用哪个设备驱动绑定到当前节点描述的设备上。


 
 
  1. Mt7628an.dtsi文件部分代码:
  2. / {
  3. #address-cells = <1>;
  4. #size-cells = <1>;
  5. compatible = "ralink,mtk7628an-soc";
  6. cpus {
  7. cpu@ 0 {
  8. compatible = "mips,mips24KEc";
  9. };
  10. };
  11. chosen {
  12. bootargs = "console=ttyS0,57600";
  13. };
  14. ......
  15. palmbus: palmbus@ 10000000 {
  16. compatible = "palmbus";
  17. reg = < 0x10000000 0x200000>;
  18. ranges = < 0x0 0x10000000 0x1FFFFF>;
  19. #address-cells = <1>;
  20. #size-cells = <1>;
  21. sysc: sysc@ 0 {
  22. compatible = "ralink,mt7620a-sysc";
  23. reg = < 0x0 0x100>;
  24. };
  25. gpio@ 600 {
  26. #address-cells = <1>;
  27. #size-cells = <0>;
  28. compatible = "mtk,mt7628-gpio", "mtk,mt7621-gpio";
  29. reg = < 0x600 0x100>;
  30. interrupt-parent = <&intc>;
  31. interrupts = < 6>;
  32. gpio0: bank@ 0 {
  33. reg = < 0>;
  34. compatible = "mtk,mt7621-gpio-bank";
  35. gpio-controller;
  36. #gpio-cells = <2>;
  37. };
  38. gpio1: bank@ 1 {
  39. reg = < 1>;
  40. compatible = "mtk,mt7621-gpio-bank";
  41. gpio-controller;
  42. #gpio-cells = <2>;
  43. };
  44. gpio2: bank@ 2 {
  45. reg = < 2>;
  46. compatible = "mtk,mt7621-gpio-bank";
  47. gpio-controller;
  48. #gpio-cells = <2>;
  49. };
  50. };
  51. spi0: spi@b00 {
  52. compatible = "ralink,mt7621-spi";
  53. reg = < 0xb00 0x100>;
  54. resets = <&rstctrl 18>;
  55. reset-names = "spi";
  56. #address-cells = <1>;
  57. #size-cells = <0>;
  58. pinctrl-names = "default";
  59. pinctrl -0 = <&spi_pins>;
  60. status = "disabled";
  61. };
  62. ......
  63. };
  64. pinctrl: pinctrl {
  65. compatible = "ralink,rt2880-pinmux";
  66. pinctrl-names = "default";
  67. pinctrl -0 = <&state_default>;
  68. state_default: pinctrl0 {
  69. };
  70. spi_pins: spi {
  71. spi {
  72. ralink,group = "spi";
  73. ralink,function = "spi";
  74. };
  75. };
  76. spi_cs1_pins: spi_cs1 {
  77. spi_cs1 {
  78. ralink,group = "spi cs1";
  79. ralink,function = "spi cs1";
  80. };
  81. };
  82. ......
  83. };
  84. };

SPI Bit-banging实现

嵌入式Linux内核中已提供SPI Bit-banging驱动代码,只需进行对应的配置即可使用。

首先在openwrt_widora-master/target/linux/ramips/dts路径下修改Widora.dts文件,将配置代码加入根节点中,并且在pinctrl中将Spis功能的引脚申明为GPIO引脚,驱动文件为drivers/spi路径下的spi-gpio.c,函数中注册的驱动名称为spi_gpio,与 compatible属性对应。


 
 
  1. dts文件部分代码:
  2. gpio-spi {
  3. status = "okay";
  4. compatible = "spi-gpio";
  5. #address-cells = <0x1>;
  6. ranges;
  7. gpio-sck = <&gpio0 14 1>;
  8. gpio-miso = <&gpio0 15 1>;
  9. gpio-mosi = <&gpio0 16 1>;
  10. cs-gpios = <&gpio0 17 1>;
  11. num-chipselects = < 1>;
  12. }
  13. spi-gpio.c文件部分代码:
  14. #define DRIVER_NAME "spi_gpio"
  15. static struct platform_driver spi_gpio_driver = {
  16. .driver = {
  17. .name = DRIVER_NAME,
  18. .owner = THIS_MODULE,
  19. .of_match_table = of_match_ptr(spi_gpio_dt_ids),
  20. },
  21. .probe = spi_gpio_probe,
  22. .remove = spi_gpio_remove,
  23. };
  24. module_platform_driver(spi_gpio_driver);

其次在OpenWrt的配置界面中选择Kernel modules–> SPI Support –>kmod-spi-gpio,选中后会自动关联 kmod-spi-bitbang模块。

最后编译内核并烧录固件。内核启动后通过lsmod命令查看已经加载到内核中的模块的状态信息,可发现内核已经加载了spi_bitbang和spi_gpio模块。

图片描述

在spi-gpio.c文件的spi_gpio_probe函数加入printk语句观察可获悉到spi-gpio驱动在启动时被加载运行,并且从dts文件中获取到定义为SPI Bit-banging功能的GPIO引脚。

图片描述

结论

SPI的bit-bang方式实现SPI协议虽然可以不依赖于控制器上的SPI外设模块,但是需要代码完成时序逻辑和同步要求,相对来说性能低于控制器自身的SPI模块,因此仅适用于低速要求的应用场合。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值