Linuxカーネル付属SPIデバイスドライバテスタ分析:spidev_test.c


Linuxシステムにおいて、SPIのユーザモードデバイスインタフェースの駆動ソースコードはdrivers/spi/spidevにある.c.アプリケーション層で/dev/spidev*を生成するノードは、read、writeを介してハードウェアデバイスとのSPI通信を達成することができる.spidevドライバの移植とアプリケーションの作成方法について説明します.ハードウェア構成:創龍TL 335 x-IDK開発ボード+SOM-TL 3359-eMMCコアボード3     

1.ドライバコードマイグレーション


このデバイスドライバをカーネルに追加するには、次の2つのことを行います.
第一に、カーネルmenuconfigでspidevのドライバ
        Device Drivers -> 

            SPI support ->

               User mode SPI device driver support

第二に、デバイスツリーファイルにspidevノード       を追加SPI 1というバスを選択し、カーネルソースのDTSファイルに対応するpinmuxと追加ノードを構成する.カーネルソースarch/arm/boot/dts/am 335 x-icev 2を開きます.dtsデバイスツリーソースファイルは、元の構成を参照して対応する場所に新しいspiノードを追加します.
&spi1 {
		status = "okay";
		pinctrl-names = "default";
		pinctrl-0 = <&spi1_pins_default>;
		
	spidev0: spi@0 {
		compatible = "spidev";
		reg = <0>;/*CS0*/
		spi-max-frequency = <40000000>;
	};
};

ピン多重定義
	spi1_pins_default: spi1_pins_default {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x990, PIN_INPUT_PULLUP | MUX_MODE0) /* (A13) spi1_sclk.spi1_sclk */
			AM33XX_IOPAD(0x994, PIN_INPUT_PULLUP | MUX_MODE0) /* (B13) spi1_d0.spi1_d0 */
			AM33XX_IOPAD(0x998, PIN_INPUT_PULLUP | MUX_MODE0) /* (D12) spi1_d1.spi1_d1 */
			AM33XX_IOPAD(0x99c, PIN_INPUT_PULLUP | MUX_MODE0) /* (C12) spi1_cs0.spi1_cs0 */
		>;
	};

ドライバコードを移植する後、カーネルを再コンパイルし、開発ボードにダウンロードすると、spiデバイス/dev/spidev 1が表示されます.0はSPI駆動移植が成功したことを示している.
    

2.アプリケーション作成


   ドライバコードを変更した後、ドライバのアーキテクチャに基づいてアプリケーションの作成を完了する必要があります.カーネルソースコードDocumentation/spiディレクトリの下にspidev_があります.test.cファイルは、カーネル作成者がLinux開発者に提供するリファレンスドキュメントであり、筆者もこのファイルを参考に作成したアプリケーションである.
アプリケーションはopen、close、read、write、ioctlの使用にほかならない.Open,closeは何も言うことはありませんが,ioctl,read,writeの使用について具体的に説明します.
    spiアプリケーション作成手順:   第一:open  第二:ioctl,ioctlには9種類のcmdがあり、それぞれ異なるargに対応している
SPI動作モードの設定または取得IOC_RD_MODE//リードモードIOC_WR_MODE//書き込みモード   以上の2種類のcmd対argはspi_device.mode
    spi_device.modeには、以下のタイプがあります.MODE_0(0|0)/SCLKアイドル時はローレベル、第1時間遅延サンプリング   #define SPI_MODE_1(0|SPI_CPHA)/SCLKアイドル時はハイレベル、第1時間遅延サンプリング   #define SPI_MODE_2(SPI_CPOL|0)/SCLKアイドル時はローレベル、第2時間遅延サンプリング   #define SPI_MODE_3(SPI_CPOL|SPI_CPHA)/SCLKアイドル時はハイレベル、2時間目の遅延サンプリングCS_HIGH 0 x 04/チップ選択高   #define SPI_LSB_FIRST 0 x 08//下位データ先転送   #define SPI_3 WIRE 0 x 10/3線式、入出力データ線は1本の線LOOP 0 x 20/ループバックモード   #define SPI_NO_CS 0 x 40//選択信号なし   #define SPI_READY 0x80//
    用法:   mode=mode|SPI_MODE_0 | SPI_CS_HIGH | SPI_LSB_FIRST | SPI_LOOP     ioctl(fd, SPI_IOC_WR_MODE, &mode); 前の4つはSCKクロック信号のアイドル時のレベルとサンプリング時刻の選択であり、4つはそのうちの1つしか選択できず、後の5つは任意のいくつかを選択することができ、使用方法は上述の通りである
[PROD 140]b、SPIの読み書きを設定または取得するには、上位または下位から開始します.IOC_RD_LSB_FIRST//LSBを読むIOC_WR_LSB_FIRST//書き込みLSB    以上の2種類のcmd対用argはspi_device.modeLSB_FIRSTの一種
   c、SPI読み書きデータビット数の設定または取得IOC_RD_BITS_PER_WORD//各字の何位を読むかIOC_WR_BITS_PER_WORD//字ごとに何桁書きますか   以上の2種類のcmd対用argはspiですdevice.bits_per_word    用法:    bits=8;    ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
SPI読み書きの最大周波数IOC_RD_MAX_SPEED_HZ//最大速度IOC_WR_MAX_SPEED_HZ//書き込み最大レート    以上の2種類のcmd対argはspi_device.max_speed_hz    用法:    speed=50*1000;    ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    e、転送データ          SPI_IOC_MESSAGE(n)/転送n個のパケット   以上のcmd対用argはspi_ioc_transfer
struct spi_ioc_transfer tr = {
	.tx_buf = (unsigned long)tx,
	.rx_buf = (unsigned long)rx,
	.len = ARRAY_SIZE(tx),
	.delay_usecs = delay,
	.speed_hz = speed,
	.bits_per_word = bits,
};

ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);

第3:readまたはwrite    char* buf[n];     read(fd,buf,sizeof(buf));またはwrite(fd,buf,sizeof(buf));
第四:close