2013年10月30日水曜日

Raspberry Pi でAD 12bit 8ch モジュールを使ってみる

Raspberry Pi でAD 12bit 2ch モジュールを使用してみます。
その際のサンプルプログラムについて説明します。
C言語はwiringpiを使います。


#include "common.h"

#include "MCUGear.h"
#include "MCUGearBase.h"
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <wiringPiSPI.h>
#include <stdio.h>

int read12bit8chAD(MCUGear *mcugear, int spichan, char ch);
void IOSimpleSPI(MCUGear *mcugear);

int main(void){

int spiSpeed = 1000000; //1MHz
int spiChan = 0; //CE0

int data[8];

if(wiringPiSetup() == -1)//wiringpiのセットアップ
return 1;

if(wiringPiSPISetup(spiChan, spiSpeed)== -1) //set CE0 and 1MHz//SPIのセットアップ
return 1;

pinMode(pin, OUTPUT);
pinMode(sw, INPUT);
pinMode(outpin[0], OUTPUT);
pinMode(outpin[1], OUTPUT);
pinMode(outpin[2], OUTPUT);
pinMode(outpin[3], OUTPUT);
pinMode(outpin[4], OUTPUT);
pinMode(outpin[5], OUTPUT);

initBase(); //initialize Baseboard   //ベースボード初期化

MCUGear AD8chM = MCUGear(N_SDA_SDA_SDA, 4); 
        //モジュール基板の裏に設定したアドレスとSPIバス 4ピン
        //任意名称「AD8chM 」という名前でモジュールを定義しています

   //Set IO --------------------------
    IOSimpleSPI(&AD8chM);
   //GPIOのどの端子をモジュールをどの端子に当てはめるかを定義する
   //---------------------------------------------------------------------
    
while(1){

//8ch AD module AD8chM.connectModule(); //connect--- //GPIOからモジュールまで配線を再構築 data[0] = read12bit8chAD(&AD8chM ,spiChan ,0);//AD0chをAD変換 data[1] = read12bit8chAD(&AD8chM ,spiChan ,1);//AD1chをAD変換 data[2] = read12bit8chAD(&AD8chM ,spiChan ,2); data[3] = read12bit8chAD(&AD8chM ,spiChan ,3); data[4] = read12bit8chAD(&AD8chM ,spiChan ,4); data[5] = read12bit8chAD(&AD8chM ,spiChan ,5); data[6] = read12bit8chAD(&AD8chM ,spiChan ,6); data[7] = read12bit8chAD(&AD8chM ,spiChan ,7); AD8chM.disconnectModule(); //disconnect---//GPIOからモジュールまで配線を切断 printf("AD0 = %d, AD1 = %d, AD2 = %d, AD3 = %d, AD4 = %d, AD5 = %d, AD6 = %d, AD7 = %d\n",data[0], data[1],data[2], data[3],data[4], data[5],data[6], data[7]);//ターミナルに表示

}

return 0;
}


void IOSimpleSPI(MCUGear *mcugear){


    unsigned char fio[12];

    // detect
    mcugear->detect_module(fio);//モジュールの取り付け位置を把握
    delay(100);
    printf("fio[0] = %d",fio[0]);
//1:MISO 13
//2:MOSI 12
//3:SCK  14
//4:CE0  10   
    
    mcugear->savePinSetting(0, IO_13, IO_REG_IN_DIR, fio[0]);//input モジュールの0番端子にMISOを割り当てる
    mcugear->savePinSetting(1, IO_12, IO_REG_OUT_DIR, fio[1]);//output モジュールの1番にMOSIを割り当てる
    mcugear->savePinSetting(2, IO_14, IO_REG_OUT_DIR, fio[2]);//output モジュールの2番にSCKを割り当てる
    mcugear->savePinSetting(3, IO_10, IO_REG_OUT_DIR, fio[3]);//output モジュールの3番にCE0を割り当てる

#ifdef BOOST_MODE
    mcugear->makeCircuit();//追々説明します
#endif

}


//MCP3204とのSPI通信 通常配線したデジタル回路として扱います

