[原创] STM32MP157A-DK1测评+SPI设备

bigbat   2020-4-8 12:28 楼主

前一阶段由于不熟悉linux的设备驱动程序的编写又找不到资料。所以就暂时把SPI设备的实验给搁置了。前几天看到网友的测评很受启发就又开始了解SPI的驱动。初步的对linux驱动有了一些认识后,开始SPI设备的实验。如果想使用SPI设备就要从设备树的配置开始。linux的设备树其实就是一种设备信息的配置文件。有点象JSON、XML文件的那种。设备树文件的主要思想就是让设备驱动和设备配置分开。这样编写设备驱动就和具体设备的BPS没有关系了。驱动程序只针对这类设备编写就可以。不同要求的具体板卡如果想使用某种外设,只要在设备的“配置文件”把这种外设的信息配置一下,驱动程序就可以工作了。就象我们测试的STM32MP157A-DK1板卡默认是不打开SPI5设备的,SPI5的PIN默认为GPIO。你的设备如果需要默认使用SPI5,打开SPI5的配置就可以。不需要针对具体设备编写驱动程序。设备树这种机制又可以将同类型的设备抽象成一种驱动,通过配置修改一下寄存器地址就可以驱动不同的同类设备。比如SPI、I2C、CAN、Uart等等字符设备。又如Uart设备的驱动操作方法是一样的,只是配置不一样而已。这样就没必要写多个驱动程序了。不同的uart使用同一个驱动只是各自的地址不一样而已。
如果想使用STM32MP157A-DK1的SPI5设备。首先需要在arch/arm/boot/dts/stm32mp157a-dk1.dts中进行修改配置。

&spi5 {
        pinctrl-names = "default", "sleep";
        pinctrl-0 = <&spi5_pins_a>;
        pinctrl-1 = <&spi5_sleep_pins_a>;
        cs-gpios = <&gpiog 15 GPIO_ACTIVE_LOW>;
        cd-gpios = <&gpiod 7  GPIO_ACTIVE_LOW>;
        status = "okay";

        spidev0: spidev@0 {
                compatible = "rohm,dh2228fv";
                reg = <0>;
                spi-max-frequency = <50000000>;
        };
};

spi5引脚配置项pinctrl-0和pinctrl-1在包含文件.dtsi中 ,这些是SPI的引脚配置。我的SD1306还需要CS和CD两个控制引脚。同时也在这次声明中配置。其实cs-gpios和cd-gpios这两个引脚使用默认配置也可以。arch/arm/boot/dts/stm32mp157-pinctrl.dtsi

spi5_sleep_pins_a: spi5-sleep-0 {
	pins {
	pinmux = <STM32_PINMUX('F', 7, ANALOG)>, /* SPI5_SCK */
	<STM32_PINMUX('F', 8, ANALOG)>, /* SPI5_MISO */
	<STM32_PINMUX('F', 9, ANALOG)>; /* SPI5_MOSI */
	
          };
};

gpiod: gpio@50005000 {
	gpio-controller;
	#gpio-cells = <2>;
	interrupt-controller;
	#interrupt-cells = <2>;
	reg = <0x3000 0x400>;
	clocks = <&rcc GPIOD>;
	st,bank-name = "GPIOD";
	status = "disabled";
	};

gpiog: gpio@50008000 {
	gpio-controller;
	#gpio-cells = <2>;
	interrupt-controller;
	#interrupt-cells = <2>;
	reg = <0x6000 0x400>;
	clocks = <&rcc GPIOG>;
	st,bank-name = "GPIOG";
	status = "disabled";
	};

pins.jpg 可以看到SPI5的引脚配置(spi5_sleep_pins_a)与资料上的一致。为PF7、 PF8、PF9这些是芯片引脚功能编号。设备树还配置了其它参数。这些配置可以在spidev.c驱动中找到。如:spidev0: spidev@0设置了驱动文件spidev.c和驱动中的功能compatible 参考下面的代码

static struct class *spidev_class;

#ifdef CONFIG_OF
static const struct of_device_id spidev_dt_ids[] = {
	{ .compatible = "rohm,dh2228fv" },
	{ .compatible = "lineartechnology,ltc2488" },
	{ .compatible = "ge,achc" },
	{ .compatible = "semtech,sx1301" },
	{},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
#endif

#ifdef CONFIG_ACPI

驱动程序中并没有看到使用这些引脚的代码,驱动只是使用了配置中的寄存器而已。SPI4和SPI5的驱动没有什么差别。只要配置好SPI5的设置,SPI5功能就可以使用了,且SPI的三个主要功能引脚全部设置完成。驱动程序配置完成后只需要编写应用层驱动程序了,也可以说只要文件向/dev/spidev0.0里面灌数据了就可以驱动SPI5了。我用的是SD1306 OLED SPI串口屏,除了SPI引脚还需要两个控制引脚(CS和CD),注意CS引脚默认为"低",使能打开。CD引脚的功能是命令选择。程序主要参考了tools\spi\spidev_test.c文件,其中主要的API有两个,
#include <linux/gpio.h> 其中的API函数 gpio_data.values用来设置cs-gpios引脚的状态
#include <linux/spi/spidev.h>主要使用了其中的宏定义,如:ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);当中的SPI_IOC_WR_MAX_SPEED_HZ等定义。
主要的文件两个
const char gpio_dev_cs = "/dev/gpiochip3";
const char gpio_dev_ds = "/dev/gpiochip5";
const char spidev_name = "/dev/spidev0.0";


int cd_gpio_set(void)
{
	int ret;
	
	ret = ioctl(cd_fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &gpio_data);
	if (ret == -1) {
		ret = -errno;
		fprintf(stderr, "Failed to issue %s (%d)\n",
			"GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret);
	}
		
	return ret;
}

void send_byte_spi(unsigned char data)
{
	int status;

	spi_tx[0] = data;

	status = ioctl(fd, SPI_IOC_MESSAGE(1), xfer);
	if (status < 0) 
	{
		perror("SPI_IOC_MESSAGE");
		return;
	}
}

用户程序参考SD1306的程序就可以。

20200407_102736146_iOS.jpg
此内容由EEWORLD论坛网友bigbat原创,如需转载或用于商业用途需征得作者同意并注明出处

回复评论 (2)

感谢楼主。教程太棒了

点赞 (1) 2020-4-8 13:42
好的开始
点赞  2020-4-8 21:31
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复