0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

村田ジャイロセンサSCC2230をRaspberry Piに接続

Last updated at Posted at 2021-03-28

 SCC2230は低ドリフトの1軸ジャイロ+3軸加速度センサである。インターフェースがSPIなのでSPIのインターフェースを持つマイコンであれば簡単に利用できると安易に考えたが実に大変だった。
 データシートによると32ビット(4バイト分)の同期型データ伝送が求められているので、raspberry pi の標準的なpython モジュールspidev.SpiDev()を用いて通信を行った。CSを下げてから4バイトを送信してCSを上げるという動作を行うxfer2を用いる。送信するデータはデータシートにあるStatus Summaryを読み出す命令である。
送信データ[0x7c,0x00,0x00,0xb3]

image.png

 残念ながらこれはうまくいっていない。いくら送信してもレジスタ選択エラーの応答しか返ってこない。通信時間は2m秒なので決して早くない。推奨インターバルの0.5m秒に比べても遅いぐらいである。速度を早くしても、ディレイやCSまでの間隔を変えても応答は全く変化がなかった。

 波形をよく見ると、8ビットのCLKの間に少し隙間が空いている。このICのステータスマシンはクロックパルスが等間隔で現れることを想定して動いているためにうまくいかないのではないか。
 この隙間をなくする方法を模索したがRaspberry Piで可能なのかどうかもはっきりしなかった。
 ではSPIのポートの使用をやめてGPIOを4本使ってプログラムでポートを操作する方法に変えることにした。
 このICでは通信データのワードのチェックにCRC8を使用するのでカスタムなCRCを計算できるモジュールが必要である。pythonに標準のcrcでは対応していなかったので、こちらを使用した。

#scc-2230 module gpio

# CS GPIO05 OUT
# MISO GPIO06 IN
# MOSI GPIO13 OUT
# CLK GPIO19 OUT

import sys
import os
import time
import datetime
import RPi.GPIO as GPIO
from crc.crc import CrcCalculator, Configuration

class scc2230():
def init(self):
BCM2708_PERI_BASE=0x20000000
GPIO_BASE=(BCM2708_PERI_BASE + 0x00200000)
BLOCK_SIZE=4096

    self.CS = 5
    self.MISO=6
    self.MOSI=13
    self.CLK=19

    self.comdata={
        "RATE":0x040000f7,
        "ACCX":0x100000e9,
        "ACCY":0x140000ef,
        "ACCZ":0x180000e5,
        "TEMP":0x1c0000e3,
        "RATE1":0x240000c7,
        "RATE2":0x280000cd,
        "ACC":0x3c0000d3,
        "HARDRESET":0xd8000431,
        "MONITOR":0xd80008ad,
        "ID0":0x600000a1,
        "ID1":0x640000a7,
        "STAT":0x6c0000ab,
        "SUMMARY":0x7c0000b3,
        "FLT60":0xfc200006,
        "FLT10":0xfc1000c7,
        "READID":0x740000bf
    }

    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    GPIO.setup(self.CS, GPIO.OUT)
    GPIO.setup(self.MISO, GPIO.IN)
    GPIO.setup(self.MOSI, GPIO.OUT)
    GPIO.setup(self.CLK, GPIO.OUT)

    GPIO.output(self.CS, 1)
    GPIO.output(self.MOSI, 0)
    GPIO.output(self.CLK, 0)

    #CRC checker
    width = 8
    poly=0x1d
    init_value=0xff
    final_xor_value=0xff
    reverse_input=False
    reverse_output=False
    configuration = Configuration(width, poly, init_value, final_xor_value, reverse_input, reverse_output)
    use_table = True
    self.crc_calculator = CrcCalculator(configuration, use_table)

    #acc-2230 setup

    time.sleep(0.02)
    self.sendcom(self.comdata["FLT60"])
    time.sleep(0.73)

    self.sendcom(self.comdata["RATE1"])
    #self.sendcom(self.comdata["STAT"])
    self.sendcom(self.comdata["RATE2"])
    #self.sendcom(self.comdata["STAT"])
    self.sendcom(self.comdata["ACC"])
    #self.sendcom(self.comdata["STAT"])
    self.sendcom(self.comdata["SUMMARY"])
    #self.sendcom(self.comdata["STAT"])
    self.sendcom(self.comdata["READID"])
    #self.sendcom(self.comdata["STAT"])
    self.sendcom(self.comdata["SUMMARY"])

    #wait for ready

    while True:
        flag,readByteArray = self.sendcom(self.comdata["SUMMARY"])
        print(u"stat {0}".format(flag),hex(readByteArray))
        flag,readByteArray = self.sendcom(self.comdata["STAT"])
        print(u"summary {0}".format(flag),hex(readByteArray))

        if flag and readByteArray&0x4900 == 0x4900:
            break
        time.sleep(0.1)
        