int read12bit8chAD(MCUGear *mcugear, int spichan,char ch){

int value = 0;
unsigned char spiBuff[3];

if(ch < 8){
spiBuff[0] = 0x18 + ch;
spiBuff[0] = (spiBuff[0] << 2);
spiBuff[1] = 0;
spiBuff[2] = 0;
 
}else{
return -1;
}

wiringPiSPIDataRW(spichan,spiBuff,3);
value = spiBuff[1] << 8;
value = spiBuff[2] + value;
value = value >> 4;

return value;
}


FRDM-KL25Z で AD 12bit 8chモジュールを使う

mbedでAD 12bit 8chモジュールを使う場合の説明です。
取得したアナログデータはUSBを通してPCで表示できます。TeraTermなどで確認してみてください。
MCU Gearの各プログラムをダウンロードしてmain.cppに以下のように記述すれば動きます。



#include "mbed.h"


#include "MCUGearBase.h"

#include "MCUGear.h"
#include "common.h"//このファイルの中にある#define LPC1768_mbedを有効、//#define FS_KL25Zを無効にする

//Initialize modules-----------------------------------------------------------------------

MCUGear AD8ch12M(PTE0, PTE1, N_SDA_SDA_SDA,4);    //AD(MCP3208) 12bit 8ch Module
//p28,p27はI2C通信バスです。I2Cでデジタルスイッチ群を操作し配線を再構築しています 
//N_SCL_SCL_VSSはモジュール基板裏面に設定したアドレスです
//SPI通信をするので4ピン再構築します
//ここでは任意の名前「AD8ch12M」という名前で登録しています
//-----------------------------------------------------------------------------------------

//Sample setting-----------------------------------------------------------------------

SPI spi(PTD2,PTD3,PTD1); // mosi, miso, sclk
DigitalOut cs(PTD0); //for SPI communications
Serial pc(USBTX, USBRX); // tx, rx
//-------------------------------------------------------------------------------------

//sample functions------------------------------------------------------------

void IOSimpleSPI(MCUGear *mcugear);             //IO setting for Simple SPI module
int read12bit8chAD(MCUGear *mcugear, char ch);  //simple ADC 8ch   //I2C端子と、モジュール基板の裏にアドレスを設定、4つの信号端子を使う
//----------------------------------------------------------------------------

//***************************************************************************************

int main() {
    
    initBase(); //initialize Baseboard//ベースボードの初期化

   //Set IO --------------------------------------------------------------

    IOSimpleSPI(&AD8ch12M);
   //IOの配線情報を保存しmbedのどの端子をモジュールのどの端子に当てはめるかを決めます
   //--------------------------

    int data2[8];

    while(1) {
       //12bit AD Mobdule-------------------------------------------------

       cs = 1; //reset CS pin
       AD8ch12M.connectModule();   //connect---//配線情報を基にモジュールとマイコン端子との配線を再構築します
//一度構築すると普通のデジタル回路と同じように扱えます
       data2[0] = read12bit8chAD(&AD8ch12M, 0);    //0ch//AD 0chの値を取得します
       data2[1] = read12bit8chAD(&AD8ch12M, 1);    //1ch
       data2[2] = read12bit8chAD(&AD8ch12M, 2);    //2ch
       data2[3] = read12bit8chAD(&AD8ch12M, 3);    //3ch
       data2[4] = read12bit8chAD(&AD8ch12M, 4);    //4ch
       data2[5] = read12bit8chAD(&AD8ch12M, 5);    //5ch
       data2[6] = read12bit8chAD(&AD8ch12M, 6);    //6ch
       data2[7] = read12bit8chAD(&AD8ch12M, 7);    //7ch
       AD8ch12M.disconnectModule();   //disconnect---//マイコンとモジュールの配線を切断します

       pc.printf("AD 0ch = %d  1ch = %d\n",whoami[0],whoami[1]);//PCに送ります

       wait(0.5);

    }    

}
//***************************************************************************************


//モジュールに搭載されているMCP3202のデバイスを動かすための関数です


