본문 바로가기

[TI]/MSPM0G5187

[MSPM0G5187-SM] I2C 테스트 - 거리 감지 센서(VL53L0X) 테스트

[MSPM0G5187 SM] 보드에는   UART, I2C 모듈들을 연결할 수 있는 커넥터가 있어 I2C 센서들을  쉽게 연결하고 Serial FND과 같은 디버깅 모듈로 간단히 표시할 수 있다.

 

간단히 I2C 거리 감지 모듈(VL53L0X)로 거리 출력값을 표시 해보자.

 

SysConfig로 I2C를 추가 하고 핀맵을 할당한다.

 

 

I2C로 거리 감지 센서의 데이터를 읽으려고 기존에 사용했던 Read/Write 함수를 사용 하는데... 에러가 발생한다.

 

void HAL_I2C_Master_Transmit(I2C_Regs *i2c, uint8_t addr, uint8_t *buf, uint16_t len, uint16_t timeout)
{
    volatile uint32_t waitCount;

    DL_I2C_fillControllerTXFIFO(i2c, buf, len);

    /* Wait for I2C to be Idle */
    waitCount = timeout * 10;

    while (!(
        DL_I2C_getControllerStatus(i2c) & DL_I2C_CONTROLLER_STATUS_IDLE));

    /* Send the packet to the controller.
     * This function will send Start + Stop automatically.
     */
    DL_I2C_startControllerTransfer(i2c, addr>>1, DL_I2C_CONTROLLER_DIRECTION_TX, len);


    /* Poll until the Controller writes all bytes */
    while (
        DL_I2C_getControllerStatus(i2c) & DL_I2C_CONTROLLER_STATUS_BUSY)
        ;

    /* Trap if there was an error */
    if (DL_I2C_getControllerStatus(i2c) &
        DL_I2C_CONTROLLER_STATUS_ERROR) {
        /* LED will remain high if there is an error */
        __BKPT(0);
    }

    /* Wait for I2C to be Idle */
    while (!(
        DL_I2C_getControllerStatus(i2c) & DL_I2C_CONTROLLER_STATUS_IDLE));
}

 

 

확인 결과MSPM05178은 최신 출시된 칩셋이고 SDK 버전도 업데이트 되면서 I2C부분에서 수정된것이 많은것 같다.

기존 I2C 코드에서 Read시 문제가 있었는데 수정이 좀 되었으려나?

일단 최신 코드 기준으로 I2C관련 코드를 다시 작성했다.

void HAL_I2C_Master_Transmit(I2C_Regs *i2c, uint8_t addr, uint8_t *buf, uint16_t len, uint16_t timeout)
{
    DL_I2CC_fillTXFIFO(i2c, buf, len);

    /* Wait for I2C to be Idle */
    while (!(
        DL_I2CC_getStatus(i2c) & DL_I2CC_STATUS_IDLE))
        ;

    /* Send the packet to the controller.
     * This function will send Start + Stop automatically.
     */
    DL_I2CC_startTransfer(i2c, addr>>1, DL_I2CC_DIRECTION_TX, len);

    /* Workaround for errata I2C_ERR_13 */
    delay_cycles(32000);

    /* Poll until the Controller writes all bytes */
    while (
        DL_I2CC_getStatus(i2c) & DL_I2CC_STATUS_BUSY)
        ;

    /* Trap if there was an error */
    if (DL_I2CC_getStatus(i2c) &
        DL_I2CC_STATUS_ERROR) {
        /* LED will remain high if there is an error */
        //__BKPT(0);
    }

    /* Wait for I2C to be Idle */
    while (!(
        DL_I2CC_getStatus(i2c) & DL_I2CC_STATUS_IDLE))
        ;
        #endif
}

 

기존에 테스트 했던 LTR559 거리 감지 센서는 10mm 내외의 짧은 거리만 측정이 가능한데 이번에는 VL53L0X 센서를 이용해서 2000mm 까지 감지 가능하도록 해 보자.

 

최대한 간한하게 거리 값만 출력하는 예제 코드를 작성했다. 거리 값을 좀더 정밀하고 안정되게 출력하려면 센서 내부 MCU의 설정을 최신 코드로 해 주어야 한다고 한다. 우선 MSPM0G5187의 I2C가 정상동작 하는지 간단히 값이 출력되는지만 확인해 보자.

#define I2C_INST           I2C_0_INST
#define I2C_TIMEOUT_COUNT 1000
#define VL53L0X_ADDR         (0x29 << 1)

#define REG_SYSRANGE_START                   0x00
#define REG_SYSTEM_SEQUENCE_CONFIG           0x01
#define REG_SYSTEM_INTERRUPT_CONFIG_GPIO     0x0A
#define REG_SYSTEM_INTERRUPT_CLEAR          0x0B
#define REG_RESULT_INTERRUPT_STATUS         0x13
#define REG_RESULT_RANGE_STATUS              0x14

#define REG_GPIO_HV_MUX_ACTIVE_HIGH				0x84

uint8_t VL53L0X_Init()
{
    uint8_t id;

    id = i2c_read_reg(VL53L0X_ADDR, 0xC0);

    if(id != 0xEE)
        return 0;

    // 기본 설정
    i2c_write_reg(VL53L0X_ADDR, 0x88, 0x00);
    i2c_write_reg(VL53L0X_ADDR, 0x80, 0x01);
    i2c_write_reg(VL53L0X_ADDR, 0xFF, 0x01);
    i2c_write_reg(VL53L0X_ADDR, 0x00, 0x00);

    uint8_t stop_variable =  i2c_read_reg(VL53L0X_ADDR, 0x91);
    i2c_write_reg(VL53L0X_ADDR, 0x00, 0x01);
    i2c_write_reg(VL53L0X_ADDR, 0xFF, 0x00);
    i2c_write_reg(VL53L0X_ADDR, 0x80, 0x00);

    i2c_write_reg(VL53L0X_ADDR, REG_SYSTEM_INTERRUPT_CONFIG_GPIO, 0x04);
    i2c_write_reg(VL53L0X_ADDR, REG_GPIO_HV_MUX_ACTIVE_HIGH, i2c_read_reg(VL53L0X_ADDR, REG_GPIO_HV_MUX_ACTIVE_HIGH) & ~0x10); // Active Low

    i2c_write_reg(VL53L0X_ADDR, REG_SYSTEM_INTERRUPT_CLEAR, 0x01);

    i2c_write_reg(VL53L0X_ADDR, REG_SYSRANGE_START, 0x02);

    return 1;
}

uint16_t VL53L0X_ReadDistance(void) {
    uint8_t high, low;
    uint16_t distance = 0;
    uint32_t timeout = 0;

    while ((i2c_read_reg(VL53L0X_ADDR, REG_RESULT_INTERRUPT_STATUS) & 0x07) == 0) {
        timeout++;
        if (timeout > 50000) return 0xFFFF;
    }

    high = i2c_read_reg(VL53L0X_ADDR, 0x1E);
    low  = i2c_read_reg(VL53L0X_ADDR, 0x1F);
    distance = (high << 8) | low;

    i2c_write_reg(VL53L0X_ADDR, REG_SYSTEM_INTERRUPT_CLEAR, 0x01);

    return distance;
}


int main(void)
{
    uint8_t id = 0;
	unsigned int distance = 0;
	uint8_t led_mask;
    
    SYSCFG_DL_init();
   
    Led1On();
    delay_ms(1000);

    VL53L0X_Init();

    while (1) {
        distance = VL53L0X_ReadDistance();
        PrintFND(distance);
        delay_ms(50);  
    }
}