Armadilloフォーラム

i2c をslaveとして使うことが可能でしょうか?

macfuruya

2022年3月1日 6時17分

いつもありがとうございます。

Armadillo-Iot A6 にて、I2Cをslaveとして使いたいと思っています。
すみませんが、以下の2点について教えてください。

1).標準のI2Cには、内部的に、デバイスがつながっているようなので、at-dtweb で、I2C3 を追加して利用した方がいいでしょうか?

2).Raspberry Pi とかであれば、gpio のライブラリで、i2c のslave 用が用意されているようで、検索するとでてくるのですが
同じように、armadillo でもi2c をslaveとして、使えるライブラリや、使う方法がありますでしょうか?

教えていただければ助かります。
よろしくお願いいたします。

コメント

at_syunya.ohshio

2022年3月3日 16時13分

大塩です。

ご質問いただいた2点について回答いたします。

> 1).標準のI2Cには、内部的に、デバイスがつながっているようなので、at-dtweb で、I2C3 を追加して利用した方がいいでしょうか?

仰る通りであるため、at-dtweb で I2C3 を利用する方法が安全と思われます。
マスタとして使用するのであれば、デフォルトで設定されている I2C ピンで問題ありません。

> 2).Raspberry Pi とかであれば、gpio のライブラリで、i2c のslave 用が用意されているようで、検索するとでてくるのですが
> 同じように、armadillo でもi2c をslaveとして、使えるライブラリや、使う方法がありますでしょうか?

Armadillo-IoT A6 の I2C は Slave mode にすることが出来るため、技術的には可能です。
用意されている example コード等はありませんので、お客様で作成と検証を行っていただくことになります。
Linuxカーネルのソースファイル内に、I2C Slave に関するドキュメントが存在しますので、そちらをご参照ください。

・ドキュメント配置場所
\linux-v4.14-at42\Documentation\i2c\slave-interface

また、デバイスツリーの config を変更する必要があります。
製品マニュアルの「イメージをカスタマイズする」を参考に、以下 config を有効にしてください。

-> Device Drivers
  -> I2C support
    [*]   I2C slave support 

以上です。

大塩様、ありがとうございます。

技術的には可能とわかりましたので、
カーネルのビルドをして、いろいろ試行錯誤してみたいと思います。

うまく動作できましたら、また報告させていただきます。

アットマークテクノの古賀です。

macfuruyaさん:
>技術的には可能とわかりましたので、
>カーネルのビルドをして、いろいろ試行錯誤してみたいと思います。
>
>うまく動作できましたら、また報告させていただきます。

NXP のフォーラムの、この投稿と、投稿で紹介されている、i.MX 内蔵の I2C コントローラのドライバのパッチが、参考になりそうです:
 https://community.nxp.com/t5/QorIQ/I2C-Linux-Slave-driver-for-LS1012a/m…
 http://patchwork.ozlabs.org/project/linux-i2c/patch/20191203114809.2122…

ところで、

macfuruyaさん(2022年3月1日 6時17分):
>2).Raspberry Pi とかであれば、gpio のライブラリで、i2c のslave 用が用意されているようで、検索するとでてくるのですが
>同じように、armadillo でもi2c をslaveとして、使えるライブラリや、使う方法がありますでしょうか?

Raspberry Pi 用の、I2C slave 動作に使えるライブラリで、もしお使いになったことのあるものがあれば、教えて下さいませ。
ユーザーランドのライブラリ実装だけで I2C slave 動作を実現していたり、あるいは、Linux の i2c-gpio ドライバを利用したものであれば、Armadillo でも利用可能かも知れませんので、見てみたいと思いました。

古賀様ありがとうございます。

カーネルのビルドと、 DTB作成までは実施いたしました。

> NXP のフォーラムの、この投稿と、投稿で紹介されている、i.MX 内蔵の I2C コントローラのドライバのパッチが、参考になりそうです:
>  https://community.nxp.com/t5/QorIQ/I2C-Linux-Slave-driver-for-LS1012a/m…
>  http://patchwork.ozlabs.org/project/linux-i2c/patch/20191203114809.2122…

参考にさせていただきます。

> ところで、
> Raspberry Pi 用の、I2C slave 動作に使えるライブラリで、もしお使いになったことのあるものがあれば、教えて下さいませ。
> ユーザーランドのライブラリ実装だけで I2C slave 動作を実現していたり、あるいは、Linux の i2c-gpio ドライバを利用したものであれば、Armadillo でも利用可能かも知れませんので、見てみたいと思いました。

参考で見たのは、ここの情報でした、しかし少し使い方が特殊かもしれません。
https://raspberrypi.stackexchange.com/questions/76109/raspberry-as-an-i…

上記の記事にあるライブライのbscXfer の関連する部分を中心に調べました。
ライブラリ内では、mmap を利用してアクセスしているようです。
https://ja.wikipedia.org/wiki/Mmap