//----------------------------------------------------------------------------------
//Simple write for 12bit 8ch AD module
//----------------------------------------------------------------------------------
int read12bit8chAD(MCUGear *mcugear, char ch){

    char sendData;
    int whoami[3];
    
    char sendData2;
//0000 0000 0110 00 00 [0000 0000 0000]
    if(ch < 8){
        sendData = 0x18+ch; //0001 1000
        sendData2 = sendData >> 2;
        sendData = sendData << 6;
        
    }else{
        return -1;
    }
    
    //12bit AD Mobdule----------------
    spi.frequency(2000000); //1MHz for KL25Z
    cs = 0;
    spi.write(sendData2);
    whoami[2] = spi.write(sendData);
    whoami[0] = whoami[2]<<8;
    whoami[0] = whoami[0] + spi.write(0x00)-0xE000;   //get data from AD device
    cs = 1;
    return whoami[0];

}

//マイコンとモジュールの配線情報を保存します。
//----------------------------------------------------------------------------------
//IO setting for Multifunction module
//----------------------------------------------------------------------------------
void IOSimpleSPI(MCUGear *mcugear){
    uint8_t fio[12];
    mcugear->detect_module(fio);//指定したモジュールがベースボードのどこに接続されているかを探してきます
    
    //miso(PTD3),mosi(PTD2),sck(PTD1),cs(PTD0)
    mcugear->savePinSetting(0, IO_MBED_PTD3, IO_REG_IN_DIR, fio[0]);//モジュールの0番端子にMISO:IN
    mcugear->savePinSetting(1, IO_MBED_PTD2, IO_REG_OUT_DIR, fio[1]);//モジュールの1番端子にMOSI:OUT
    mcugear->savePinSetting(2, IO_MBED_PTD1, IO_REG_OUT_DIR, fio[2]);//モジュールの2番端子にSCK:OUT
    mcugear->savePinSetting(3, IO_MBED_PTD0, IO_REG_OUT_DIR, fio[3]);//モジュールの3番端子にCS:OUT

#ifdef BOOST_MODE
    mcugear->makeCircuit();//これは再構築をショートカットするためにベースボードに配線情報を保存する関数です。
//速度を上げたいときに使えますが、自動的に行われるのでモジュールの積層方法によってタイミングがずれます。
#endif
}

mbed LPC1768 で AD 12bit 8chモジュールを使う

mbedでAD 12bit 8chモジュールを使う場合の説明です。
取得したアナログデータはUSBを通してPCで表示できます。TeraTermなどで確認してみてください。
MCU Gearの各プログラムをダウンロードしてmain.cppに以下のように記述すれば動きます。



#include "mbed.h"


#include "MCUGearBase.h"

#include "MCUGear.h"
#include "common.h"//このファイルの中にある#define LPC1768_mbedを有効、//#define FS_KL25Zを無効にする

//Initialize modules-----------------------------------------------------------------------

MCUGear AD8ch12M(p28, p27, N_SDA_SDA_SDA,4);    //AD(MCP3208) 12bit 8ch Module
//p28,p27はI2C通信バスです。I2Cでデジタルスイッチ群を操作し配線を再構築しています 
//N_SCL_SCL_VSSはモジュール基板裏面に設定したアドレスです
//SPI通信をするので4ピン再構築します
//ここでは任意の名前「AD8ch12M」という名前で登録しています
//-----------------------------------------------------------------------------------------

//Sample setting-----------------------------------------------------------------------

SPI spi(p5, p6, p7); // mosi, miso, sclk
DigitalOut cs(p8); //for SPI communications
Serial pc(USBTX, USBRX); // tx, rx
//-------------------------------------------------------------------------------------

//sample functions------------------------------------------------------------

void IOSimpleSPI(MCUGear *mcugear);             //IO setting for Simple SPI module
MCUGear AD8ch12M(PTE0, PTE1, N_SDA_SDA_SDA,4);    //I2C端子と、モジュール基板の裏にアドレスを設定、4つの信号端子を使う
//----------------------------------------------------------------------------

//***************************************************************************************

