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.

LAUNCHXL-F28379D: MAX1978 Not Responding to SPI-DAC Transmissions from C2000 MCU

Part Number: LAUNCHXL-F28379D


Hello TI Community,

I'm experiencing an issue with the MAX1978 on a development board, where it doesn't respond to SPI transmissions from a C2000 MCU. I'm using a MAX5144 DAC for the SPI-DAC conversion. I've sent a fixed test value calculated as uint16_t fixedData = (uint16_t)(0.3 * 16383), considering the 14-bit resolution of MAX5144.

//#############################################################################
//
// FILE:   spi_ex3_external_loopback_fifo_interrupt.c
//
// TITLE:  SPI Digital Loopback with FIFO Interrupts
//
//! \addtogroup driver_example_list
//! <h1>SPI Digital External Loopback with FIFO Interrupts</h1>
//!
//! This program uses the external loopback between two SPI modules. Both
//! the SPI FIFOs and their interrupts are used. SPIA is configured as a slave
//! and receives data from SPI B which is configured as a master.
//!
//! A stream of data is sent and then compared to the received stream.
//! The sent data looks like this: \n
//!  0000 0001 \n
//!  0001 0002 \n
//!  0002 0003 \n
//!  .... \n
//!  FFFE FFFF \n
//!  FFFF 0000 \n
//!  etc.. \n
//! This pattern is repeated forever.
//!
//! \b External \b Connections \n
//!  -GPIO25 and GPIO17 - SPISOMI
//!  -GPIO24 and GPIO16 - SPISIMO
//!  -GPIO27 and GPIO19 - SPISTE
//!  -GPIO26 and GPIO18 - SPICLK
//!
//! \b Watch \b Variables \n
//!  - \b sData - Data to send
//!  - \b rData - Received data
//!  - \b rDataPoint - Used to keep track of the last position in the receive
//!    stream for error checking
//!
//
//#############################################################################
//
// $Release Date: $
// $Copyright:
// Copyright (C) 2013-2023 Texas Instruments Incorporated - http://www.ti.com/
//
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions 
// are met:
// 
//   Redistributions of source code must retain the above copyright 
//   notice, this list of conditions and the following disclaimer.
// 
//   Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the 
//   documentation and/or other materials provided with the   
//   distribution.
// 
//   Neither the name of Texas Instruments Incorporated nor the names of
//   its contributors may be used to endorse or promote products derived
//   from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// $
//#############################################################################

//
// Included Files
//
#include "driverlib.h"
#include "device.h"

//
// Globals
//
volatile uint16_t sData[2];         // Send data buffer
volatile uint16_t rData[2];         // Receive data buffer
volatile uint16_t rDataPoint = 0;   // To keep track of where we are in the
                                    // data stream to check received data

//
// Function Prototypes
//
void initSPIBMaster(void);
void initSPIASlave(void);
void configGPIOs(void);
__interrupt void spibTxFIFOISR(void);
__interrupt void spiaRxFIFOISR(void);

//
// Main
//
void main(void)
{
    uint16_t i;

    //
    // Initialize device clock and peripherals
    //
    Device_init();

    //
    // Disable pin locks and enable internal pullups.
    //
    Device_initGPIO();

    //
    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    //
    Interrupt_initModule();

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();

    //
    // Interrupts that are used in this example are re-mapped to ISR functions
    // found within this file.
    //
    Interrupt_register(INT_SPIB_TX, &spibTxFIFOISR);
    Interrupt_register(INT_SPIA_RX, &spiaRxFIFOISR);

    //
    // Configure GPIOs for external loopback.
    //
    configGPIOs();

    //
    // Set up SPI B as master, initializing it for FIFO mode
    //
    initSPIBMaster();

    //
    // Set up SPI A as slave, initializing it for FIFO mode
    //
    initSPIASlave();

    //
    // Initialize the data buffers
    //
    for(i = 0; i < 2; i++)
    {
        sData[i] = i;
        rData[i]= 0;
    }

    //
    // Enable interrupts required for this example
    //
    Interrupt_enable(INT_SPIA_RX);
    Interrupt_enable(INT_SPIB_TX);

    //
    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    //
    EINT;
    ERTM;

    //
    // Loop forever. Suspend or place breakpoints to observe the buffers.
    //
    while(1)
    {
        ;
    }
}

