FC2カウンター FPGAの部屋 FPGAを使用したシステム
fc2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

3 軸加速度センサーのメイン基板と 3 軸加速度センサー基板に部品を搭載した

3 軸加速度センサーのメイン基板(2021/07/02)”の続き。

前回は、 3 軸加速度センサーの基板からの I2C 信号を受けて、ZYBO Z7-20 に接続するメイン基板を作成した。今回はその 3 軸加速度センサー基板と 3 軸加速度センサーのメイン基板に部品を搭載した。

3 軸加速度センサーのメイン基板は結構壮観だ。規模が大きい。
ストロベリーリナックスさんの”LTC4331 絶縁型I2C延長モジュール(2個セット) ”が並んでいるのが壮観だ。
下の JB から JE のヘッダは ZYBO Z7-20 と接続する。
IMG_20210721_153631604.jpg

3 軸加速度センサー基板だ。こちらもストロベリーリナックスさんの”LTC4331 絶縁型I2C延長モジュール(2個セット) ”がある。メイン基板と I2C で接続しているので、当然だが。。。
IMG_20210721_153710726.jpg

すでに 1CH だけだが、動作は確認している。

(追記) 3D プリンタの Adventure 3 で作成した 3 軸加速度センサー基板のケースを貼っておきます。
IMG_20210806_094637248.jpg

ケースの裏です。ネジ頭は底面より引っ込む様にプリントしてあります。
IMG_20210806_094713224_HDR.jpg

これは何でしょう? 秘密です。。。
IMG_20210806_094746351.jpg
  1. 2021年09月03日 05:50 |
  2. FPGAを使用したシステム
  3. | トラックバック:0
  4. | コメント:0

3 軸加速度センサーのメイン基板(2021/07/02)

AXI4-Lite インターフェースの I2C Master Core を使用して 3 軸加速度度センサーの値を収集する4(NMJ2884U1を使用してスレーブ側の電源をON/OFFする)”の続きで、”新しく 3 軸加速度センサー基板を作成する”の続き。

ストロベリーリナックスさんの”LTC4331 絶縁型I2C延長モジュール(2個セット) ”のスレーブ側に付けるストロベリーリナックスさんの”ADXL355 超低ノイズ3軸加速度センサモジュール”は同じ値をずっと出力して、リセットが効かないことがある。そこで、秋月電子の低飽和型レギュレーター 3.3V500mA NJM2884U1-33 を使用して、スレーブ側の電源を GPIO で ON/OFF できるようにした。前回は、その 3 軸加速度センサーの基板を作成した。今回は、 3 軸加速度センサーの基板からの I2C 信号を受けて、ZYBO Z7-20 に接続するメイン基板を作成した。

回路図はこんな感じだ。
acc_sensor_6_210702.png

一部を拡大すると、ストロベリーリナックスさんの”LTC4331 絶縁型I2C延長モジュール(2個セット) ”や秋月電子の低飽和型レギュレーター 3.3V500mA NJM2884U1-33 が見えると思う。これで、”新しく 3 軸加速度センサー基板を作成する”の基板の電源を ON/OFF することができる。
acc_sensor_7_210702.png

基板はこんな感じだ。
acc_sensor_8_210702.png

昨日、基板ができあがってきた。
acc_sensor_4_210702.jpg
acc_sensor_5_210702.jpg

247 mm X 147 mm の基板なので、かなり大きかった。
  1. 2021年07月02日 04:43 |
  2. FPGAを使用したシステム
  3. | トラックバック:0
  4. | コメント:0

新しく 3 軸加速度センサー基板を作成する(2021/07/01)

AXI4-Lite インターフェースの I2C Master Core を使用して 3 軸加速度度センサーの値を収集する4(NMJ2884U1を使用してスレーブ側の電源をON/OFFする)”の続き。

前回、ストロベリーリナックスさんの”LTC4331 絶縁型I2C延長モジュール(2個セット) ”のスレーブ側に付けるストロベリーリナックスさんの”ADXL355 超低ノイズ3軸加速度センサモジュール”は同じ値をずっと出力して、リセットが効かないことがある。そこで、秋月電子の低飽和型レギュレーター 3.3V500mA NJM2884U1-33 を使用して、スレーブ側の電源を GPIO で ON/OFF できるようにした。今回は、その 3 軸加速度センサーの基板を作成した。