def BinToint(self,data):
    val=(data>>8)&0xffff
    if val>32767:
        val-=65536
    return val

def rateconv(self,data):
    val=self.BinToint(data)
    rate=val/50.0 #deg/sec
    return rate

def accconv(self,data):
    val=self.BinToint(data)
    acc=val/5886.0 #g
    return acc

def tempconv(self,data):
    val=self.BinToint(data)
    temp=val/14.7+60.0 #°C
    return temp


def sendcom(self,comdata):
    cnt=0
    indata=0b0
    #print(u"send",hex(comdata))
    GPIO.output(self.CS, 0) #CS assert
    while cnt < 32:
    #CS
        if comdata & 0x80000000:
            GPIO.output(self.MOSI, 1)
        else:
            GPIO.output(self.MOSI, 0)

        indata<<=1

        GPIO.output(self.CLK, 1) #CLK assert

        indata+=GPIO.input(self.MISO)

        GPIO.output(self.CLK, 0) #CS negate

        comdata<<=1
        cnt+=1

    GPIO.output(self.CS, 1) #CS assert

    #print(u"recv",hex(indata))

    # check crc8
    csum=indata&0xff
    dat2=(indata>>8)&0xff
    dat1=(indata>>16)&0xff
    dat0=(indata>>24)&0xff

    checksum = self.crc_calculator.calculate_checksum([dat0,dat1,dat2])
    if checksum != csum:
        print("crc error ",hex(dat0),hex(dat1),hex(dat2),hex(csum))
        return False,indata

    return True,indata

def readdata(self):

    flag,stat = self.sendcom(self.comdata["RATE"])
    if flag==False:
        print("flag1 error",stat)
        return False
    flag,rate = self.sendcom(self.comdata["ACCX"])
    if flag==False:
        print("flag2 error",rate)
        return False
    flag,accx = self.sendcom(self.comdata["ACCY"])
    if flag==False:
        print("flag3 error",accx)
        return False
    flag,accy = self.sendcom(self.comdata["ACCZ"])
    if flag==False:
        print("flag4 error",accy)
        return False
    flag,accz = self.sendcom(self.comdata["TEMP"])
    if flag==False:
        print("flag5 error",accz)
        return False
    flag,temp = self.sendcom(self.comdata["STAT"])
    if flag==False:
        print("flag6 error",temp)
        return False
    return (rate,accx,accy,accz,temp)

def __del__(self):
    GPIO.cleanup(self.CS)
    GPIO.cleanup(self.MOSI)
    GPIO.cleanup(self.MISO)
    GPIO.cleanup(self.CLK)

if name=='main':
# main program

scc=scc2230()

while True:
    values=scc.readdata()
    if isinstance(values,bool):
        print(u"data error ")
    else:
        rate=scc.rateconv(values[0])
        accx=scc.accconv(values[1])
        accy=scc.accconv(values[2])
        accz=scc.accconv(values[3])
        temp=scc.tempconv(values[4])
        print(u"values {0} {1} {2} {3} {4}".format(rate,accx,accy,accz,temp))
    time.sleep(0.01)
    
    
del scc
sys.exit()

この書き換えにより通信が安定しデータが取り出せるようになった。

 ソフトウエア処理によりクロックに隙間がなくなったために解決したのだろうか。測定したところ、8ビットごとの隙間はなくなったが、OSのディスパッチもあるのでクロックパルスにあちこちに隙間がある。

image.png

 それでも安定しているということは、8ビットごとの隙間の繰り返しこそ問題が発生する要因となっていると推測される。

 GPIOのアクセス速度が遅いので通信は1.2ミリ秒くらいはかかる。このあたりはC言語を用いてレジスタを直接アクセスすれば早くなるだろう。通信のためのCPUの負荷はかなりのものなので使いにくいICではある。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?