This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSPM0G3507: MSPM0G3507 + DAC80508MC SPI sinewave generator

Part Number: MSPM0G3507
Other Parts Discussed in Thread: DAC80508

 

Hello,

 

I am using a SPI polling method for eight channel data transfer from a LP-MSPM0G3507 EVM and a DAC80508MC Chip. 

 

My goal is to generate sine waves in the 20-27khz range. Currently the output looks more like an AM wave and after the 3 step increase the value drops below zero before reaching the next step increase.

 

I think the issue is related to one of the following

  • Manual CS pin is deasserting during the data byte transfer and interrupt output. 
  • MCLK doesn’t have the bandwidth to output these frequencies on all 8 channels at once
  • Issue with the delay time.

 

Below I have provided the 3 main files:

Main file:

#include "ti_msp_dl_config.h"

#include <math.h>

#include <stdint.h>

#include "dacINIT.h"

 

#define SINE_N        256u

#define SINE_AMPL     1.0f

#define MID_CODE      32768u

#define SAMPLE_DELAY  160u

#define NUM_CHANNELS  8

#define ACTUAL_FS  45455.0f

 

 

volatile uint32_t dbg_loopCount = 0;

volatile uint16_t dbg_lastVal0  = 0;

volatile uint8_t  dbg_idx0      = 0;

 

/* Target frequencies */

static const float freqs[NUM_CHANNELS] = {

    20000.0f, 21000.0f, 22000.0f, 23000.0f,

    24000.0f, 25000.0f, 26000.0f, 27000.0f

};

 

/* 32-bit DDS */

typedef struct { uint32_t phase, step; } DDS_t;

static DDS_t dds[NUM_CHANNELS];

 

static void init_DDS(void)

{

    for (int i = 0; i < NUM_CHANNELS; i++)

    {

        dds[i].phase = 0;

        dds[i].step  = (uint32_t)((freqs[i] * 4294967296.0f) / ACTUAL_FS);

    }

}

 

static uint16_t sine_lut[SINE_N];

 

static void build_sine(void)

{

    for (uint32_t i = 0; i < SINE_N; i++)

    {

        float s = sinf(2.0f * 3.1415926f * (float)i / (float)SINE_N);

        float x = (float)MID_CODE + s * (SINE_AMPL * 32767.0f);

        if (x < 0.0f)     x = 0.0f;

        if (x > 65535.0f) x = 65535.0f;

        sine_lut[i] = (uint16_t)(x + 0.5f);

    }

}

 

int main(void)

{

    SYSCFG_DL_init();

 

    DAC_CLR_HIGH();

    delay_cycles(32000u);

    delay_cycles(320000u);

 

    DAC80508_soft_reset();

    delay_cycles(320000u);

 

    DAC_CLR_HIGH();

    delay_cycles(32000u);

 

    DAC80508_write_reg(DAC80508_REG_CONFIG, 0x0000u);

    DAC80508_write_reg(DAC80508_REG_GAIN,   0x01FFu);

    DAC80508_write_reg(DAC80508_REG_SYNC,   0x0000u);

 

    for (uint8_t ch = 0; ch < NUM_CHANNELS; ch++)

        dacSetChannel(ch, MID_CODE);

 

    build_sine();

    init_DDS();

 

    ledON();

 

    while (1)

    {

        dbg_loopCount++;

 

        for (uint8_t ch = 0; ch < NUM_CHANNELS; ch++)

        {

            dds[ch].phase += dds[ch].step;

            uint8_t  idx = (uint8_t)(dds[ch].phase >> 24);

            uint16_t val = sine_lut[idx];

            dacSetChannel(ch, val);

            if (ch == 0) { dbg_lastVal0 = val; dbg_idx0 = idx; }

        }

 

        if ((dbg_loopCount % 500) == 0)

            DL_GPIO_togglePins(gpioLED_PORT, gpioLED_LED1_PIN);

 

        delay_cycles(SAMPLE_DELAY);

    }

}

SysCFG:

 */

const Board         = scripting.addModule("/ti/driverlib/Board");