回路図を示す。
acc_sensor_1_210701.png

SCL と SDA 用のプルアップ抵抗は 1 kΩが 2 つ並列になっているが、 1 個しか基板に乗せない予定だ。つまり 1 kΩということだ。
この基板はメイン基板から LANケーブルで電源を供給してもらう基板になっている。

基板を示す。
acc_sensor_2_210701.png

やはり、”LTC4331 絶縁型I2C延長モジュール(2個セット) ”が付いているので基板が大きくなってしまった。

(2021/07/02 :追記)
昨日できあがった基板が届いた。
acc_sensor_3_210702.jpg
  1. 2021年07月01日 05:21 |
  2. FPGAを使用したシステム
  3. | トラックバック:0
  4. | コメント:0

AXI4-Lite インターフェースの I2C Master Core を使用して 3 軸加速度度センサーの値を収集する4(NMJ2884U1を使用してスレーブ側の電源をON/OFFする)

AXI4-Lite インターフェースの I2C Master Core を使用して 3 軸加速度度センサーの値を収集する3”の続き。

ストロベリーリナックスさんの”LTC4331 絶縁型I2C延長モジュール(2個セット) ”のスレーブ側に付けるストロベリーリナックスさんの”ADXL355 超低ノイズ3軸加速度センサモジュール”は同じ値をずっと出力して、リセットが効かないことがある。そこで、秋月電子の低飽和型レギュレーター 3.3V500mA NJM2884U1-33 を使用して、スレーブ側の電源を GPIO で ON/OFF できるようにした。
下図にそのブロック図を示す。
i2cm_axi4ls_17_210601.png

ZYBO Z7-20 の Vivado 2020.2 プロジェクトの acc_sensor_pow_202 を示す。
i2cm_axi4ls_18_210601.png

ブロックデザインを示す。
i2cm_axi4ls_19_210601.png

ZYBO Z7-20 のスライドスイッチの SW0 で NJM2884U1-33 の CONTROL 端子を制御する。

Address Map を示す。
i2cm_axi4ls_20_210601.png

制約ファイルを示す。

set_property IOSTANDARD LVCMOS33 [get_ports iic_0_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports iic_0_sda_io]
set_property PACKAGE_PIN V8 [get_ports iic_0_scl_io]
set_property PACKAGE_PIN W8 [get_ports iic_0_sda_io]

