STM32에서 Wii의 Nunchak 사용

소개



freeRTOS의 공부를 위해, STM32F103을 Arduino는 아니고 STM32CubeIDE를 사용해 여러가지 동작시킨다.
이번에는 I2C 디바이스의 조작으로 집으로 굴러 갔던 Wii의 은척을 동작시켰다.

사용한 환경



  • 하드웨어
  • 마이크로 컴퓨터 : STM32F103C8T6 (일명 Black Pill) 300 엔 정도
  • 디버거:ST-LinkV2-1( NUCLEO 부속의 것을 사용) 1500엔 정도
  • Wii 은 척 (흰색, Wii 본체의 발매일에 구입)
  • USB 시리얼 변환 ( 이런거 )


  • 소프트웨어
  • STM32CubeIDE (ST 사 공식에서 다운로드)
  • freeRTOS (상기 CubeIDE에 포함되어 있음)


  • 하드웨어 준비



  • Nunchak과 마이크로 컴퓨터를 연결하기 위해 Nunchak 케이블을 버리고 4 개의 선
  • 흰색: GND
  • 빨강: 3.3V
  • 녹색: SDA
  • 황:SCL
    를 꺼냅니다.

  • I2C용 풀업 저항 연결
    2개의 저항(2~3KΩ 정도)을 사용하여 SDA, SCL과 3.3V를 저항으로 연결한다.
  • 마이크로 컴퓨터와의 접속
    4선을 아래와 같이 접속합니다.



  • 마이크로 컴퓨터 측
    ---
    은척 측


    GND
    ---
    흰색: GND

    V3
    ---
    빨강: 3.3V

    PB7
    ---
    녹색: SDA

    PB6
    ---
    노랑: SCL


    (SDA, SCL은 풀업 저항을 통해 3.3V에 연결됩니다)

    I2C 사양



    arduino의 라이브러리 등에서 다음을 알 수 있었다.

    기본 정보


  • 디바이스 ID: 0x52@7bit
  • 초기화: 2Byte 라이트[0x40,0x00]
  • 데이터 읽기 : 0x00을 라이트 후 6Byte 리드한다

  • 동작 파형


  • 초기화
  • 데이터 읽기시 0x00 라이트
  • 데이터 읽기

  • 리드 데이터 사양



    암호화 정보



    데이터는 암호화되어 있으므로 다음 수식을 사용하여 복합
    result = (input ^ 0x17) + 0x17

    리드 데이터 내부




    리드 데이터
    비트 할당
    설명
    비고


    1Byte 눈
    [7:0]
    조이스틱 X축
    중앙값 130, 왼쪽으로 기울이면 감소

    2Byte 눈
    [7:0]
    조이스틱 Y축
    센터 값 130, 아래로 기울이면 감소

    3Byte 눈
    [7:0]
    가속도 센서 X축
    [9:2]bit의 값(하위 2bit는 6Byte째에 존재)

    4Byte 눈
    [7:0]
    가속도 센서 Y축
    [9:2]bit의 값(하위 2bit는 6Byte째에 존재)

    5Byte 눈
    [7:0]
    가속도 센서 Z축
    [9:2]bit의 값(하위 2bit는 6Byte째에 존재)

    6Byte 눈
    [7:6][5:4][3:2][1][0]
    가속도 센서 Z축 가속도 센서 Y축 가속도 센서 X축 C 버튼 Z 버튼
    [1:0]bit눈[1:0]bit눈[1:0]bit눈누름시 0누름시 0


    소스 코드



    라이브러리 이외의 부분의 소스는 다음과 같이 된다
    // ヌンチャク構造体宣言
    typedef struct {
        uint8_t joy_x;
        uint8_t joy_y;
        uint8_t button_c;
        uint8_t button_z;
        uint16_t accel_x;
        uint16_t accel_y;
        uint16_t accel_z;
    }wiiNunchuck;
    // HALライブラリでは7bitアドレスを左シフトして設定する
    #define WII_NUNCHUCK_DEV_ID ((0x52)<<1)
    
    // ディレイ関数、置き換えやすいように関数化
    static void userDelay(uint32_t millisec)
    {
        osDelay(millisec);
    }
    
    // データリード前に0x00をライト
    static void send_request(I2C_HandleTypeDef *hi2c)
    {
        uint8_t pData[2] = {0x00, 0x00};
        HAL_I2C_Master_Transmit(hi2c, WII_NUNCHUCK_DEV_ID, pData, 1, 3000);
    }
    
    // 複合
    static uint8_t decode_byte(uint8_t x)
    {
        return ((x ^ 0x17) + 0x17);
    }
    
    // データリード
    void WiiNunchuck_getKey(I2C_HandleTypeDef *hi2c, wiiNunchuck *keyStatus)
    {
        int cnt=0;
        uint8_t rxData[6],decData[6];
    
        send_request(hi2c);
        userDelay(2);
    
        // 6Byteリード
        HAL_I2C_Master_Receive(hi2c, WII_NUNCHUCK_DEV_ID|0x01 , rxData, 6, 3000);
    
        // データ複合
        for(cnt=0; cnt<6; cnt++){
            decData[cnt] = decode_byte(rxData[cnt]);
        }
    
        // 構造体へ代入
        keyStatus->joy_x = decData[0];
        keyStatus->joy_y = decData[1];
        keyStatus->button_c = (decData[5]>>1) & 0x01;
        keyStatus->button_z = (decData[5]>>0) & 0x01;
        keyStatus->accel_x = (((uint16_t)decData[2])<<2) | ((decData[5]>>2) & 0x03);
        keyStatus->accel_y = (((uint16_t)decData[3])<<2) | ((decData[5]>>4) & 0x03);
        keyStatus->accel_z = (((uint16_t)decData[4])<<2) | ((decData[5]>>6) & 0x03);
    
    }
    
    // ヌンチャク初期化
    void WiiNunchuck_init(I2C_HandleTypeDef *hi2c)
    {
        uint8_t pData[2] = {0x40, 0x00};
        HAL_I2C_Master_Transmit(hi2c, WII_NUNCHUCK_DEV_ID, pData, 2, 3000);
    
    }
    

    동작 결과



    출력 예




    멤버 이름



    joy_x
    131

    joy_y
    131

    button_c
    1

    button_z
    1

    accel_x
    696

    accel_y
    509

    accel_z
    543


    총평



    버튼과 스틱 정보는 성공적으로 얻을 수 있었지만,
    가속 센서의 값이 올바른지 여부를 결정할 수 없습니다.
    (기울면 중력 가속도 방향의 값이 바뀌는 것은 확인할 수 있지만…)

     

    좋은 웹페이지 즐겨찾기