Skip to content

예제 i2c_myARS USB

irmusy edited this page Oct 7, 2013 · 2 revisions

개요

본 예제는 I2C 인터페이스를 이용해 myARS-USB 장치로 부터 출력값을 읽고 그것을 파싱하는 예를 보기 위해 작성하였습니다. myARS-USB는 UART, I2C, USB 인터페이스를 지원합니다. I2C 인터페이스는 MCU와 근거리 장치간 인터페이스에 자주 사용되며, UART에 비해 비교적 고속(400kHz)의 양방향 데이터 통신 수단입니다. 또한 하나의 I2C 채널에 여러 장치를 연결하여 동시에 통신할 수 있어 MCU와 센서, 컨트롤러 등의 인터페이스에 많이 사용됩니다. I2C에 관한 보다 상세한 내용은 I2C 스펙 문서를 참조하시기 바랍니다.

LM3S8962 칩에는 한 개의 I2C 인터페이스 장치가 내장되어 있습니다. 이를 myARS-USB와 연결하여 출력값을 읽고, 그 결과를 다시 UART로 출력하는 구성이며, 회로도는 아래와 같습니다.

i2c_myARS-USB 회로도

회로도는 PDF 파일로 다운로드 받으실 수도 있습니다.

I2C에 연결된 두 개의 풀업 저항은 도선의 길이, 연결된 장치의 수 및 특성에 따라 다른 값이 될 수도 있습니다. 일반적으로 1k~10k 사이의 값이 사용되며, 오실로스코프를 이용하여 파형을 관찰했을 때 구형파의 형상이 잘 보일 정도의 저항 값을 사용해야 합니다. I2C 라인에 myCortex-LM8962와 myARS-USB만 연결되어 있고, 도선의 길이가 30cm 이하인 경우 4.7k 정도면 무리 없이 사용할 수 있습니다.

[myMCU-EXP rev.B](myMCU-EXP rev.B) 보드를 사용하는 경우 두 개의 풀업 저항이 이미 장착되어 있으므로 myARS-USB만 연결하면 됩니다.

I2C 인터페이스는 100kHz와 400kHz의 통신 속도가 있습니다. 본 예제에서는 400kHz 속도를 사용합니다. myCortex-LM8962가 I2C 마스터(master), myARS-USB가 I2C 슬레이브(slave) 역할을 하게 됩니다. myARS-USB의 I2C slave address는 0x1C입니다.

PC와 연결하기 위한 UART0 설정은 아래와 같습니다.

  • 115200bps
  • No parity bit
  • 8 data bit
  • 1 stop bit

관련 Peripheral

  • SysCtl
  • GPIO
  • I2C
  • UART

소스 살펴보기

38 line:

#include "myARS-USB.h"

myARS-USB 헤더 파일을 include합니다. 이 헤더 파일에는 myARS-USB의 I2C slave address 정의와 레지스터 어드레스 정의가 있습니다. 이 헤더 파일은 common 폴더에 있습니다.

60 line:

typedef struct
{
    short acc_x;
    short acc_y;
    short acc_z;
    short gyro_x;
    short gyro_y;
    short temp;
    short roll;
    short pitch;
} ars_t;

myARS-USB에서 결과 값을 읽어 올 때 사용할 메모리 버퍼의 구조체입니다. I2C 통신은 바이트(8 비트)단위로 이루어지므로 2 바이트로 구성된 myARS-USB의 결과 값들은 2개 바이트의 조합으로 이루어 집니다. 2 바이트의 값을 상위 바이트와 하위 바이트로 나누어 전송하고, 이를 받은 쪽에서 바이트 연산을 이용해 다시 조합하게 됩니다. 하지만 LM3S8962 칩은 little endian을 사용하는 Cortex-M3 코어이고, myARS-USB의 레지스터 순서는 little endian을 염두에 두고 정의되어 있기 때문에 이처럼 구조체로 type casting 하는 것 만으로 바이트 연산을 대신할 수 있습니다. 본 구조체는 myARS-USB의 레지스터 맵(register map)과 동일한 순서로 구성되어 있습니다.