set_property PACKAGE_PIN G15 [get_ports {SW0[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {SW0[0]}]
set_property PACKAGE_PIN V12 [get_ports {POW_CONTROL[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {POW_CONTROL[0]}]


論理合成、インプリメンテーション、ビットストリームの生成を行った。
Project Summary を示す。
i2cm_axi4ls_21_210601.png

ハードウェアをエクスポートして、Vitis を立ち上げた。
Vitis でプラットフォームとアプリケーション・プロジェクトを作成し、アプリケーション・ソフトウェアを作成して、ZYBO Z7-20 で確かめてみたところ、SW0 を ON した 0.5 秒後に 3軸加速度センサーの計測がスタートした。SW0 を OFF すると 3軸加速度センサーの計測が止まった。何度やっても ON/OFF することができた。成功だ。
i2cm_axi4ls_22_210601.png

実際の実験の様子を示す。ピンクの丸で囲った部分が NJM2884U1-33 だ。
i2cm_axi4ls_23_210601.jpg

アプリケーション・ソフトウェア acc_sensor_pow.c を示す。

// acc_sensor_pow.c
// 2021/05/28 by marsee
// コード中のコメント部分は”OpenCores.org の I2C controller core ”のマニュアルから引用した
// https://opencores.org/projects/i2c

#include <stdio.h>
#include <stdint.h>
#include "xil_io.h"
#include "xparameters.h"
#include <unistd.h>
#include "xtime_l.h"
#include "xgpio.h"

#define I2CM_PRER_LO    XPAR_I2CM_AXI4LS_0_BASEADDR
#define I2CM_PRER_HI    (XPAR_I2CM_AXI4LS_0_BASEADDR+0x4)
#define I2CM_CTR        (XPAR_I2CM_AXI4LS_0_BASEADDR+0x8)
#define I2CM_RXR        (XPAR_I2CM_AXI4LS_0_BASEADDR+0xc)
#define I2CM_TXR        (XPAR_I2CM_AXI4LS_0_BASEADDR+0xc)
#define I2CM_CR         (XPAR_I2CM_AXI4LS_0_BASEADDR+0x10)
#define I2CM_SR         (XPAR_I2CM_AXI4LS_0_BASEADDR+0x10)

#define CR_STA      0x80    // generate (repeated) start condition
#define CR_STO      0x40    // generate stop condition
#define CR_RD       0x20    // read from slave
#define CR_WR       0x10    // write from slave
#define CR_NACK     0x08    //  when a receiver, sent ACK (ACK = ‘0’) or NACK (ACK = ‘1’)
#define CR_IACK     0x01    // Interrupt acknowledge. When set, clears a pending interrupt.

#define SR_RxACK    0x80    // Received acknowledge from slave.This flag represents acknowledge from  the addressed slave.
                            // ‘1’ = No acknowledge received , ‘0’ = Acknowledge received
#define SR_Busy     0x40    // I2C bus busy
                            // ‘1’ after START signal detected , ‘0’ after STOP signal detected
#define SR_AL       0x20    // Arbitration lost. This bit is set when the core lost arbitration. Arbitration is lost when:
                            // * a STOP signal is detected, but non requested , * The master drives SDA high, but SDA is low.
#define SR_TIP      0x02    // Transfer in progress.
                            // ‘1’ when transferring data , ‘0’ when transfer complete
#define SR_IF       0x01    //  Interrupt Flag. This bit is set when an interrupt is pending, which
                            //  will cause a processor interrupt request if the IEN bit is set.
                            //  The Interrupt Flag is set when:
                            // *  one byte transfer has been completed , *  arbitration is lost

#define SW0_GPIO            1
#define POW_CONTROL_GPIO    2

void idle_check(){
    while(Xil_In32(I2CM_SR) & SR_TIP); // TIP bit is clear
}
void acc_sensor_write(uint8_t dev_addr, uint8_t waddr, uint8_t wdata){
    dev_addr &= 0xfe;
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)dev_addr);
    Xil_Out32(I2CM_CR, (u32)(CR_STA|CR_WR));
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)waddr);
    Xil_Out32(I2CM_CR, (u32)CR_WR);
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)wdata);
    Xil_Out32(I2CM_CR, (u32)(CR_STO|CR_WR));
    idle_check();
}
uint8_t acc_sensor_read1(uint8_t dev_addr, uint8_t raddr){
    const uint8_t devw_addr = dev_addr & 0xfe;

    dev_addr |= 0x01;
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)devw_addr);
    Xil_Out32(I2CM_CR, (u32)(CR_STA|CR_WR));
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)raddr);
    Xil_Out32(I2CM_CR, (u32)CR_WR);
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)dev_addr);
    Xil_Out32(I2CM_CR, (u32)(CR_STA|CR_WR));
    idle_check();

    Xil_Out32(I2CM_CR, (u32)(CR_STO|CR_RD|CR_NACK));
    idle_check();

    uint8_t rdata8 = (uint8_t)(Xil_In32(I2CM_RXR) & 0xff);
    return(rdata8);
}
void acc_sensor_read3(uint8_t dev_addr, uint8_t raddr, int32_t *rdata){
    uint8_t rdata8a[3];
    const uint8_t devw_addr = dev_addr & 0xfe;

    dev_addr |= 0x01;
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)devw_addr);
    Xil_Out32(I2CM_CR, (u32)(CR_STA|CR_WR));
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)raddr);
    Xil_Out32(I2CM_CR, (u32)CR_WR);
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)dev_addr);
    Xil_Out32(I2CM_CR, (u32)(CR_STA|CR_WR));
    idle_check();

    Xil_Out32(I2CM_CR, (u32)CR_RD);
    idle_check();
    rdata8a[0] = (uint8_t)(Xil_In32(I2CM_RXR) & 0xff);

    Xil_Out32(I2CM_CR, (u32)CR_RD);
    idle_check();
    rdata8a[1] = (uint8_t)(Xil_In32(I2CM_RXR) & 0xff);

    Xil_Out32(I2CM_CR, (u32)(CR_STO|CR_RD|CR_NACK));
    idle_check();
    rdata8a[2] = (uint8_t)(Xil_In32(I2CM_RXR) & 0xff);

    *rdata = (((int32_t)rdata8a[0])<<12) + (((int32_t)rdata8a[1])<<4) + (((int32_t)(rdata8a[2] & 0xf0))>>4);
    if(*rdata & 0x80000) // Is the 19th bit 1?
        *rdata |= 0xfff00000; // sign extension
}