int main() {
    
    initBase(); //initialize Baseboard//ベースボードの初期化

   //Set IO --------------------------------------------------------------

    IOSimpleSPI(&AD8ch12M);
   //IOの配線情報を保存しmbedのどの端子をモジュールのどの端子に当てはめるかを決めます
   //--------------------------

    int data2[8];

    while(1) {
       //12bit AD Mobdule-------------------------------------------------

       cs = 1; //reset CS pin
       AD8ch12M.connectModule();   //connect---//配線情報を基にモジュールとマイコン端子との配線を再構築します
//一度構築すると普通のデジタル回路と同じように扱えます
       data2[0] = read12bit8chAD(&AD8ch12M, 0);    //0ch//AD 0chの値を取得します
       data2[1] = read12bit8chAD(&AD8ch12M, 1);    //1ch
       data2[2] = read12bit8chAD(&AD8ch12M, 2);    //2ch
       data2[3] = read12bit8chAD(&AD8ch12M, 3);    //3ch
       data2[4] = read12bit8chAD(&AD8ch12M, 4);    //4ch
       data2[5] = read12bit8chAD(&AD8ch12M, 5);    //5ch
       data2[6] = read12bit8chAD(&AD8ch12M, 6);    //6ch
       data2[7] = read12bit8chAD(&AD8ch12M, 7);    //7ch
       AD8ch12M.disconnectModule();   //disconnect---//マイコンとモジュールの配線を切断します

       pc.printf("AD 0ch = %d  1ch = %d\n",whoami[0],whoami[1]);//PCに送ります

       wait(0.5);

    }    

}
//***************************************************************************************


//モジュールに搭載されているMCP3202のデバイスを動かすための関数です


//----------------------------------------------------------------------------------
//Simple write for 12bit 8ch AD module
//----------------------------------------------------------------------------------
int read12bit8chAD(MCUGear *mcugear, char ch){

    char sendData;
    int whoami[3];
    
    if(ch < 8){
        sendData = 0x18+ch; //0001 1000
    }else{
        return -1;
    }
    
    //12bit AD Mobdule----------------
    spi.frequency(1000000); //1MHz
    spi.format(14,0);    //Change SPI format mbed only
    cs = 0;
    spi.write(sendData);
    whoami[0] = spi.write(0x0000)-0x2000;   //get data from AD device
    cs = 1;
    return whoami[0];
}

//マイコンとモジュールの配線情報を保存します。
//----------------------------------------------------------------------------------
//IO setting for Multifunction module
//----------------------------------------------------------------------------------
void IOSimpleSPI(MCUGear *mcugear){
    uint8_t fio[12];
    mcugear->detect_module(fio);//指定したモジュールがベースボードのどこに接続されているかを探してきます
    
    //miso(p6),mosi(p5),sck(p7),cs(p8)
    mcugear->savePinSetting(0, IO_MBED_P6, IO_REG_IN_DIR, fio[0]);//モジュールの0番端子にMISO:IN
    mcugear->savePinSetting(1, IO_MBED_P5, IO_REG_OUT_DIR, fio[1]);//モジュールの1番端子にMOSI:OUT
    mcugear->savePinSetting(2, IO_MBED_P7, IO_REG_OUT_DIR, fio[2]);//モジュールの2番端子にSCK:OUT
    mcugear->savePinSetting(3, IO_MBED_P8, IO_REG_OUT_DIR, fio[3]);//モジュールの3番端子にCS:OUT

#ifdef BOOST_MODE

    mcugear->makeCircuit();//これは再構築をショートカットするためにベースボードに配線情報を保存する関数です。
#endif
}

//end of sample functions----------------------------------------------------


LPC1114FN28 で AD 12bit 8chモジュールを使う

AD 12bit 2ch モジュールの使い方について詳細な説明です。
サンプルプログラムでは以下のように設定し、シリアル通信で結果をPCに表示できます。

main.cの説明です。
1、実際に関数の使い方
2、マイコンのピン設定(入出力設定など)
3、マイコンからモジュールに接続する配線情報の関数
4、AD変換のためのデバイスを動かす関数


//define your module and function
//1=ON, 0=OFF
#define SimpleUART 1 //今回はシリアル通信を使うので1にしてON
#define AD12bit2 0 //今回はAD2chを使うので1にしてON
#define AD12bit8 1
#define DA12bit  0
#define LCDM 0
#define SigHold 0
#define Universal2 0

#define MultiFunctionModule 0

#define PWM_MODE 0
#define AD_MODE 0
#define I2C_MODE 0

#ifdef __USE_CMSIS

#include "LPC11xx.h"
#endif

#include <cr_section_macros.h>

#include <NXP/crp.h>

