TinyGoを使用したAE-BMX055の動作プログラムの作成

## 1．はじめに
　今までAruduinoやルネサス系のマイコンを利用してC言語でプログラムを書くことが多かったのですが、最近の言語を学習したいと思い、Micropythonに取り組んでいました。MicroPythonは結構色々な人が取り組んでネット上での資料も多くあったので、私がやっていることが少しでも利用できる人がいたら良いと思い、またGo言語にも少し興味があったのでTinyGoに取り組んでみることにしました。 

## 2. ハードウェアについて
　今回はとりあえず手元にあった9軸センサモジュールのAE-BMX055とSeeed XIAOを使って製作しました。Seeed XIAOはTinyGoをサポートしているので開発しやすいと思います。
　下の図は今回の製作した回路図です。
![AE-BMX055.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271682/10204077-64e8-527d-de6e-d2b83cd79bbe.png)

## 3．プログラムについて
　AE-BMX055はI2Cを使用するので、[TinyGo Drivers](https://github.com/tinygo-org/drivers)をインストールして開発しました。
　プログラムはTinyGo Driversを利用してI2Cで加速度、角速度、地磁気のデータを取得しています。
　下のプログラムはAE-BMX055の制御関係のプログラムです。 

```golang:bmx055.go
package bmx055

import (
	"time"
	"tinygo.org/x/drivers"
)

type bmx055_data struct {
	// Acc
	XAcc float64
	YAcc float64
	ZAcc float64

	// Gyaro
	XGyro float64
	YGyro float64
	ZGyro float64

	// Mag
	XMag int32
	YMag int32
	ZMag int32
}

type Device struct {
	bus         drivers.I2C
	AccAddress  uint8
	GyroAddress uint8
	MagAddress  uint8
	Dat         bmx055_data
}

func New(bus drivers.I2C) Device {
	return Device{
		bus:         bus,
		AccAddress:  ACCAddress,
		GyroAddress: GyroAddress,
		MagAddress:  MagAddress,
	}
}

/* Init*/
func (d *Device) Configture() {
	/* Acc*/
	_ = d.bus.WriteRegister(d.AccAddress, AccPmuRangeReg, []byte{0x03})
	_ = d.bus.WriteRegister(d.AccAddress, AccPmuBwReg, []byte{0x08})
	_ = d.bus.WriteRegister(d.AccAddress, AccPmuLpwReg, []byte{0x00})
	time.Sleep(100 * time.Millisecond)

	/* Gyro*/
	_ = d.bus.WriteRegister(d.GyroAddress, GyroRangeReg, []byte{0x04})
	_ = d.bus.WriteRegister(d.GyroAddress, GyroBwReg, []byte{0x07})
	_ = d.bus.WriteRegister(d.GyroAddress, GyroLpm1Reg, []byte{0x00})
	time.Sleep(100 * time.Millisecond)

	/* Mag */
	_ = d.bus.WriteRegister(d.MagAddress, MagPowCtlReg, []byte{0x83})
	time.Sleep(100 * time.Millisecond)
	_ = d.bus.WriteRegister(d.MagAddress, MagPowCtlReg, []byte{0x01})
	time.Sleep(100 * time.Millisecond)

	_ = d.bus.WriteRegister(d.MagAddress, MagAdvOpOutputReg, []byte{0x00})
	_ = d.bus.WriteRegister(d.MagAddress, MagAxesReg, []byte{0x84})
	_ = d.bus.WriteRegister(d.MagAddress, MagRepXyReg, []byte{0x04})
	_ = d.bus.WriteRegister(d.MagAddress, MagRepZReg, []byte{0x16})

}

//isConnected
func (d *Device) IsConnected() bool {
	data := make([]byte, 1)
	_ = d.bus.ReadRegister(d.AccAddress, BGW_CHIPID, data)
	return data[0] == 0xfa
}

/* Get Acceralater Data Function */
func (d *Device) GetAcc() error {
	data := make([]byte, 6)
	err := d.bus.ReadRegister(d.AccAddress, AccDataStartReg, data)
	if err != nil {
		println(err)
		return err
	}
	// Get ACC Data

	x := int32(uint16(data[1])*256|uint16(data[0]&0xf0)) >> 4
	if x > 2047 {
		x -= 4096
	}
	y := int32(uint16(data[3])*256|uint16(data[2]&0xf0)) >> 4
	if y > 2047 {
		y -= 4096
	}
	z := int32(uint16(data[5])*256|uint16(data[4]&0xf0)) >> 4
	if z > 2047 {
		z -= 4096
	}

	d.Dat.XAcc = float64(x) * 0.0196
	d.Dat.YAcc = float64(y) * 0.0196
	d.Dat.ZAcc = float64(z) * 0.0196

	return nil
}

/* Get Gyro Data Function */
func (d *Device) GetGyro() error {
	data := make([]byte, 6)
	err := d.bus.ReadRegister(d.GyroAddress, GyroDataStartReg, data)
	if err != nil {
		println(err)
		return err
	}

	// Get Gyro Data
	x := int32(uint16(data[1])<<8 | uint16(data[0]))
	if x > 32767 {
		x -= 65536
	}
	y := int32(uint16(data[3])<<8 | uint16(data[2]))
	if y > 32767 {
		y -= 65536
	}
	z := int32(uint16(data[5])<<8 | uint16(data[4]))
	if z > 32767 {
		z -= 65536
	}

	//
	d.Dat.XGyro = float64(x) * 0.0038
	d.Dat.YGyro = float64(y) * 0.0038
	d.Dat.ZGyro = float64(z) * 0.0038

	return nil
}

/* Get Magnetic Filed Data Function */
func (d *Device) GetMag() error {

	data := make([]byte, 6)

	err := d.bus.ReadRegister(d.MagAddress, MagDataStartReg, data)
	if err != nil {
		println(err)
		return err
	}
	// Get ACC Data
	d.Dat.XMag = int32(uint16(data[1])<<8|uint16(data[0]&0xf8)) / 8
	if d.Dat.XMag > 4095 {
		d.Dat.XMag -= 8192
	}
	d.Dat.YMag = int32(uint16(data[3])<<8|uint16(data[2]&0xf8)) / 8
	if d.Dat.YMag > 4095 {
		d.Dat.YMag -= 8192
	}
	d.Dat.ZMag = int32(uint16(data[5])<<8|uint16(data[4]&0xfe)) / 2
	if d.Dat.ZMag > 16383 {
		d.Dat.ZMag -= 32768
	}
	return nil
}

```
下のプログラムは動作確認用のプログラムです。

```golang:main.go
package bmx055

import (
	"fmt"
	"machine"
	"time"
)

func main() {

	var err error

	machine.I2C0.Configure(machine.I2CConfig{})
	d := New(machine.I2C0)

	conected := d.IsConnected()

	// BMX055 is Conenect ?
	if !conected {
		// Not Connected
		println("Not Connected!")
		for {
		}
	}

	// Initilaize For BMX055
	d.Configture()

	for {

		/* Get Accelerometer Data */
		err = d.GetGyro()
		if err == nil {
			fmt.Printf("Gyro : x=%5.2f y=%5.2f z=%5.2f\n", d.Dat.XGyro, d.Dat.YGyro, d.Dat.ZGyro)
		}

		/* Get Gyro Data */
		err = d.GetAcc()
		if err == nil {
			fmt.Printf("Acc  : x=%5.2f y=%5.2f z=%5.2f\n", d.Dat.XAcc, d.Dat.YAcc, d.Dat.ZAcc)
		}

		/* Get Geomagnetic sensor Data*/
		err = d.GetMag()
		if err == nil {
			fmt.Printf("Mag  : x=%4d y=%4d z=%4d\n", d.Dat.XMag, d.Dat.YMag, d.Dat.ZMag)
		}

		fmt.Println()

		time.Sleep(100 * time.Millisecond)
	}
}

```
## 4. 動作の様子
　下の図のようにシリアルポート経由で角速度、加速度、地磁気のデータが出力されます。
![Terminal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271682/08f2b4af-4235-aa61-4f69-4e5c14ba05b8.png)

## 5. 最後に
　今回のTinyGoのプログラムを作ってみて、Go言語の楽しさがわかってきました。Go言語をやり始めて3週間ぐらいですが、何とか本などを見ながら、サンプルプログラムを作ることができました。まだまだ、未完成ですがとりあえずはデータを取得できるので何かに活用できると思います。
　もし、良かったら[ここ](https://github.com/Keisuke-Hongyo/BMX055)に公開していますので、自由に使ってください。
　次は色々なセンサを組み合わせて実際に役立つものをに取り組みたいと思います。