void initialize_code(){
    // I2C I2C operating frequency setting 433KHz/100MHz, 415kHz/96MHz
    Xil_Out32(I2CM_PRER_LO, (u32)0x29);
    Xil_Out32(I2CM_PRER_HI, (u32)0x0);

    Xil_Out32(I2CM_CTR, 0x80); // enable core

    acc_sensor_write(0x3a, 0x2c, 0x83); // I2C speed is Hi speed, +-8g
    acc_sensor_write(0x3a, 0x1e, 0x00); // OFFSET_X_H
    acc_sensor_write(0x3a, 0x1f, 0x00); // OFFSET_X_L
    acc_sensor_write(0x3a, 0x20, 0x00); // OFFSET_Y_H
    acc_sensor_write(0x3a, 0x21, 0x00); // OFFSET_Y_L
    acc_sensor_write(0x3a, 0x22, 0x00); // OFFSET_Z_H
    acc_sensor_write(0x3a, 0x23, 0x00); // OFFSET_Z_L

    acc_sensor_write(0x3a, 0x2d, 0x00); // stanby clear
}

int main(){
    uint8_t read_data, read_rdy;
    int32_t dataX, dataY, dataZ;
    XTime cur_time;
    XGpio XGpio_ap;
    int status;

    // GPIOの初期化
    status = XGpio_Initialize(&XGpio_ap, XPAR_AXI_GPIO_0_BASEADDR);
    if (status != XST_SUCCESS) return XST_FAILURE;
    XGpio_SetDataDirection(&XGpio_ap, SW0_GPIO, 1); // input
    XGpio_SetDataDirection(&XGpio_ap, POW_CONTROL_GPIO, 0); // output
    uint8_t sw0_state = XGpio_DiscreteRead(&XGpio_ap, SW0_GPIO);
    XGpio_DiscreteWrite(&XGpio_ap, POW_CONTROL_GPIO, sw0_state);
    if((sw0_state & 1) == 0){
        do {
            sw0_state = XGpio_DiscreteRead(&XGpio_ap, SW0_GPIO);
            XGpio_DiscreteWrite(&XGpio_ap, POW_CONTROL_GPIO, sw0_state);
            usleep(500000); // 500 ms Wait
        }while((sw0_state & 1) == 0);
    }

    initialize_code();

    while(1){
        do{
            read_data = acc_sensor_read1(0x3b, 0x04);
            read_rdy = read_data & 0x01;
        }while(read_rdy != 0x01);

        acc_sensor_read3(0x3b, 0x08, &dataX);
        acc_sensor_read3(0x3b, 0x0b, &dataY);
        acc_sensor_read3(0x3b, 0x0e, &dataZ);

        XTime_GetTime(&cur_time);
        printf("%lf,%x,%x,%x\n", (double)((long long int)cur_time)/333333.3435, (int)dataX, (int)dataY, (int)dataZ);

        usleep(2434); // for 400 kHz

        sw0_state = XGpio_DiscreteRead(&XGpio_ap, SW0_GPIO);
        if((sw0_state & 1) == 0){
            do {
                sw0_state = XGpio_DiscreteRead(&XGpio_ap, SW0_GPIO);
                XGpio_DiscreteWrite(&XGpio_ap, POW_CONTROL_GPIO, sw0_state);
                usleep(500000); // 500 ms Wait
            }while((sw0_state & 1) == 0);
            XGpio_DiscreteWrite(&XGpio_ap, POW_CONTROL_GPIO, 1);
            initialize_code();
        }
    }
}

  1. 2021年06月01日 04:27 |
  2. FPGAを使用したシステム
  3. | トラックバック:0
  4. | コメント:0

AXI4-Lite インターフェースの I2C Master Core を使用して 3 軸加速度度センサーの値を収集する3

AXI4-Lite インターフェースの I2C Master Core を使用して 3 軸加速度度センサーの値を収集する2”の続き。

前回は、クロック・ストレッチング付きの i2cm_axi4ls IP を使った回路で、3軸加速度センサーのデータを受け取ることができた。今回は、ストロベリーリナックスさんの”LTC4331 絶縁型I2C延長モジュール(2個セット) ”を使って、I2C を 15m 延長する。