// Variable to store CRP value in. Will be placed automatically

// by the linker when "Enable Code Read Protect" selected.
// See crp.h header for more information
__CRP const unsigned int CRP_WORD = CRP_NO_CRP ;

// TODO: insert other include files here

#include "MCUGear.h"
#include "type.h"
#include "i2c.h"
#include "spi.h"
#include "common.h"

#include "SimpleUart.h"

//save SPI data//SPIデータを保存する
uint32_t src_addr[SPI_BUFSIZE];
uint32_t dest_addr[SPI_BUFSIZE];

void ModuleIOConfig(void);
void IOSimpleSPI(MCUGear *mcugear, char address);

int read12bit8chAD(MCUGear *mcugear, char ch);//使う関数を定義しておく

//main関数 初期化してADデータをそのままシリアル通信を介してPCに送っています。
//シリアル通信のボーレートは115200としました。
int main(void) {

// TODO: insert code here

        //色々初期化します
SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock/10000);//Timer (1/10000) Sec = 0.1 msec

//I2C setting

init_I2C();//I2Cの初期化

//IO setting

ModuleIOConfig();//マイコンのIO設定が書いてあります。

//SPI setting

SPI_IOConfig();//port 0 PIO0_8 _9 _6 _2
SPI_Init();

double dData;
//UART setting
initUART(115200);
UART_Puts("TEST\r\n");


//Baseboard setting

init_BASEboard();//ベースボードの初期化

 uint32_t data2[8];
 //12bit 8ch AD module setting
 MCUGear AD12bit8ch;//モジュールの任意名前を定義します。ここでAD12bit8chとしました。
 IOSimpleSPI(&AD12bit8ch, N_SDA_SDA_SDA);//定義したモジュールのアドレスを設定します。


while(1) {


connectModule(&AD12bit8ch);//モジュールとマイコン端子の配線を自動的に行います
                //上の一行で再構築が終わっているので、あとは普通のデジタル回路として扱えます data2[0] = read12bit8chAD(&AD12bit8ch, 0);//0chの電圧を12bitのデータとして取得します
data2[1] = read12bit8chAD(&AD12bit8ch, 1);//1ch
data2[2] = read12bit8chAD(&AD12bit8ch, 2);//2ch
data2[3] = read12bit8chAD(&AD12bit8ch, 3);//3ch
data2[4] = read12bit8chAD(&AD12bit8ch, 4);//4ch
data2[5] = read12bit8chAD(&AD12bit8ch, 5);//5ch
data2[6] = read12bit8chAD(&AD12bit8ch, 6);//6ch
data2[7] = read12bit8chAD(&AD12bit8ch, 7);//7ch
disconnectModule(&AD12bit8ch);//モジュールとマイコン端子の配線を切断します

                //シリアル通信でPCにデータを送ります

UART_Puts(" Ch0: ");
UART_PutData(data2[0],0);

UART_Puts(" Ch1: ");
UART_PutData(data2[1],0);

UART_Puts(" Ch2: ");
UART_PutData(data2[2],0);

UART_Puts(" Ch3: ");
UART_PutData(data2[3],0);

UART_Puts(" Ch4: ");
UART_PutData(data2[4],0);

UART_Puts(" Ch5: ");
UART_PutData(data2[5],0);

UART_Puts(" Ch6: ");
UART_PutData(data2[6],0);

UART_Puts(" Ch7: ");
UART_PutData(data2[7],0);

UART_Puts("\r\n");
}

return 0 ;


}




マイコンのピン設定

I2C、SPI、UART、IN、OUTの設定です。これは普通にマイコン使うときには必要な処理です。

//----------------------------------------------------------------------------------

