MSP432 ADS8341
ADS8341
16ビットの4チャンネルADC。
SPIの設定
const eUSCI_SPI_MasterConfig spiMasterConfig2 =
{
EUSCI_B_SPI_CLOCKSOURCE_SMCLK, // SMCLK Clock Source
12000000, // SMCLK = DCO = 12000000
1200000, // SPICLK = 12000000
EUSCI_B_SPI_MSB_FIRST, // MSB First
EUSCI_B_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT, //up edge
EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_LOW, // Low polarity
EUSCI_SPI_3PIN
//EUSCI_SPI_4PIN_UCxSTE_ACTIVE_LOW // 3Wire SPI Mode
};
タイミングチャートを見ると、MSP432から送りだし、ADS8341がDINの内容を読むときは、立ち上がりのエッジで、送りだすときは、立下りのタイミング・・というしろものだが、EUSCI_B_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXTでOK。
MSP432は、まずクロックだが、
SPI_transmitData(EUSCI_B2_BASE, control_bits);
と8ビット分を送信すると、8ビット分のクロックを送る。続けて送ってはくれないので、
SPI_transmitData(EUSCI_B2_BASE, 0B00000000);
といったように何かを送信してあげないとクロックを送らない。ADS8341はスタートビットが1でないと反応しないので、0B00000000を送る=クロックを送るになる。
内部クロックモードと外部クロックモードがある。Externalでつかうが、ここではまった点は、コントロールビットを送った後に、1ビットだけ無反応なビットをはさんで16ビット分のデータが送られてくる。つまり、1ビット分だけずれるから、16ビットの最後は25ビット目になり、4バイト目にさしかかる。やり方は二つあって、24ビット分で1周期としておいて、次の設定命令を送る時に、同時に前ビットのLSBの情報が出てくるので読み取る
というのと、
32ビット分をひとまとめとして、処理する方法。読み取りの繰り返し周期がはやい時は全社でよいが、周期が遅い場合は、最後のビットは、時間的に随分前の情報という事になる。
MAP_GPIO_setOutputLowOnPin(GPIO_PORT_SPI2_CS, GPIO_PIN_SPI2_CS);
MAP_SPI_transmitData(EUSCI_B2_BASE, control_bits);
Datatemp[3]=MAP_SPI_receiveData(EUSCI_B2_BASE);
MAP_SPI_transmitData(EUSCI_B2_BASE, 0B00000000);
Datatemp[0]=MAP_SPI_receiveData(EUSCI_B2_BASE);
MAP_SPI_transmitData(EUSCI_B2_BASE, 0B00000000);
Datatemp[1]=MAP_SPI_receiveData(EUSCI_B2_BASE);
MAP_SPI_transmitData(EUSCI_B2_BASE, 0B00000000);
Datatemp[2]=MAP_SPI_receiveData(EUSCI_B2_BASE);
for (i=0;i<10;i++){}
MAP_GPIO_setOutputHighOnPin(GPIO_PORT_SPI2_CS, GPIO_PIN_SPI2_CS);
上記の流れで一応読めるが問題が発生。コントロールビットを送っている間もMISOのラインからは、データが送られてくる(ゼロですが・・・)ので、格納する。
ただ、最初だけゼロを2回受け取る・・・・その後は一回で済む。ロジアナでは確認できない・・・そのため、1つ全体にずれてしまって、LSBが最初読み取るときにかえってきてしまう(前のデータ変換の最後)。その後読む、 Datatemp[0]の位置に、コントロールビットを送っている間のデータである0x00が格納されて、 Datatemp[1]の位置にMSBが格納される。このMSBは、コントロールビット終了から1ビットは無反応なので、最初は必ずゼロになる。言葉で書いてもわからんだろうからロジアナの図をみて ほしい。
このバグを解消できず、対処法として、上のように結果1つずれた形で使っている・・・一応正しい値を返してはくる。
↓はADCの入力にVrefより高い電圧をあえていれて、0xFFFFを返すようにした状態で取得したもの。
ADCの関数部分だけを以下に書いておく。
float ADCVread(uint8_t chan){
uint16_t receivedData;
static uint8_t control_bits=0;
static uint8_t Datatemp[4];
static uint8_t dummy;
const float Vdacref=1.500;
//Send data via SPI
/*contorl bit
BIT 7:Start bit must always be HIGH.
BIT 6:A2, 5:A1, 4:A0
single end SGL/DIF HIGH
A2 A1 A0 CH0 CH1 CH2 CH3
0 0 0 +IN
1 0 1 +IN
0 1 0 +IN
1 1 0 +IN
differential SGL/DIF LOW
A2 A1 A0 CH0 CH1 CH2 CH3
0 0 1 +IN -IN
1 0 1 -IN +IN
0 1 0 +IN -IN
1 1 0 -IN +IN
BIT 3 never used:0
BIT 2 SGL/DIF single end SGL/DIF HIGH, Differential Channel Control LOW
BIT 1 PD1, 0 PD0
PD1 PD2
0 0 Power-down between conversions
1 0 Selects Internal Clock Mode
0 1 never used
1 1 Selects External Clock Mode.Power down between conversions
*/
switch(chan) {
case 0: //Channel A
control_bits=0B10010111;
break;
case 1: //Channel B
control_bits=0B11010111;
break;
case 2: //Channel C
control_bits=0B10100111;
break;
case 3: //Channel D
control_bits=0B11100111;
break;
default:
control_bits=0B10010111;
}
int i;
/* Transmitting data to slave */
MAP_GPIO_setOutputLowOnPin(GPIO_PORT_SPI2_CS, GPIO_PIN_SPI2_CS);
MAP_SPI_transmitData(EUSCI_B2_BASE, control_bits);
Datatemp[3]=MAP_SPI_receiveData(EUSCI_B2_BASE);
MAP_SPI_transmitData(EUSCI_B2_BASE, 0B00000000);
Datatemp[0]=MAP_SPI_receiveData(EUSCI_B2_BASE);
MAP_SPI_transmitData(EUSCI_B2_BASE, 0B00000000);
Datatemp[1]=MAP_SPI_receiveData(EUSCI_B2_BASE);
MAP_SPI_transmitData(EUSCI_B2_BASE, 0B00000000);
Datatemp[2]=MAP_SPI_receiveData(EUSCI_B2_BASE);
for (i=0;i<10;i++){}
MAP_GPIO_setOutputHighOnPin(GPIO_PORT_SPI2_CS, GPIO_PIN_SPI2_CS);
//----1st byte----/
Datatemp[1]=Datatemp[1] << 1; //shift 1 bit to left
//2nd byte shift 7 bit to right
dummy=Datatemp[2] >>7;
// new 1st byte
Datatemp[1]=Datatemp[1] | dummy;
//----2nd byte----//
Datatemp[2]=Datatemp[2] <<1; //shift 1 bit to left
//3nd byte shift 7 bit to right
dummy=Datatemp[3] >>7;
//----new 2nd byt----
Datatemp[2]=Datatemp[2] | dummy;
receivedData=Datatemp[1] <<8 | Datatemp[2];
return Vdacref*receivedData/65536;
//sprintf (OLED_buffer, "%x %x %x %x", Datatemp[0],Datatemp[1],Datatemp[2],Datatemp[3]);
//sprintf (OLED_buffer, "%7.5f", Vdacref*receivedData/65536);
//draw6x8Str(0, 2, OLED_buffer, 1,0);
}
ここまでのMSP432で使ったUARTでPC接続以外をまとめたファイル
コメント
コメントを投稿