//
// Function to configure SPI B as master with FIFO enabled.
//
void initSPIBMaster(void)
{
    //
    // Must put SPI into reset before configuring it
    //
    SPI_disableModule(SPIB_BASE);

    //
    // SPI configuration. Use a 500kHz SPICLK and 16-bit word size.
    //
    SPI_setConfig(SPIB_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA0,
                  SPI_MODE_MASTER, 500000, 16);
    SPI_disableLoopback(SPIB_BASE);
    SPI_setEmulationMode(SPIB_BASE, SPI_EMULATION_FREE_RUN);

    //
    // FIFO and interrupt configuration
    //
    SPI_enableFIFO(SPIB_BASE);
    SPI_clearInterruptStatus(SPIB_BASE, SPI_INT_TXFF);
    SPI_setFIFOInterruptLevel(SPIB_BASE, SPI_FIFO_TX2, SPI_FIFO_RX2);
    SPI_enableInterrupt(SPIB_BASE, SPI_INT_TXFF);

    //
    // Configuration complete. Enable the module.
    //
    SPI_enableModule(SPIB_BASE);
}

//
// Function to configure SPI A as slave with FIFO enabled.
//
void initSPIASlave(void)
{
    //
    // Must put SPI into reset before configuring it
    //
    SPI_disableModule(SPIA_BASE);

    //
    // SPI configuration. Use a 500kHz SPICLK and 16-bit word size.
    //
    SPI_setConfig(SPIA_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA0,
                  SPI_MODE_SLAVE, 500000, 16);
    SPI_disableLoopback(SPIA_BASE);
    SPI_setEmulationMode(SPIA_BASE, SPI_EMULATION_FREE_RUN);

    //
    // FIFO and interrupt configuration
    //
    SPI_enableFIFO(SPIA_BASE);
    SPI_clearInterruptStatus(SPIA_BASE, SPI_INT_RXFF);
    SPI_setFIFOInterruptLevel(SPIA_BASE, SPI_FIFO_TX2, SPI_FIFO_RX2);
    SPI_enableInterrupt(SPIA_BASE, SPI_INT_RXFF);

    //
    // Configuration complete. Enable the module.
    //
    SPI_enableModule(SPIA_BASE);
}

//
// Configure GPIOs for external loopback.
//
void configGPIOs(void)
{
    //
    // This test is designed for an external loopback between SPIA
    // and SPIB.
    // External Connections:
    // -GPIO25 and GPIO17 - SPISOMI
    // -GPIO24 and GPIO16 - SPISIMO
    // -GPIO27 and GPIO19 - SPISTE
    // -GPIO26 and GPIO18 - SPICLK
    //

    //
    // GPIO17 is the SPISOMIA.
    //
    GPIO_setMasterCore(17, GPIO_CORE_CPU1);
    GPIO_setPinConfig(GPIO_17_SPISOMIA);
    GPIO_setPadConfig(17, GPIO_PIN_TYPE_PULLUP);
    GPIO_setQualificationMode(17, GPIO_QUAL_ASYNC);

    //
    // GPIO16 is the SPISIMOA clock pin.
    //
    GPIO_setMasterCore(16, GPIO_CORE_CPU1);
    GPIO_setPinConfig(GPIO_16_SPISIMOA);
    GPIO_setPadConfig(16, GPIO_PIN_TYPE_PULLUP);
    GPIO_setQualificationMode(16, GPIO_QUAL_ASYNC);

    //
    // GPIO19 is the SPISTEA.
    //
    GPIO_setMasterCore(19, GPIO_CORE_CPU1);
    GPIO_setPinConfig(GPIO_19_SPISTEA);
    GPIO_setPadConfig(19, GPIO_PIN_TYPE_PULLUP);
    GPIO_setQualificationMode(19, GPIO_QUAL_ASYNC);

    //
    // GPIO18 is the SPICLKA.
    //
    GPIO_setMasterCore(18, GPIO_CORE_CPU1);
    GPIO_setPinConfig(GPIO_18_SPICLKA);
    GPIO_setPadConfig(18, GPIO_PIN_TYPE_PULLUP);
    GPIO_setQualificationMode(18, GPIO_QUAL_ASYNC);

    //
    // GPIO25 is the SPISOMIB.
    //
    GPIO_setMasterCore(25, GPIO_CORE_CPU1);
    GPIO_setPinConfig(GPIO_25_SPISOMIB);
    GPIO_setPadConfig(25, GPIO_PIN_TYPE_PULLUP);
    GPIO_setQualificationMode(25, GPIO_QUAL_ASYNC);

    //
    // GPIO24 is the SPISIMOB clock pin.
    //
    GPIO_setMasterCore(24, GPIO_CORE_CPU1);
    GPIO_setPinConfig(GPIO_24_SPISIMOB);
    GPIO_setPadConfig(24, GPIO_PIN_TYPE_PULLUP);
    GPIO_setQualificationMode(24, GPIO_QUAL_ASYNC);

    //
    // GPIO27 is the SPISTEB.
    //
    GPIO_setMasterCore(27, GPIO_CORE_CPU1);
    GPIO_setPinConfig(GPIO_27_SPISTEB);
    GPIO_setPadConfig(27, GPIO_PIN_TYPE_PULLUP);
    GPIO_setQualificationMode(27, GPIO_QUAL_ASYNC);

    //
    // GPIO26 is the SPICLKB.
    //
    GPIO_setMasterCore(26, GPIO_CORE_CPU1);
    GPIO_setPinConfig(GPIO_26_SPICLKB);
    GPIO_setPadConfig(26, GPIO_PIN_TYPE_PULLUP);
    GPIO_setQualificationMode(26, GPIO_QUAL_ASYNC);
}

