2000円もせずに400cm測れる超優秀なセンサーモジュールがあります。
4mまで測れるので単眼カメラの停止時の車間詰め補助に使おうと思っています。
ADAS搭載車両で、前方車両が発進したことを知らせる機能がある車両がありますが、大抵4m以上車両間隔が開くと通知されます。
チッ どいつもこいつもI2C使いやがって
というわけで自作RISC-VにI2Cモジュールを接続します。
といっても、私がI2Cモジュールを一生懸命1から作成するわけではなく、すでにintel Quartus Prime/Platform Designerに用意されているので、これを接続するだけです。
Avalon-MM Masterに対応するとこのようにモジュールの低レイヤを意識せず接続できるのでとても便利です。
CPU側から見ると、スレーブモジュールがSDRAMだろうとSPIメモリだろうと特定のアドレスに向けてLoad/Store命令を実行してデータのRWをしているだけです。
I2C HALの整備
NiosII用のHALを使用することはライセンス違反となる可能性があります。なので、取り急ぎHALを作りました。
Embedded Peripherals IP User Guideのp.170から、Figure 47~51,54を参考にすればさほど難しいモジュールではありません。
全体は以下を参照ください。
KyogenRV/qsys_i2c.c at master · panda5mt/KyogenRV · GitHub
VL53L1X API
STMicroからC API、PololuからArduino用のC++ APIが提供されています。Pololu提供のAPIが使いやすく思えましたので、C用に書き直しました。
全体は以下を参照ください。ライセンスはPololuをベースにしているため、3条項修正BSDライセンスに準拠しています。
KyogenRV/VL53L1X.c at master · panda5mt/KyogenRV · GitHub
動かしてみた
以下にmain.c
を示します。
#include <stdio.h> #include <stdint.h> #include "krv_utils.h" #include "xprintf.h" #define USE_VL53L1X (1) #define USE_SDRAM (1) #ifdef USE_VL53L1X #include "qsys_i2c.h" #include "VL53L1X.h" #endif //USE_VL53L1X #ifdef USE_SDRAM int32_t sdram_test(void) { uint32_t data,length; length = SDRAM_0_END - SDRAM_0_BASE; xprintf("SDRAM write start\r\n"); for (int k = 0 ; k < length ; k = k + 4) { put32(SDRAM_0_BASE + k, k); } xprintf("SDRAM read start\r\n"); for (int k = 0 ; k < length ; k = k + 4) { data = get32(SDRAM_0_BASE + k); if(data != k) { xprintf("error fount at 0x%x: expecting %d but got %d\r\n",k,k,data); return -1; } } return 0; } #endif // USE_SDRAM // main function int32_t main(int argc, char *argv[]) { uint64_t i; xdev_out(&uart_putc); // override xprintf #ifdef USE_VL53L1X xprintf("I2C init\r\n"); i2c_init(I2C_0_BASE); i2c_disable_isr(I2C_0_BASE); if(true == VL53L1X_init()) { xprintf("VL5351X init OK.\r\n"); VL53L1X_setDistanceMode(VL53L1X_Long); VL53L1X_setMeasurementTimingBudget(50000); VL53L1X_startContinuous(50); } else { xprintf("VL5351X init failed.\r\n"); } #endif //USE_VL53L1X uint32_t data = 0; #ifdef USE_SDRAM if(0 == sdram_test()) { xprintf("SDRAM r/w test OK!\r\n"); } else { xprintf("SDRAM r/w test fail......\r\n"); } #endif //USE_SDRAM xprintf("KyogenRV (RV32I) Start...\r\n"); while(1){ wait_ms(500); put32(PIO_0_BASE, 0x55); wait_ms(500); put32(PIO_0_BASE, 0xAA); #ifdef USE_VL53L1X data = VL53L1X_read(true); xprintf("value = %d\r\n",data); #endif //USE_VL53L1X i = get_time_ms() / 1000; xprintf("machine time = %llu second\r\n",i); } return 0; }
define文の
#define USE_VL53L1X (1) #define USE_SDRAM (1)
はそれぞれ、VL53L1Xを使う場合、及びSDR SDRAMを接続する場合の設定です。
使わない場合はそれぞれ0にしてください。