Linux环境下SPI CLK无法通过初始化修改的排查要点咨询
SPI时钟设置不生效的排查要点
问题背景
在Linux环境下通过SPI接口访问外设,设备能正常通信,但修改SPI时钟频率后设置不生效。以下是相关初始化代码和设备树配置:
SPI初始化代码
int spidev_init(char *rfdev, int mode, int bits, int speed) { int file; int ret; file = open(rfdev, O_RDWR); if (file < 0) { printf("%s can't open device!!!\0", rfdev); return -1; } /* * spi mode */ ret = ioctl(file, SPI_IOC_WR_MODE, &mode); if (ret == -1) { printf("%s can't set spi mode!!!", rfdev); return -2; } else bit2equ(spi_mode, mode); ret = ioctl(file, SPI_IOC_RD_MODE, &mode); if (ret == -1) { printf("%s can't get spi mode!!!", rfdev); return -3; } /* * bits per word */ ret = ioctl(file, SPI_IOC_WR_BITS_PER_WORD, &bits); if (ret == -1) { printf("%s can't set bits per word!!!", rfdev); return -4; } else bit2equ(spi_bits, bits); ret = ioctl(file, SPI_IOC_RD_BITS_PER_WORD, &bits); if (ret == -1) { printf("%s can't get bits per word!!!", rfdev); return -5; } /* * max speed hz */ ret = ioctl(file, SPI_IOC_WR_MAX_SPEED_HZ, &speed); if (ret == -1) { printf("%s can't set max speed hz!!!", rfdev); return -6; } else bit2equ(spi_speed, speed); ret = ioctl(file, SPI_IOC_RD_MAX_SPEED_HZ, &speed); if (ret == -1) { printf("%s can't get max speed hz!!!", rfdev); return -7; } return file; }
SPI设备树配置
&spi2 { pinctrl-names = "default"; pinctrl-0 = <&spi2_pincfg>; pinctrl-1 = <&spi2_pincfg_sleep>; #address-cells = <1>; #size-cells = <0>; status = "okay"; spidev@0 { compatible = "rohm,dh2228fv"; reg = <0>; spi-max-frequency = <500000>; // spi-max-frequency = <1000000>; // spi-max-frequency = <25000000>; }; }; spi2: ssp@e401e000 { compatible = "zinus,zinus-spi"; reg = <0xE401D000 0x40>; interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cru CLK_SSP2_FUNC>, <&cru CLK_SSP2_APB_BUS>; clock-names = "spiclk", "apb_pclk"; resets = <&cru RST_SSP2>; reset-names = "spi"; dmas = <&sysdma ZN_DMA_SPI2_TX 3>, <&sysdma ZN_DMA_SPI2_RX 3>; dma-names = "tx", "rx"; status = "disabled"; }; spi2 { spi2_pincfg:spi2_pincfg { zinus,pins = <ZN_GPIO_14 4 &config_pull_disable>, <ZN_GPIO_15 4 &config_pull_disable>, <ZN_GPIO_16 4 &config_pull_disable>, <ZN_GPIO_17 4 &config_pull_disable>; }; spi2_pincfg_sleep:spi2-pincfg-sleep { zinus,pins = <ZN_GPIO_14 0 &config_pull_disable>, <ZN_GPIO_15 0 &config_pull_disable>, <ZN_GPIO_16 0 &config_pull_disable>, <ZN_GPIO_17 0 &config_pull_disable>; }; };
排查要点
- 设备树频率上限限制:外设节点的
spi-max-frequency是用户空间设置的硬上限,代码中设置的speed如果超过DTS里的500000,会被钳位到该值。需修改DTS中的spi-max-frequency为目标频率,重新编译烧录设备树。 - SPI控制器时钟源配置:检查
cru节点中CLK_SSP2_FUNC的分频、倍频参数,确保其能生成目标频率所需的基础时钟。比如目标25MHz时,需确认该时钟源头能提供足够高的频率进行分频。 - SPI驱动时钟处理逻辑:查看
zinus,zinus-spi驱动源码中处理SPI_IOC_WR_MAX_SPEED_HZ的逻辑,确认是否正确将用户设置的频率转换为硬件寄存器的分频值,是否存在硬编码限制。 - 验证实际生效频率:在代码中
SPI_IOC_RD_MAX_SPEED_HZ后添加打印,输出读取到的speed值,判断是设置未生效还是被驱动钳位。 - 硬件分频兼容性:部分SPI控制器仅支持基础时钟的整数分频,无法设置任意频率。需确认目标频率是否在控制器支持的分频范围内。
- 外设驱动冲突:外设节点
compatible为rohm,dh2228fv,若内核加载了该专属驱动,可能会覆盖用户空间的时钟设置。可改为compatible = "spidev"使用通用驱动,或修改专属驱动的时钟配置。 - 权限与设备节点检查:确保程序以root权限运行,避免
ioctl权限不足导致设置失效;同时确认打开的rfdev是正确的SPI设备节点(如/dev/spidev2.0)。 - 内核日志排查:执行
dmesg | grep spi查看SPI相关的错误或警告日志,直接定位时钟设置失败的原因。
内容的提问来源于stack exchange,提问作者andy
相关产品推荐
相关产品推荐