配線の様子を示す。
i2cm_axi4ls_12_210510.jpg

I2C 延長側の3軸加速度センサーの I2C の波形を示す。スレーブ側は約 1 MHz で、マスタ側が 430 KHz 程度なので、スレーブ側(3軸加速度センサー側)はクロック・ストレッチングされているようだが、LTC4331(マスタ)側でやっているので、スレーブの 3 軸加速度センサーにとっては、通常の I2C と変わりが無いと思う。下が SCK で上が SDA だ。
i2cm_axi4ls_13_210510.jpg

拡大する。
SCK の最後の 2 山の間隔が短いのが分かると思う。
i2cm_axi4ls_14_210510.jpg

今度は ZYBO Z7-20 のマスタ側の波形を見る。こちらは約 430 KHz なので、クロック・ストレッチングの様子は見えない。
スレーブ側が速いのでクロック・ストレッチングする必要がないためだと思う。
i2cm_axi4ls_15_210510.jpg

拡大する。
i2cm_axi4ls_16_210510.jpg

なお、プルアップ抵抗はマスタ側、スレーブ側共に 1 KΩとなっている。

15m のケーブルを付けて 8 時間連続運転したが、問題なく通信できていた。
  1. 2021年05月11日 04:23 |
  2. FPGAを使用したシステム
  3. | トラックバック:0
  4. | コメント:0

AXI4-Lite インターフェースの I2C Master Core を使用して 3 軸加速度度センサーの値を収集する2

AXI4-Lite インターフェースの I2C Master Core を使用して 3 軸加速度度センサーの値を収集する1”の続き。

AXI4-Lite インターフェースの I2C Master Core を IP にする”で作成した AXI4-Lite インターフェースの I2C Master Core IP を使用して、ストロベリーリナックスの ADXL355 超低ノイズ3軸加速度センサモジュールのデータを I2C で収集してみようということで、前回は、Vivado 2020.2 でプロジェクトを作成し、i2cm_axi4ls IP を使ってブロックデザインを作成し、論理合成、インプリメンテーション、ビットストリームを生成して成功した。そして、ハードウェアをエクスポートした。今回は、Vitis 2020.2 を立ち上げて、プラットフォームとアプリケーション・ソフトウェアを作成して、ZYBO Z7-20 とストロベリーリナックスの ADXL355 超低ノイズ3軸加速度センサモジュールで試してみよう。

Vivado 2020.2 の Tools メニューから Launch Vitis を選択して、Vitis 2020.2 を立ち上げた。
acc_sensor_202 ディレクトリに下に、vitis_work ディレクトリを作成して、Workspace とした。
acc_bd_wrapper プラットフォームと acc_sensor アプリケーション・プロジェクトを作成した。
acc_sensor.c アプリケーション・ソフトウェアを作成して、ビルドしたところ、成功し、acc_sensor.elf が生成された。
i2cm_axi4ls_6_210426.png

ZYBO Z7-20 とストロベリーリナックスの ADXL355 超低ノイズ3軸加速度センサモジュールを接続した。
SCL と SDA のプルアップ抵抗はそれぞれ 1 kΩにしてある。
i2cm_axi4ls_7_210426.jpg

アプリケーション・ソフトウェアを Run すると、3軸加速度センサーのセンサー・データを取得することができた。成功だ。うまく行ってよかった。。。
i2cm_axi4ls_11_210426.png

I2C の波形を示す。
i2cm_axi4ls_8_210426.jpg

拡大する。
i2cm_axi4ls_9_210426.jpg

クロックの周期を測定した。 2.32 us だった。周波数にすると 431 kHz だった。
i2cm_axi4ls_10_210426.jpg

acc_sensor.c を貼っておく。

// acc_sensor.c
// 2021/04/19 by marsee
// コード中のコメント部分は”OpenCores.org の I2C controller core ”のマニュアルから引用した
// https://opencores.org/projects/i2c

#include <stdio.h>
#include <stdint.h>
#include "xil_io.h"
#include "xparameters.h"
#include <unistd.h>
#include "xtime_l.h"