//
// SPI A Transmit FIFO ISR
//
/*__interrupt void spibTxFIFOISR(void)
{
    uint16_t i;

    //
    // Send data
    //
    for(i = 0; i < 2; i++)
    {
       SPI_writeDataNonBlocking(SPIB_BASE, sData[i]);
    }

    //
    // Increment data for next cycle
    //
    for(i = 0; i < 2; i++)
    {
       sData[i] = sData[i] + 1;
    }

    //
    // Clear interrupt flag and issue ACK
    //
    SPI_clearInterruptStatus(SPIB_BASE, SPI_INT_TXFF);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP6);
}*/

__interrupt void spibTxFIFOISR(void)
{
    uint16_t i;

    // 计算DAC的固定值,例如0.3的比例
    uint16_t fixedData = (uint16_t)(0.3 * 16383); // 16383 = 2^14 - 1
    uint8_t highByte, lowByte;

    // 从16位数据中提取两个8位字节
    highByte = (fixedData >> 8) & 0xFF; // 高8位
    lowByte = fixedData & 0xFF;        // 低8位

    // 发送数据
    for(i = 0; i < 2; i++)
    {
        // 发送高8位
        SPI_writeDataNonBlocking(SPIB_BASE, highByte);

        // 发送低8位
        SPI_writeDataNonBlocking(SPIB_BASE, lowByte);
    }

    // Increment data for next cycle - 但在这里我们不修改数据,因为我们发送固定的值
    for(i = 0; i < 2; i++)
    {
       // 在这里不需要修改sData,因为我们总是发送相同的固定值
    }

    // 清除中断标志并确认
    SPI_clearInterruptStatus(SPIB_BASE, SPI_INT_TXFF);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP6);
}


//
// SPI B Receive FIFO ISR
//
 __interrupt void spiaRxFIFOISR(void)
{
    uint16_t i;

    //
    // Read data
    //
    for(i = 0; i < 2; i++)
    {
        rData[i] = SPI_readDataNonBlocking(SPIA_BASE);
    }

    //
    // Check received data
    //
    for(i = 0; i < 2; i++)
    {
        if(rData[i] != (rDataPoint + i))
        {
            // Something went wrong. rData doesn't contain expected data.
            Example_Fail = 1;
            ESTOP0;
        }
    }

    rDataPoint++;

    //
    // Clear interrupt flag and issue ACK
    //
    SPI_clearInterruptStatus(SPIA_BASE, SPI_INT_RXFF);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP6);

    Example_PassCount++;
}

//
// End of File
//
MAX5141-MAX5144.pdf8422.max1978evkit.pdf those datasheet for MAX1978 and MAX5144

The SPI output appears correct, but the MAX1978 doesn't respond as expected, particularly in terms of TEC temperature control. I anticipated the TEC would heat up corresponding to the 0.3 DAC value. Could anyone offer insights or troubleshooting suggestions for this issue?

Thanks in advance!