104 line:

    //
    // Configure I2C0 for myARS-USB
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);
    I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(), true);  // 400 kHz

I2C 장치를 enable시키고 초기화합니다. I2C 인터페이스 속도를 400kHz로 설정합니다. 이 속도는 SCL 라인의 클럭 속도를 의미합니다. I2C 인터페이스에 사용되는 GPIO 핀은 PB2, PB3 입니다.

113 line:

    //
    // Set up the period for the SysTick timer.
    //
    SysTickPeriodSet(SysCtlClockGet() / 100);   // 100Hz SysTick timer
    SysTickIntEnable();
    SysTickIntRegister(SysTickIntHandler);
    SysTickEnable();

100Hz 주기로 결과값을 읽어오기 위해 100Hz 주기의 SysTick 타이머를 설정합니다. 10ms 간격으로 SysTick 타이머 인터럽트가 발생하여 myARS-USB로 부터 값을 읽어올 수 있습니다.

125 line:

    I2C_Read(ARS_REG_WHO_AM_I, &who_am_i, 1);
    printf("who am i = 0x%02X\r\n", who_am_i);

myARS-USB의 WHO_AM_I 레지스터의 값을 읽어옵니다. 이 레지스터는 항상 0xB0의 값이 읽혀져야 합니다. 이는 I2C 인터페이스나 myARS-USB가 정상 동작하는 지 확인하기 위한 레지스터입니다.

134 line:

        SysCtlSleep();

인터럽트가 발생할 때 까지 이곳에서 sleep 합니다. 위에서 100Hz 주기로 SysTick 타이머 인터럽트를 설정해 두었습니다.

137 line:

        // read registers from myARS-USB via I2C interface
        I2C_Read(ARS_REG_ACC_X_LOW, (unsigned char *)&ars, sizeof(ars_t));

I2C 장치로 부터 데이터를 읽어옵니다. 읽을 레지스터 주소는 ARS_REG_ACC_X_LOW이고, 이 레지스터로 부터 ars_t 구조체 크기(16 바이트)만큼 읽어와서 그 결과를 ars 변수에 저장합니다. ars 변수는 ars_t 형태의 구조체이지만 이를 unsigned char* 형태로 type casting하여 메모리 버퍼로 사용합니다. I2C 인터페이스를 사용하여 ARS_REG_ACC_X_LOW부터 ARS_REG_PITCH_HIGH 레지스터 까지 16 바이트의 값을 읽어오고, 그 결과를 ars 변수가 있는 메모리에 저장합니다. 이 결과를 ars_t 형태의 구조체로 재해석 하면 별도의 바이트 연산 필요 없이 바로 결과값을 얻을 수 있습니다.

141 line:

        acc_x = (float)ars.acc_x * 9.8 / 2048.;
        acc_y = (float)ars.acc_y * 9.8 / 2048.;
        acc_z = (float)ars.acc_z * 9.8 / 2048.;

        gyro_x = (float)ars.gyro_x * 0.232;
        gyro_y = (float)ars.gyro_y * 0.232;

        temp = (float)ars.temp * 0.1;

        roll = (float)ars.roll * 0.01;
        pitch = (float)ars.pitch * 0.01;

        printf("ACC[m/s/s]:%.2f,%.2f,%.2f\r\n", acc_x, acc_y, acc_z);
        printf("GYRO[deg/s]:%.2f,%.2f\r\n", gyro_x, gyro_y);
        printf("TEMP[degC]:%.1f\r\n", temp);
        printf("R/P[deg]:%.2f,%.2f\r\n\r\n", roll, pitch);
        LED_TOGGLE();

ars 구조체 변수에서 결과값을 읽어 물리량으로 계산한 후 printf()를 사용해 UART로 출력합니다.

161 line:

void SysTickIntHandler(void)
{
}

SysTick 타이머 인터럽트 핸들러입니다. SysTick 타이머는 100Hz 주기의 이벤트를 위해 사용되었기 때문에 본 인터럽트 핸들러에서는 별도로 하는 일이 없습니다.