#define I2CM_PRER_LO    XPAR_I2CM_AXI4LS_0_BASEADDR
#define I2CM_PRER_HI    (XPAR_I2CM_AXI4LS_0_BASEADDR+0x4)
#define I2CM_CTR        (XPAR_I2CM_AXI4LS_0_BASEADDR+0x8)
#define I2CM_RXR        (XPAR_I2CM_AXI4LS_0_BASEADDR+0xc)
#define I2CM_TXR        (XPAR_I2CM_AXI4LS_0_BASEADDR+0xc)
#define I2CM_CR         (XPAR_I2CM_AXI4LS_0_BASEADDR+0x10)
#define I2CM_SR         (XPAR_I2CM_AXI4LS_0_BASEADDR+0x10)

#define CR_STA      0x80    // generate (repeated) start condition
#define CR_STO      0x40    // generate stop condition
#define CR_RD       0x20    // read from slave
#define CR_WR       0x10    // write from slave
#define CR_NACK     0x08    //  when a receiver, sent ACK (ACK = ‘0’) or NACK (ACK = ‘1’)
#define CR_IACK     0x01    // Interrupt acknowledge. When set, clears a pending interrupt.

#define SR_RxACK    0x80    // Received acknowledge from slave.This flag represents acknowledge from  the addressed slave.
                            // ‘1’ = No acknowledge received , ‘0’ = Acknowledge received
#define SR_Busy     0x40    // I2C bus busy
                            // ‘1’ f after START signal detected , ‘0’ after STOP signal detected
#define SR_AL       0x20    // Arbitration lost. This bit is set when the core lost arbitration. Arbitration is lost when:
                            // * a STOP signal is detected, but non requested , * The master drives SDA high, but SDA is low.
#define SR_TIP      0x02    // Transfer in progress.
                            // ‘1’ f when transferring data , ‘0’f when transfer complete
#define SR_IF       0x01    //  Interrupt Flag. This bit is set when an interrupt is pending, which
                            //  will cause a processor interrupt request if the IEN bit is set.
                            //  The Interrupt Flag is set when:
                            // *  one byte transfer has been completed , *  arbitration is lost

void idle_check(){
    while(Xil_In32(I2CM_SR) & SR_TIP); // TIP bit is clear
}
void acc_sensor_write(uint8_t dev_addr, uint8_t waddr, uint8_t wdata){
    dev_addr &= 0xfe;
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)dev_addr);
    Xil_Out32(I2CM_CR, (u32)(CR_STA|CR_WR));
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)waddr);
    Xil_Out32(I2CM_CR, (u32)CR_WR);
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)wdata);
    Xil_Out32(I2CM_CR, (u32)(CR_STO|CR_WR));
    idle_check();
}
uint8_t acc_sensor_read1(uint8_t dev_addr, uint8_t raddr){
    const uint8_t devw_addr = dev_addr & 0xfe;

    dev_addr |= 0x01;
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)devw_addr);
    Xil_Out32(I2CM_CR, (u32)(CR_STA|CR_WR));
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)raddr);
    Xil_Out32(I2CM_CR, (u32)CR_WR);
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)dev_addr);
    Xil_Out32(I2CM_CR, (u32)(CR_STA|CR_WR));
    idle_check();

    Xil_Out32(I2CM_CR, (u32)(CR_STO|CR_RD|CR_NACK));
    idle_check();

    uint8_t rdata8 = (uint8_t)(Xil_In32(I2CM_RXR) & 0xff);
    return(rdata8);
}
void acc_sensor_read3(uint8_t dev_addr, uint8_t raddr, int32_t *rdata){
    uint8_t rdata8a[3];
    const uint8_t devw_addr = dev_addr & 0xfe;

    dev_addr |= 0x01;
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)devw_addr);
    Xil_Out32(I2CM_CR, (u32)(CR_STA|CR_WR));
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)raddr);
    Xil_Out32(I2CM_CR, (u32)CR_WR);
    idle_check();

    Xil_Out32(I2CM_TXR, (u32)dev_addr);
    Xil_Out32(I2CM_CR, (u32)(CR_STA|CR_WR));
    idle_check();

    Xil_Out32(I2CM_CR, (u32)CR_RD);
    idle_check();
    rdata8a[0] = (uint8_t)(Xil_In32(I2CM_RXR) & 0xff);

    Xil_Out32(I2CM_CR, (u32)CR_RD);
    idle_check();
    rdata8a[1] = (uint8_t)(Xil_In32(I2CM_RXR) & 0xff);

    Xil_Out32(I2CM_CR, (u32)(CR_STO|CR_RD|CR_NACK));
    idle_check();
    rdata8a[2] = (uint8_t)(Xil_In32(I2CM_RXR) & 0xff);

    *rdata = (((int32_t)rdata8a[0])<<12) + (((int32_t)rdata8a[1])<<4) + (((int32_t)(rdata8a[2] & 0xf0))>>4);
    if(*rdata & 0x80000) // Is the 19th bit 1?
        *rdata |= 0xfff00000; // sign extension
}