const GPIO          = scripting.addModule("/ti/driverlib/GPIO", {}, false);

const GPIO1         = GPIO.addInstance();

const GPIO2         = GPIO.addInstance();

const SPI           = scripting.addModule("/ti/driverlib/SPI", {}, false);

const SPI1          = SPI.addInstance();

const SYSCTL        = scripting.addModule("/ti/driverlib/SYSCTL");

const ProjectConfig = scripting.addModule("/ti/project_config/ProjectConfig");

 

/**

 * Write custom configuration values to the imported modules.

 */

Board.genPeriphPinFile       = true;

Board.genResourceCSV         = true;

Board.genResourceCSVAdvanced = "detailed";

Board.genFileMod.$name       = "ti_driverlib_BoardPins0";

Board.genFileCSV.$name       = "ti_driverlib_ResourcesCSV0";

 

GPIO1.$name                               = "gpioLED";

GPIO1.associatedPins[0].launchPadShortcut = "LED1En";

GPIO1.associatedPins[0].$name             = "LED1";

GPIO1.associatedPins[0].initialValue      = "SET";

GPIO1.associatedPins[0].pin.$assign       = "PA0";

 

GPIO2.port                           = "PORTB";

GPIO2.$name                          = "gpioCLR";

GPIO2.associatedPins[0].$name        = "clrPIN";

GPIO2.associatedPins[0].initialValue = "SET";

GPIO2.associatedPins[0].assignedPin  = "7";

GPIO2.associatedPins[0].pin.$assign  = "PB7";

 

SPI1.$name                              = "mySPI";

SPI1.phase                              = "1";

SPI1.targetBitRate                      = 16000000;

SPI1.peripheral.$assign                 = "SPI1";

SPI1.peripheral.sclkPin.$assign         = "PB9";

SPI1.peripheral.mosiPin.$assign         = "PB8";

SPI1.peripheral.misoPin.$assign         = "PB14";

SPI1.peripheral.cs0Pin.$assign          = "PB6";

SPI1.sclkPinConfig.$name                = "ti_driverlib_gpio_GPIOPinGeneric0";

SPI1.sclkPinConfig.direction            = scripting.forceWrite("OUTPUT");

SPI1.sclkPinConfig.onlyInternalResistor = scripting.forceWrite(false);

SPI1.sclkPinConfig.passedPeripheralType = scripting.forceWrite("Digital");

SPI1.mosiPinConfig.$name                = "ti_driverlib_gpio_GPIOPinGeneric1";

SPI1.mosiPinConfig.direction            = scripting.forceWrite("OUTPUT");

SPI1.mosiPinConfig.hideOutputInversion  = scripting.forceWrite(false);

SPI1.mosiPinConfig.onlyInternalResistor = scripting.forceWrite(false);

SPI1.mosiPinConfig.passedPeripheralType = scripting.forceWrite("Digital");

SPI1.misoPinConfig.$name                = "ti_driverlib_gpio_GPIOPinGeneric2";

SPI1.misoPinConfig.onlyInternalResistor = scripting.forceWrite(false);

SPI1.misoPinConfig.passedPeripheralType = scripting.forceWrite("Digital");

SPI1.cs0PinConfig.$name                 = "ti_driverlib_gpio_GPIOPinGeneric3";

SPI1.cs0PinConfig.direction             = scripting.forceWrite("OUTPUT");

SPI1.cs0PinConfig.hideOutputInversion   = scripting.forceWrite(false);

SPI1.cs0PinConfig.onlyInternalResistor  = scripting.forceWrite(false);

SPI1.cs0PinConfig.passedPeripheralType  = scripting.forceWrite("Digital");

 

SYSCTL.clockTreeEn = true;

 

ProjectConfig.genLibDrivers = true;

ProjectConfig.genLibGC      = true;

 

/**

 * Pinmux solution for unlocked pins/peripherals. This ensures that minor changes to the automatic solver in a future

 * version of the tool will not impact the pinmux you originally saw.  These lines can be completely deleted in order to

 * re-solve from scratch.

 */

Board.peripheral.$suggestSolution          = "DEBUGSS";

