LoginSignup
2
1

More than 3 years have passed since last update.

STM32でWiiのヌンチャクを使う

Posted at

はじめに

freeRTOSの勉強のため、STM32F103をArduinoでは無くSTM32CubeIDEを使用していろいろ動作させる。
今回はI2Cデバイスの操作として家に転がっていたWiiのヌンチャクを動作させた。

使用した環境

  • ハードウェア

    • マイコン :STM32F103C8T6 (別名Black Pill) 300円ぐらい
    • デバッガ :ST-LinkV2-1 (NUCLEO付属のものを使用) 1500円ぐらい
    • Wiiヌンチャク (白、Wii本体の発売日に購入)
    • USBシリアル変換 (こんなの)
  • ソフトウェア

    • STM32CubeIDE (ST社公式からダウンロード)
    • freeRTOS   (上記CubeIDEに内包されている)

ハードウェアの準備

  1. ヌンチャクとマイコンを接続するため、ヌンチャクのケーブルをバラし4本の線

    • 白:GND
    • 赤:3.3V
    • 緑:SDA
    • 黄:SCL を出します。
  2. I2C用のプルアップ抵抗の接続
     2本の抵抗(2~3KΩ程度)を使用し、SDA,SCLと3.3Vを抵抗でつなぐ。

  3. マイコンとの接続
     4線を下記のように接続します。

マイコン側 --- ヌンチャク側
GND --- 白:GND
V3 --- 赤:3.3V
PB7 --- 緑:SDA
PB6 --- 黄:SCL

 (SDA,SCLはプルアップ抵抗経由で3.3Vにも接続されています)

I2C仕様

arduinoのライブラリなどから以下のことが分かった。

基本情報

  • デバイスID : 0x52@7bit
  • 初期化 : 2Byteライト[0x40,0x00]
  • データ読み出し : 0x00をライト後6Byteリードする 

動作波形

  • 初期化
    初期化.png

  • データ読み出し時の0x00ライト
    リクエスト.png

  • データ読み出し
    read.png

リードデータ仕様

暗号化について

 データは暗号化されているため以下の数式を使用して複合する
 result = (input ^ 0x17) + 0x17

リードデータ内部

リードデータ bit割付 説明 備考
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

総評

ボタンとスティックの情報は正常に取得できたが、
加速センサの値が正しいかどうか判断できない。
(傾けると重力加速度の方向の値が変わることは確認できるが…)

 

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1