int main(){
    uint8_t read_data, read_rdy;
    int32_t dataX, dataY, dataZ;
    XTime cur_time;

    // I2C I2C operating frequency setting 433KHz/100MHz, 415kHz/96MHz
    Xil_Out32(I2CM_PRER_LO, (u32)0x29);
    Xil_Out32(I2CM_PRER_HI, (u32)0x0);

    Xil_Out32(I2CM_CTR, 0x80); // enable core

    acc_sensor_write(0x3a, 0x2c, 0x83); // I2C speed is Hi speed, +-8g
    acc_sensor_write(0x3a, 0x1e, 0x00); // OFFSET_X_H
    acc_sensor_write(0x3a, 0x1f, 0x00); // OFFSET_X_L
    acc_sensor_write(0x3a, 0x20, 0x00); // OFFSET_Y_H
    acc_sensor_write(0x3a, 0x21, 0x00); // OFFSET_Y_L
    acc_sensor_write(0x3a, 0x22, 0x00); // OFFSET_Z_H
    acc_sensor_write(0x3a, 0x23, 0x00); // OFFSET_Z_L

    acc_sensor_write(0x3a, 0x2d, 0x00); // stanby clear

    while(1){
        do{
            read_data = acc_sensor_read1(0x3b, 0x04);
            read_rdy = read_data & 0x01;
        }while(read_rdy != 0x01);

        acc_sensor_read3(0x3b, 0x08, &dataX);
        acc_sensor_read3(0x3b, 0x0b, &dataY);
        acc_sensor_read3(0x3b, 0x0e, &dataZ);

        XTime_GetTime(&cur_time);
        printf("%lf,%x,%x,%x\n", (double)((long long int)cur_time)/333333.3435, (int)dataX, (int)dataY, (int)dataZ);

        usleep(2434); // for 400 kHz
    }
}

  1. 2021年04月27日 04:20 |
  2. FPGAを使用したシステム
  3. | トラックバック:0
  4. | コメント:0

AXI4-Lite インターフェースの I2C Master Core を使用して 3 軸加速度度センサーの値を収集する1

AXI4-Lite インターフェースの I2C Master Core を IP にする”で作成した AXI4-Lite インターフェースの I2C Master Core IP を使用して、ストロベリーリナックスの ADXL355 超低ノイズ3軸加速度センサモジュールのデータを I2C で収集してみよう。
しかし、やっとこれで目的を達成することができる。結構長かった。

Vivado 2020.2 で acc_sensor_202 プロジェクトを作成した。
i2cm_axi4ls_1_210425.png

AXI4-Lite インターフェースの I2C Master Core を IP にする”の IP を acc_sensor_202 ディレクトリの下に i2cm_axi4ls ディレクトリを作成して、 marsee101_user_i2cm_axi4ls_1.0.zip の中身をコピーした。

acc_bd ブロックデザインを新規作成して、Zynq Processing System 7 プロセッサ IP を Add IP し、 i2cm_axi4ls IP も Add IP して回路を完成させた。
i2cm_axi4ls_2_210425.png

Address Map を示す。
i2cm_axi4ls_3_210425.png

制約ファイルの acc_sensor.xdc を貼っておく。

set_property IOSTANDARD LVCMOS33 [get_ports iic_0_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports iic_0_sda_io]
set_property PACKAGE_PIN V8 [get_ports iic_0_scl_io]
set_property PACKAGE_PIN W8 [get_ports iic_0_sda_io]


これで、論理合成、インプリメンテーション、ビットストリームの生成を行って、成功した。
Project Summary を示す。
i2cm_axi4ls_4_210425.png

ハードウェアをエクスポートして、acc_bd_wrapper.xsa を生成した。
i2cm_axi4ls_5_210426.png
  1. 2021年04月26日 04:58 |
  2. FPGAを使用したシステム
  3. | トラックバック:0
  4. | コメント:0
»