あったので、その報告をば。
昨年ETのときかな?にSTマイクロのブースでみつけて
いいなー、と思っていたデバイスなんで、
ことしのET Westで、これのNUCLEO Packをもらってきたん。
たしかに、応答性がよくて、取り回しも便利。
自分で実装できるパッケージじゃないのと、内部用に2.8Vが必要という
めんどくささ、も我慢できるかなーー、というのはあったんだけど
問題は、I2Cデバイスであるにも関わらず、利用するための
内部のアドレス情報がまーーーったく開示されておらず
STM32のNUCLEO用のサンプルから自分用にポーティングしないとどうしようもない
というイケてないデバイスで、つかうのを躊躇してたんですよね。
今年のETで、STの担当者にこの件、きいてみたら
『これの前のデバイスで、アドレス情報など、サポートにじゃんじゃん質問がきたから
データシートへの記載、やめてるんですよねー』
とか。
それ、あかんやろ(>_<)
で、躊躇してたんだけど、Pololuで、このデバイスボードを発見!
https://www.pololu.com/product/2490

しかも、だいぶ簡素化された状態で、Arduino用のライブラリもgitに上がっているという
なんとまぁ、うれしい状態。
で、これをPSoCでつかいたいので、これをCの形式に変換しなおしてつかってみた。
PSoCもGCCをつかっているので、本来C++が使えるはずなんだけど
現状ではCオンリーなので、しかたない。
ソースはここ。
VL53L0X.C
VL53L0X.H
[<====ソース抜粋====>]
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ================ 関数名の振り替え | |
#define IIC_MasterSendStart( x, y ) EZI2C_1_I2CMasterSendStart( x, y ) | |
#define IIC_MasterStop() EZI2C_1_I2CMasterSendStop() | |
#define IIC_MasterClearStatus() EZI2C_1_I2CMasterClearStatus() | |
#define IIC_MasterWriteByte(x) EZI2C_1_I2CMasterWriteByte( x ) | |
#define IIC_MasterStatus() EZI2C_1_I2CMasterStatus() | |
#define IIC_MasterReadBuf(x, y, z, f) EZI2C_1_I2CMasterReadBuf(x, y, z, f) | |
#define IIC_MasterWriteBuf(x, y, z, f) EZI2C_1_I2CMasterWriteBuf(x, y, z, f) | |
#define IIC_MSTR_NO_ERROR EZI2C_1_I2C_MSTR_NO_ERROR | |
#define IIC_MODE_COMPLETE_XFER EZI2C_1_I2C_MODE_COMPLETE_XFER | |
#define IIC_MODE_REPEAT_START EZI2C_1_I2C_MODE_REPEAT_START | |
#define IIC_MSTAT_RD_CMPLT EZI2C_1_I2C_MSTAT_RD_CMPLT | |
#define IIC_MSTAT_XFER_INP EZI2C_1_I2C_MSTAT_XFER_INP | |
// =============== I2C のアクセス関数 | |
extern uint32 EZIIC_MasterStop(void); | |
extern uint32 EZI2C_1_I2CMasterStatus(void); | |
extern uint32 EZI2C_1_I2CMasterClearStatus(void); | |
extern uint32 EZI2C_1_I2CMasterWriteBuf(uint32 slaveAddress, uint8 * wrData, uint32 cnt, uint32 mode); | |
extern uint32 EZI2C_1_I2CMasterReadBuf(uint32 slaveAddress, uint8 * rdData, uint32 cnt, uint32 mode); | |
extern uint32 EZI2C_1_I2CMasterGetReadBufSize(void); | |
extern uint32 EZI2C_1_I2CMasterGetWriteBufSize(void); | |
extern void EZI2C_1_I2CMasterClearReadBuf(void); | |
extern void EZI2C_1_I2CMasterClearWriteBuf(void); | |
extern uint32 EZI2C_1_I2CMasterSendStart(uint32 slaveAddress, uint32 bitRnW); | |
extern uint32 EZI2C_1_I2CMasterSendRestart(uint32 slaveAddress, uint32 bitRnW); | |
extern uint32 EZI2C_1_I2CMasterSendStop(void); | |
extern uint32 EZI2C_1_I2CMasterWriteByte(uint32 theByte); | |
extern uint32 EZI2C_1_I2CMasterReadByte(uint32 ackNack); | |
// 外部参照 | |
uint32_t timeout_start_ms ; // 経過時間の観測変数 |
[<==== ここまで ====>]
VL53L0Xの先頭部でI2Cへのアクセス関数部を別名定義してる。
PSoCの場合 PSoC5やPSoC4で、I2Cへのアクセス関数名がそれなりに変化しちゃって
固定してると、結構めんどくさい感じになりやすいので
VL53L0XでつかうI2Cの関数を、指定できるようにしてみた。
ほんとはClassがつかえれば、いいだろうし、Cであっても
関数ポインタつかえばできるのも理解してるけど、
なんとなく可読性がおちちゃうのが気になって、こういうベタなやり方にしてみた。
あと、タイムアウトを判定するために外部で
uint32_t timeout_start_ms ; // 経過時間の観測変数
を減算してやる必要があります。
main.cなどでタイマーを利用してるソースの先頭に
extern uint32_t timeout_start_ms ;
を定義して、1msのタイマーの中で
if ( timeout_start_ms ) timeout_start_ms--;
としてください。
[<====ソースサンプル====>]
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern uint32_t timeout_start_ms ; // 経過時間の観測変数 | |
extern uint8_t VL53L0X_init(uint8_t io_2v8 ); //= TRUE); | |
extern void VL53L0X_startContinuous(uint32_t period_ms ); //= 0); | |
extern void VL53L0X_stopContinuous(void); | |
extern uint16_t VL53L0X_readRangeContinuousMillimeters(void); | |
extern uint16_t VL53L0X_readRangeSingleMillimeters(void); | |
extern uint8_t VL53L0X_setSignalRateLimit(float limit_Mcps); | |
extern uint8_t VL53L0X_setVcselPulsePeriod(enum vcselPeriodType type, uint8_t period_pclks); | |
extern uint8_t VL53L0X_setMeasurementTimingBudget(uint32_t budget_us); | |
extern uint8_t VL53L0X_timeoutOccurred(void); | |
// Timer1ms | |
CY_ISR( timer_isr ) | |
{ | |
static int32 led_c = 0; | |
static int led_w = 0; | |
Timer_1_STATUS; // TCビットをクリアするためにSTATUSを空読みしておく | |
if ( timeout_start_ms) timeout_start_ms--; | |
} | |
void main(){ | |
uint16 pdist = 0; | |
CyGlobalIntEnable; /* Uncomment this line to enable global interrupts. */ | |
isr_Timer1_StartEx( timer_isr ); // タイマーの割り込みを関連づけ | |
Timer_1_Start(); // タイマースタート | |
EZI2C_1_Start(); //D6T用 I2C スタート | |
// イニシャライズ | |
VL53L0X_init( 1 ); //2.8Vモードで初期化 | |
VL53L0X_startContinuous(0); // 連続動作 | |
CyDelay(50); // 周辺デバイスの立ち上がり待ち | |
for(;;){ | |
pdist = VL53L0X_readRangeContinuousMillimeters(); // 連続読み出し | |
CyDelay(50); | |
} | |
} | |
[<==== ここまで ====>]
みたいなかんじかな。
標準状態だとサンプルが30ms間隔で行われるので、
それ以上は待ってやったほうが、いい、ってかんじですね。
観測早いし確実なのはいいなぁ。
超音波はつかいにくいし。