物理アドレスも、raspberry pi ごとで、切り替えするようになっているようです。
以下の資料だと、160ページの情報をもとにアクセスしているようです。
https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals…

そこで、armadillo のCPUである、NXP Semiconductors i.MX6ULL でもメモリ上で同じように
処理できるのであれば、アドレスをあわせてあげれば、利用できるのかもしれませんが、
NXP Semiconductors i.MX6ULL の詳細な資料が手元になく、調べられておりません。
データシートは、どこかで提供されていますでしょうか?

よろしくお願いいたします。

アットマークテクノの古賀です。

macfuruyaさん:
>>ところで、
>>Raspberry Pi 用の、I2C slave 動作に使えるライブラリで、もしお使いになったことのあるものがあれば、教えて下さいませ。
>>ユーザーランドのライブラリ実装だけで I2C slave 動作を実現していたり、あるいは、Linux の i2c-gpio ドライバを利用したものであれば、Armadillo でも利用可能かも知れませんので、見てみたいと思いました。
>
>参考で見たのは、ここの情報でした、しかし少し使い方が特殊かもしれません。
>https://raspberrypi.stackexchange.com/questions/76109/raspberry-as-an-i…

こちらの、pigpio ライブラリですね:
 https://abyz.me.uk/rpi/pigpio/cif.html
 https://github.com/joan2937/pigpio
ざっとソースを眺めてみました。

>上記の記事にあるライブライのbscXfer の関連する部分を中心に調べました。
>ライブラリ内では、mmap を利用してアクセスしているようです。
>https://ja.wikipedia.org/wiki/Mmap

そうですね。bscXfer では、Rasberry Pi の内蔵 I2C コントローラである BSC (Broadcom Serial Controller) のレジスタを /de/mem で mmap() して使っているようです。
ということで、Rasberry Pi のハードウェアに依存した実装ですので、汎用性は高くありませんが、面白いやり方だなと思いました。有難うございます。

>物理アドレスも、raspberry pi ごとで、切り替えするようになっているようです。
>以下の資料だと、160ページの情報をもとにアクセスしているようです。
>https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals…
>
>そこで、armadillo のCPUである、NXP Semiconductors i.MX6ULL でもメモリ上で同じように
>処理できるのであれば、アドレスをあわせてあげれば、利用できるのかもしれませんが、
>NXP Semiconductors i.MX6ULL の詳細な資料が手元になく、調べられておりません。
>データシートは、どこかで提供されていますでしょうか?

こちらからダウンロードできます:
 https://www.nxp.com/products/processors-and-microcontrollers/arm-proces…

Reference Manaul のセクションにある "i.MX 6ULL Applications Processor Reference Manual" が、i.MX 6ULL のデータシート(リファレンスマニュアル)です。

古賀様ありがとうございます。

> >NXP Semiconductors i.MX6ULL の詳細な資料が手元になく、調べられておりません。
> >データシートは、どこかで提供されていますでしょうか?
> こちらからダウンロードできます:
>  https://www.nxp.com/products/processors-and-microcontrollers/arm-proces…
> Reference Manaul のセクションにある "i.MX 6ULL Applications Processor Reference Manual" が、i.MX 6ULL のデータシート(リファレンスマニュアル)です。

資料が入手できました。
ありがとうございます。

I2C Slave通信はまだ、うまくいっておりません。
試験しているI2Cマスタ装置から機器のアドレスにアクセスすると、機器のアドレスは認識して受け付けるようですが、その後データが届きません。
1バイト目のデータの割込み処理はあるが、次の処理がないように見えますので、割込み処理あたりから見てみようと思います。

教えていただいた、パッチも当てたものがこれでいいのか、そちらも調べてみたいと思います。

アットマークテクノの古賀です。

macfuruyaさん:
>I2C Slave通信はまだ、うまくいっておりません。
>試験しているI2Cマスタ装置から機器のアドレスにアクセスすると、機器のアドレスは認識して受け付けるようですが、その後データが届きません。
>1バイト目のデータの割込み処理はあるが、次の処理がないように見えますので、割込み処理あたりから見てみようと思います。
>
>教えていただいた、パッチも当てたものがこれでいいのか、そちらも調べてみたいと思います。

そうですね。i2c-imx.c の slave 動作対応は、カーネル 5.11-rc1 で正式に取り込まれたようですから、Armadillo-IoT A6 のカーネル 4.14 に件のパッチを適用したものと、5.11 以降のものとを見比べてみるのが良いのではないかと思います:
 https://elixir.bootlin.com/linux/v5.11-rc1/source/drivers/i2c/busses/i2…

大塩様 ありがとうございます。