Nero

  • I updated the code to comply to the MAX5144 receiving format, but the output signal is now odd; can someone explain why?





    The first one looks fine but why does the second one appear


    Now there is a weird warming effect, a regular warming followed by a sudden cooldown.

  • Hi Nero,

    A couple of observations from your code:

    1. In the init functions, both SPI instances are configured to transmit 16-bit words. For your use-case, you would need to modify the dataWidth parameter in SPI_setConfig() to 8.

    2. As discussed in the earlier thread, transmitted data will have to be passed in a 16-bit format, with the required bits left justified. So, in spibTxFIFOISR(), highByte and lowByte will need to match this format. Also, the for loop will transmit the bits from fixedData twice per ISR.

    Updating these should give you the right output from the SPI.

    Regarding the inconsistency in the MAX1978 response, I suggest consulting their reference manuals. There may be a difference in conventions for formatting incoming data, so this will need to be handled on the receiving board.

    Thanks,

    Arnav

  • I'm facing an issue where the CS line in my SPI setup remains low instead of going high after the DAC data transfer is complete. The timing diagram shows that CS doesn't return high after the final data bit is clocked out. All connections are verified, and the SPI configuration has been double-checked. Any advice on what might be causing the CS line to stay low would be helpful.

  •  I did this, after change it no more signal now lol

  • CS still not work. real need help.

  • Hi Nero,

    A certain delay period is expected between the end of one transmission to the start of another for the CS to return to inactive high state. You can refer to this section of the F28379D Datasheet (8.12.5.1.1.2) for exact details: 

    Since the TX interrupts are coming in continuously, the gap between two interrupts may not be enough for the CS line to return. You could try stopping the interrupts after N transmissions are completed, or adding some sufficient delay between transmissions, and observe the CS pin.

    Thanks, 

    Arnav 

  • I've encountered some progress with the SPI communication for the DAC voltage control. The target was to stabilize the voltage at 0.3V to match the corresponding temperature setting. However, I'm observing that the voltage is persistently at 0.4V.

    I suspected a possible issue with the thermistor's contact with the TEC, so I attempted to adjust the DAC setting by lowering the target voltage in the code with uint16_t fixedData = (uint16_t)((0.2 / 1.5) * 16383);, which is the calculated 14-bit DAC value for 0.2V. Despite this, the output remains at 0.4V and does not decrease as expected.

    Is it possible that there's a communication issue that's preventing the DAC from adjusting the voltage correctly? Or is it more likely that the issue lies in the physical assembly or contact of the thermistor with the TEC?

    Your insights would be greatly appreciated.

    Nero



  • I am currently encountering an issue with SPI communication where an unexpected byte is appended to the end of my intended transmission. The desired behavior is to transmit a single pair of 0x22 bytes. However, as evidenced by the logic analyzer trace, a 0x20 byte is consistently transmitted following the correct pair, which I refer to colloquially as a "little tail".

    This spurious byte is not part of the intended data frame and its persistent occurrence suggests it might be an artifact of the current SPI buffer handling or ISR configuration. My efforts to amend the transmission code and eliminate this extraneous byte have not yet yielded the desired clean signal.

    I am seeking assistance or suggestions to resolve this anomaly. Any insights into potential causes or corrective actions would be greatly appreciated.

  • The core of the issue is that after changing a value in the code from 0.2 to 0.4, intended to double the output to the DAC, the SPI output is not showing the expected results. Instead of doubling, the output is showing as 0x88 on the MOSI line, which is not the calculated value (0x4444 after left-justification), and there are occasional unexpected variations like 0x80 or 0x8C. This suggests a problem with the data preparation or SPI transmission process.

    __interrupt void spibTxFIFOISR(void)
    {
    // 计算DAC的固定值,例如0.3的比例
    uint16_t fixedData = (uint16_t)((0.4 / 1.5) * 16383); // 14-bit DAC value
    fixedData = fixedData << 2; // Left-justify the data to make it 16 bits

    // 将固定值放入sData数组中,准备发送
    sData[0] = fixedData;

    // 检查发送FIFO是否为空并准备好发送新数据
    while((SPI_getTxFIFOStatus(SPIB_BASE) & SPI_FIFO_TXEMPTY) != SPI_FIFO_TXEMPTY);

    // 发送数据
    SPI_writeDataNonBlocking(SPIB_BASE, sData[0]);
    DEVICE_DELAY_US(100);

    // 清除发送FIFO中断标志
    SPI_clearInterruptStatus(SPIB_BASE, SPI_INT_TXFF);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP6);
    // DEVICE_DELAY_US(100);
    }

  • I'm fine-tuning the SPI timings in our project based on the TI datasheet's Master Mode Switching Characteristics. I need to align the MOSI signal ahead of the SCLK's rising edge, but the microsecond-level granularity of our system poses a challenge for implementing the nanosecond-precise timings detailed in the specs.

    Could you advise on strategies to shift MOSI timing within our microcontroller's constraints, or is additional hardware required for such precision?


  • Hi Nero,

    You can adjust the protocol parameter in SPI_setConfig() for this purpose. This allows you to configure the Polarity (whether to output data on rising or falling edge), and the Phase (whether to add a half-cycle delay).

    Thanks,

    Arnav