//IO config for module
//This function is IO setting for MCUgear sample code.
//Modify this function to fit your program
//----------------------------------------------------------------------------------
void ModuleIOConfig(void){
//Reserved IOs for SPI, UART, I2C and Debugger.
//Pin1  PIO0_8 MISO
//Pin2  PIO0_9 MOSI
//Pin6  PIO0_6 SCK0
//Pin25 PIO0_2 SSL0
//Pin15 PIO1_6 RXD
//Pin16 PIO1_7 TXD
//Pin5  PIO0_5 SDA
//Pin27 PIO0_4 SCL

//This is for LCD and simple digital out.

//Pin4  R_PIO0_11
//Pin9  R_PIO1_0
//Pin10 R_PIO1_1
//Pin11 R_PIO1_2
//Pin26 PIO0_3
//Pin28 PIO0_7

LPC_IOCON->PIO0_3 = 0xd0;

LPC_IOCON->PIO0_7 = 0xd0;
LPC_IOCON->R_PIO0_11 = 0xd1;
LPC_IOCON->R_PIO1_0 = 0xd1;
LPC_IOCON->R_PIO1_1 = 0xd1;
LPC_IOCON->R_PIO1_2 = 0xd1;

LPC_GPIO0->DIR  |= (1<<3);

LPC_GPIO0->DIR  |= (1<<7);
LPC_GPIO0->DIR  |= (1<<11);
LPC_GPIO1->DIR  |= (1<<0);
LPC_GPIO1->DIR  |= (1<<1);
LPC_GPIO1->DIR  |= (1<<2);


//You can change setting of IOs. Input or output

//Pin13 PIO1_4 output
//Pin14 PIO1_5 output
//Pin17 PIO1_8 input
//Pin18 PIO1_9 input

//sample code : set out put for signal hold and universal module

LPC_IOCON->PIO1_4 = 0xd0;
LPC_IOCON->PIO1_5 = 0xd0;
LPC_IOCON->PIO1_8 = 0xd0;
LPC_IOCON->PIO1_9 = 0xd0;

LPC_GPIO1->DIR  |= (1<<4);

LPC_GPIO1->DIR  |= (1<<5);
LPC_GPIO1->DIR  &= ~(1<<8); //input
LPC_GPIO1->DIR  &= ~(1<<9); //input
}



マイコンからモジュールに接続する配線情報の関数

どのマイコンの端子をモジュールの何番ピンに当てはめるかという情報を保存します

//----------------------------------------------------------------------------------

//Simple SPI
//----------------------------------------------------------------------------------
void IOSimpleSPI(MCUGear *mcugear, char address){

mcugear->address = address;

mcugear->PinNum = 4;//使用する端子の数がSPIの4ピン
//Pin1 PIO0_8 MISO
//Pin2 PIO0_9 MOSI
//Pin6 PIO0_6 SCK0
//Pin25 PIO0_2 SSL0
detectModule(mcugear);
    savePinSetting(mcugear, 0, IO_LPC1114FN_1, IO_REG_IN_DIR);//モジュールの0番端子にMISOIN
    savePinSetting(mcugear, 1, IO_LPC1114FN_2, IO_REG_OUT_DIR);//モジュールの1番端子にMOSIOUT
    savePinSetting(mcugear, 2, IO_LPC1114FN_6, IO_REG_OUT_DIR);//モジュールの2番端子にSCK:OUT
    savePinSetting(mcugear, 3, IO_LPC1114FN_25, IO_REG_OUT_DIR);//モジュールの3番端子にCS:OUT
    mcugear->Bank = 0;//ここは追々説明します。今回はこのまま

}




AD変換のためのデバイスMCP3208を動かす関数


//----------------------------------------------------------------------------------
//Simple write for 12bit 8ch AD module
//----------------------------------------------------------------------------------
int read12bit8chAD(MCUGear *mcugear, char ch){

    char sendData;
    int whoami[3];

    if(ch < 8){
        sendData = 0x18+ch; //0001 1000
        sendData = (sendData << 2);

    }else{
        return -1;
    }

    //12bit AD Mobdule----------------
LPC_GPIO0->DATA |= (1<<2); //CS pin High
LPC_GPIO0->DATA &= ~(1<<2); //CS pin Low
    src_addr[0] = sendData;
SPI_Send( (uint32_t *)src_addr, SPI_BUFSIZE); //port0

SPI_Receive( (uint32_t *)dest_addr, 1 );
whoami[0] = dest_addr[0]<<8;

SPI_Receive( (uint32_t *)dest_addr, 1 );
whoami[1] = whoami[0] + dest_addr[0];
whoami[1] = whoami[1] >> 4;

LPC_GPIO0->DATA |= (1<<2); //CS pin High

    return whoami[1];
}