> 仰る通りであるため、at-dtweb で I2C3 を利用する方法が安全と思われます。
> マスタとして使用するのであれば、デフォルトで設定されている I2C ピンで問題ありません。

at-dtwebにて、I2C3 を追加しまして、装置のDTBを入れ替えました。
/dev/i2c-2 として追加されているように見えました。

> Armadillo-IoT A6 の I2C は Slave mode にすることが出来るため、技術的には可能です。
> 用意されている example コード等はありませんので、お客様で作成と検証を行っていただくことになります。
> Linuxカーネルのソースファイル内に、I2C Slave に関するドキュメントが存在しますので、そちらをご参照ください。
>
> ・ドキュメント配置場所
> \linux-v4.14-at42\Documentation\i2c\slave-interface
>
> また、デバイスツリーの config を変更する必要があります。
> 製品マニュアルの「イメージをカスタマイズする」を参考に、以下 config を有効にしてください。
>

> -> Device Drivers
>   -> I2C support
>     [*]   I2C slave support 
> 

slave support を追加してkernel をビルドしました。
さらに、I2C eeprom slave driver を改造して、 i2c-slave.aaa.c の作成と、Kconfig とMakefile の編集をして、kernel をビルドし直しました。

その上で、紹介いただいたドキュメントと同じように
# echo slave-aaa 0x1064 > /sys/bus/i2c/devices/i2c-2/new_device
を実行しました。

すると、dmesg に、以下のメッセージがでて、ハード的にサポートがないようにも見えます。
[ 2444.937647] i2c-slave-aaa 2-1064: i2c_slave_register: not supported by adapter

なにか、設定が不足していますでしょうか?
それとも、ハード的にサポートされないのでしょうか?

よろしくお願いいたします。

アットマークテクノの古賀です。

macfuruyaさん:
>すると、dmesg に、以下のメッセージがでて、ハード的にサポートがないようにも見えます。
>[ 2444.937647] i2c-slave-aaa 2-1064: i2c_slave_register: not supported by adapter
>
>なにか、設定が不足していますでしょうか?
>それとも、ハード的にサポートされないのでしょうか?

このエラーメッセージは、
 /drivers/i2c/i2c-core.c
で実装されている i2c_slave_register() が出しており、この関数の引数 client に渡された i2c_client 構造体の、adapter::algo が指す i2c_algorithm 構造体のメンバー reg_slave が NULL の場合に出すようようになっています:
 https://github.com/atmark-techno/linux-4.9-at/blob/e58af3a93f3c60c6842f…
 https://github.com/atmark-techno/linux-4.9-at/blob/e58af3a93f3c60c6842f…

ということで、以下のパッチを、i.MX シリーズの SoC 内蔵 I2C コントローラのドライバに当てる必要があるでしょう。このパッチでは、i.MX シリーズの SoC 内蔵の I2C コントローラのドライバで宣言している、i2c_algorithm 構造体型の static 変数 i2c_imx_algo の、reg_slave メンバーに設定する関数を実装しています。

macfuruyaさん(2022年3月5日 19時29分):
>>NXP のフォーラムの、この投稿と、投稿で紹介されている、i.MX 内蔵の I2C コントローラのドライバのパッチが、参考になりそうです:
>> https://community.nxp.com/t5/QorIQ/I2C-Linux-Slave-driver-for-LS1012a/m…
>> http://patchwork.ozlabs.org/project/linux-i2c/patch/20191203114809.2122…
>
>参考にさせていただきます。

古賀様 ありがとうございます。

すみません、パッチについて教えていただいていたのに、ちゃんと理解できておらず見落としておりました。

パッチを適用して、カーネルをビルドし直して、エラーがでなくなりました。
パッチの適用時に少しエラーがでましたので、手作業で修正しました。

通信確認をしていきたいと思います。

古賀様 ありがとうございます。

その後の報告と確認です。
現状は、I2Cのマスタ装置からのアクセスに対して、スレーブのアドレスに反応して、最初の割り込みはかかるのですが、継続の割り込みが発生しません。

あらためて、dmesg をみると、以下のログがありました。
i2c i2c-2: can't use DMA, using PIO instead.

どの部分で、このメッセージになるのか、調べると
i2c_imx.c 内の i2c_imx_dma_request 関数内で、
dma->chan_tx = dma_request_slave_channel(dev, "tx");
を呼び出した際に、エラーになっているようです。

DMAは使えないのが正しいのか、それとも本来は使えるはずで、なにかまだ設定が足らないのか
教えていただけないでしょうか?

よろしくお願いいたします。

アットマークテクノの古賀です。

macfuruyaさん:
>その後の報告と確認です。
>現状は、I2Cのマスタ装置からのアクセスに対して、スレーブのアドレスに反応して、最初の割り込みはかかるのですが、継続の割り込みが発生しません。