Board.peripheral.swclkPin.$suggestSolution = "PA20";

Board.peripheral.swdioPin.$suggestSolution = "PA19";

 

Header:

#ifndef DACINIT_H

#define DACINIT_H

 

#include "ti_msp_dl_config.h"

#include <stdint.h>

 

#define DAC80508_REG_NOP      0x00

#define DAC80508_REG_DEVID    0x01

#define DAC80508_REG_SYNC     0x02

#define DAC80508_REG_CONFIG   0x03

#define DAC80508_REG_GAIN     0x04

#define DAC80508_REG_TRIGGER  0x05

#define DAC80508_REG_BRDCAST  0x06

#define DAC80508_REG_STATUS   0x07

#define DAC80508_REG_DAC0     0x08

#define DAC80508_REG_DAC1     0x09

#define DAC80508_REG_DAC2     0x0A

#define DAC80508_REG_DAC3     0x0B

#define DAC80508_REG_DAC4     0x0C

#define DAC80508_REG_DAC5     0x0D

#define DAC80508_REG_DAC6     0x0E

#define DAC80508_REG_DAC7     0x0F

 

#define dacSOFTRESET_VAL  0x000Au

 

/* CLR — PB7 */

#define DAC_CLR_HIGH() DL_GPIO_setPins  (gpioCLR_PORT, gpioCLR_clrPIN_PIN)

#define DAC_CLR_LOW()  DL_GPIO_clearPins(gpioCLR_PORT, gpioCLR_clrPIN_PIN)

 

/* LED — PA0 */

#define ledON()  DL_GPIO_setPins  (gpioLED_PORT, gpioLED_LED1_PIN)

#define ledOFF() DL_GPIO_clearPins(gpioLED_PORT, gpioLED_LED1_PIN)

 

/* Watchpoints */

volatile uint32_t dbg_writeCount = 0;

volatile uint32_t dbg_spiStat0  = 0;

volatile uint32_t dbg_spiDone   = 0;

 

static inline void DAC80508_WRITE(uint8_t addr, uint16_t data)

{

    while (DL_SPI_isBusy(mySPI_INST)) {}

    dbg_spiStat0 = SPI1->STAT;

    DL_SPI_transmitData8(mySPI_INST,  addr        & 0x1Fu);

    DL_SPI_transmitData8(mySPI_INST, (data >> 8)  & 0xFFu);

    DL_SPI_transmitData8(mySPI_INST,  data        & 0xFFu);

    //while (DL_SPI_isBusy(mySPI_INST)) {}

    dbg_spiDone  = SPI1->STAT;

    dbg_writeCount++;

}

 

static inline void DAC80508_write_reg(uint8_t reg, uint16_t val)

{

    DAC80508_WRITE(reg, val);

}

 

static inline void DAC80508_soft_reset(void)

{

    DAC80508_WRITE(DAC80508_REG_TRIGGER, dacSOFTRESET_VAL);

}

 

static inline void dacSetChannel(uint8_t ch, uint16_t code)

{

    DAC80508_WRITE((uint8_t)(DAC80508_REG_DAC0 + (ch & 0x07u)), code);

}

 

#endif

 

  • The CS problem is easy to solve. make it a GPIO and control it yourself. (i.e., use 3 wire mode instead of 4 wire mode). Do you have a scope you can put on the SPI lines?

  • With a 16MHz SPI and 24-bit samples my arithmetic says that's (theoretical max) 1.5us/sample/channel or 12us/sample for a per-channel rate of 83.3ksps. At 27kHz that's about 3 samples/period, which provides almost no visual fidelity (barely recognizable). 

    If ACTUAL_FS=45.4ksps reflects your observed/measured output rate, that's only 2 samples/period, which won't be recognizable at all.

    This goal would seem to be overly ambitious.

    If you speed up SYSCLK to 80MHz (i.e. >= 64MHz) you can run the SPI at 32MHz, which would (theoretically) provide 6 samples/period.

    Keep in mind that the output rate is really the LDAC rate; you can load the data registers ahead of time as long as you trigger (LDAC) on schedule.