2016年5月22日日曜日

mbedのRTOS TimerでSPI DACのMCP4922を動かす。

Tickerクラスの割り込みではなく、RTOSのTimerでタイミングをとってMCP4922を動作させてみた。

配線図
MCP4922は3.3Vで動作させている。


main.cpp

#include "mbed.h"
#include "rtos.h"

#define SPIM_TIMER_PERIOD   (1)
#define SPIM_RATE           (8000000)   // 8MHz
#define SPIM_WAIT           /*(wait_us(1))*/

#define DCO_PACKET_HEADER   (0x55)
#define SPI_DUMMY_DATA      (0xaa)      // テスト用ダミーデータ

// ピン・アサイン
#define PIN_CHECK       PA_10
#define PIN_DCO_CS      PB_6
#define PIN_DCF_CS      PC_7
#define PIN_DAC_CS      PA_9
#define PIN_DAC_LDAC    PA_8

SPI SpiM(SPI_MOSI, SPI_MISO, SPI_SCK); 
DigitalOut DcoCs(PIN_DCO_CS);
DigitalOut DcfCs(PIN_DCF_CS);
DigitalOut DacCs(PIN_DAC_CS);
DigitalOut DacLdac(PIN_DAC_LDAC);

DigitalOut CheckPin(PIN_CHECK);

void writeToDco()
{
    DcoCs = 0;
    // DCO Header
    SpiM.write(DCO_PACKET_HEADER);
    // Wave Form
    SpiM.write(SPI_DUMMY_DATA);
    // Pulse Width
    SpiM.write(SPI_DUMMY_DATA);
    // Frequency
    SpiM.write(SPI_DUMMY_DATA);
    SpiM.write(SPI_DUMMY_DATA);
    SPIM_WAIT;
    DcoCs = 1;
}

void writeToDcf()
{
    // Filter Q
    DcfCs = 0;
    SpiM.write(0);  // address
    SpiM.write(SPI_DUMMY_DATA);
    SPIM_WAIT;
    DcfCs = 1;
    // Filter CutOff
    DcfCs = 0;
    SpiM.write(1);  // address
    SpiM.write(SPI_DUMMY_DATA);
    SPIM_WAIT;
    DcfCs = 1;
    DcfCs = 0;
    SpiM.write(3);  // address
    SpiM.write(SPI_DUMMY_DATA);
    SPIM_WAIT;
    DcfCs = 1;
}

void writeToDac()
{
    static int v = 0;
    int nv;
    
    nv = 4095 - v; // Data for Channel B
    
    DacLdac = 1;
    
    // Channel A
    DacCs = 0;
    SpiM.write((v >> 8) | 0x30);    // 0x30: DAC_A(0) | Vref Unbuffered(0) | Vout 1x(1) | !SHDN(1)
    SpiM.write(v & 0xff);
    SPIM_WAIT;
    DacCs = 1;
    
    // Channel B
    DacCs = 0;
    SpiM.write((nv >> 8) | 0xB0);    // 0xB0: DAC_B(1) | Vref Unbuffered(0) | Vout 1x(1) | !SHDN(1)
    SpiM.write(nv & 0xff);  
    SPIM_WAIT;
    DacCs = 1;
    
    DacLdac = 0;
    
    v++;
    if (v == 4095) {
        v = 0;
    }
}
    
void writeToSpi(void const *n)
{
    CheckPin = !CheckPin;
    
    // DCO
    writeToDco();
    
    // DCF
    writeToDcf();
    
    // DCO
    writeToDac();
}

int main()
{
    RtosTimer SpiM_timer(writeToSpi, osTimerPeriodic);
    
    SpiM.format(8, 0);
    SpiM.frequency(SPIM_RATE);
    SpiM_timer.start(SPIM_TIMER_PERIOD);
    
    Thread::wait(osWaitForever);
}


MCP4922はChannel Aにフルスケールのノコギリ波、channel Bは逆位相のノコギリ波を出力。

MCP4922への出力以外に同じSPIバスを使ったデバイスを想定して、ダミーデータを出力させている。(writeToDco()、wirteToDcf())

出力波形


ch1:Channnel A ch2:Channel B

SPIの信号


ch1:SPI_MOSI ch2:SPI_SCK

最初の5byteがDCO、次の6byteがDCF、最後の4byteがMCP4922

DAC


ch1:PIN_DAC_CS ch2:SPI_SCK


ch1:PIN_DAC_LDAC ch2:SPI_SCK

DCO


ch1:PIN_DCO_CS ch2:SPI_SCK

DCF


ch1:PIN_DCF_CS ch2:SPI_SCK