確認ですが、「割り込みがかかる」というのは、具体的に何を指しているでしょうか?
カーネル 5.11 で i2c-imx.c に取り込まれたスレーブモード動作の実装を見ると、I2C コントローラの割り込みに対して、割り込み処理関数である i2c_imx_isr() が呼び出され、そして、スレーブモードで動作している場合は、i2c_imx_isr() が i2c_imx_slave_isr() を呼び出すようになっています:
 https://elixir.bootlin.com/linux/v5.11-rc1/source/drivers/i2c/busses/i2…
 https://elixir.bootlin.com/linux/v5.11-rc1/source/drivers/i2c/busses/i2…
ここで、i2c_imx_slave_isr() の実装を見ると、i.MX6 ULL のリファレンスマニュアルにある "31.5.6 Slave mode" に記載されている通り、I2Cx_I2SR レジスタの IAAS ビットが 1 の場合、つまり、対向マスタから自身のアドレスを受信した時の割り込みであれば、I2Cx_I2SR レジスタの SRW ビットが 1 (slave transmit) か 0 (slave receive) かに応じ、I2Cx_I2CR レジスタの MTX ビットに 1 または 0 を書き込むようになっています。リファレンスマニュアルによれば、I2Cx_I2CR レジスタの MTX ビットへの書き込みにより、I2Cx_I2SR レジスタの IAAS ビットがクリアされて、その後のデータバイト受信による割り込みが発生するようです。

お手元の、パッチを当てた i2c-imx.c での実装は、カーネル 5.11 の i2c-imx.c と同じようになっているでしょうか?

ところで、

>あらためて、dmesg をみると、以下のログがありました。
>i2c i2c-2: can't use DMA, using PIO instead.
>
>どの部分で、このメッセージになるのか、調べると
>i2c_imx.c 内の i2c_imx_dma_request 関数内で、
>dma->chan_tx = dma_request_slave_channel(dev, "tx");
>を呼び出した際に、エラーになっているようです。

これは、ドライバ初期化時に DMA 有効化を試み、失敗しているのですが、その場合は、以後の I2C 送信・受信要求で DMA を使わず PIO するだけなように見えます。であれば、大きな問題ではないと思います。

>DMAは使えないのが正しいのか、それとも本来は使えるはずで、なにかまだ設定が足らないのか
>教えていただけないでしょうか?

デバイスツリーの設定で、I2C に DMA チャネルを割り当てるようにしてやれば使えるような気がします。が、「対向マスタから自分のアドレスを受信した時にしか割り込みがかからない」というのは、DMA 有効/無効とは違う要因ではないかと思いますので、まずは、スレーブモード動作時の、割り込みの応答処理について確認してみて下さいませ。

古賀様 ありがとうございます。

> 確認ですが、「割り込みがかかる」というのは、具体的に何を指しているでしょうか?
> カーネル 5.11 で i2c-imx.c に取り込まれたスレーブモード動作の実装を見ると、I2C コントローラの割り込みに対して、割り込み処理関数である i2c_imx_isr() が呼び出され、そして、スレーブモードで動作している場合は、i2c_imx_isr() が i2c_imx_slave_isr() を呼び出すようになっています:
>  https://elixir.bootlin.com/linux/v5.11-rc1/source/drivers/i2c/busses/i2…
>  https://elixir.bootlin.com/linux/v5.11-rc1/source/drivers/i2c/busses/i2…
> ここで、i2c_imx_slave_isr() の実装を見ると、i.MX6 ULL のリファレンスマニュアルにある "31.5.6 Slave mode" に記載されている通り、I2Cx_I2SR レジスタの IAAS ビットが 1 の場合、つまり、対向マスタから自身のアドレスを受信した時の割り込みであれば、I2Cx_I2SR レジスタの SRW ビットが 1 (slave transmit) か 0 (slave receive) かに応じ、I2Cx_I2CR レジスタの MTX ビットに 1 または 0 を書き込むようになっています。リファレンスマニュアルによれば、I2Cx_I2CR レジスタの MTX ビットへの書き込みにより、I2Cx_I2SR レジスタの IAAS ビットがクリアされて、その後のデータバイト受信による割り込みが発生するようです。
>
> お手元の、パッチを当てた i2c-imx.c での実装は、カーネル 5.11 の i2c-imx.c と同じようになっているでしょうか?

はい、i2c_imx_isr() から、 i2c_imx_slave_isr() その後、作成しているスレーブ用のドライバ?側にわったってきております。
作成している部分では、最初の割り込み時は届きますが、継続が届かない状態でした。

パッチと、最新のソースを比べますと、かなりの部分で違いがありました。
なので、最新のソースに近いように改造をしました。
その結果、最初の割り込のあと、継続の割り込みも届くようにはなりました。
ただ、まだうまくいかない場合もあるのでもう少し調べてみます。