166 line:

unsigned long I2C_Write(unsigned char addr, unsigned char *buff, unsigned long len)
{
    unsigned long l = len;

    I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, ARS_SLAVE_ADDRESS, false);
    I2CMasterDataPut(I2C0_MASTER_BASE, addr);
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MCS_START | I2C_MCS_RUN);
    while(I2CMasterBusy(I2C0_MASTER_BASE));

    while(l--)
    {
        I2CMasterDataPut(I2C0_MASTER_BASE, *buff++);
        if (l == 0)
            I2CMasterControl(I2C0_MASTER_BASE, I2C_MCS_STOP | I2C_MCS_RUN);
        else
            I2CMasterControl(I2C0_MASTER_BASE, I2C_MCS_RUN);
        while(I2CMasterBusy(I2C0_MASTER_BASE));
    }

    return len;
}

I2C에 값을 쓰는 함수입니다. 값을 받을 슬레이브 장치의 주소는 ARS_SLAVE_ADDRESS로 지정되어 있습니다. 이 슬레이브 장치의 addr 레지스터에 값을 write할 것이며, buff 변수가 가지고 있는 내용을 len 크기 만큼 write 하게 됩니다. 본 예제에서는 이 함수를 사용하지 않습니다만 참고용으로 넣어 두었습니다.

188 line:

unsigned long I2C_Read(unsigned char addr, unsigned char *buff, unsigned long len)
{
    unsigned long l;

    if (len == 0)
        return 0;

    if (!buff)
        return 0;

    I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, ARS_SLAVE_ADDRESS, false);
    I2CMasterDataPut(I2C0_MASTER_BASE, addr);
    I2CMasterControl(I2C0_MASTER_BASE, I2C_MCS_START | I2C_MCS_RUN);
    while(I2CMasterBusy(I2C0_MASTER_BASE));

    if (len == 1)
    {
        I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, ARS_SLAVE_ADDRESS, true);
        I2CMasterControl(I2C0_MASTER_BASE, I2C_MCS_STOP | I2C_MCS_START | I2C_MCS_RUN);
        while(I2CMasterBusy(I2C0_MASTER_BASE));
        *buff = I2CMasterDataGet(I2C0_MASTER_BASE);

    }
    else
    {
        l = len;
        I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, ARS_SLAVE_ADDRESS, true);
        I2CMasterControl(I2C0_MASTER_BASE, I2C_MCS_ACK | I2C_MCS_START | I2C_MCS_RUN);
        while(I2CMasterBusy(I2C0_MASTER_BASE));
        *buff++ = I2CMasterDataGet(I2C0_MASTER_BASE);

        while(l--)
        {
            if (l == 0)
                I2CMasterControl(I2C0_MASTER_BASE, I2C_MCS_STOP | I2C_MCS_RUN);
            else
                I2CMasterControl(I2C0_MASTER_BASE, I2C_MCS_ACK | I2C_MCS_RUN);
            while(I2CMasterBusy(I2C0_MASTER_BASE));
            *buff++ = I2CMasterDataGet(I2C0_MASTER_BASE);
        }
    }

    return len;
}

I2C로 부터 값을 읽어오는 함수입니다. I2C 슬레이브 어드레스는 ARS_SLAVE_ADDRESS로 고정되어 있습니다. addr 레지스터 부터 len 바이트 만큼 값을 읽어와 buff 메모리 버퍼에 저장합니다.

실행 방법 안내

  1. 제안된 회로도와 같이 myARS-USB와 myCortex-LM8962 보드를 연결합니다.
  2. 펌웨어를 빌드하여 다운로드한 후 리셋 스위치를 1회 누릅니다.
  3. PC에서 ComPortMaster를 시작하고 Stellaris-JTAG의 가상 시리얼 포트를 open합니다.
  4. 초당 100개의 메시지가 출력됨을 확인합니다.
  5. myARS-USB를 움직여 가면서 실제 움직임과 출력되는 결과 값이 일치되는지 확인합니다.