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.

Compiler/TM4C123GH6PM: SPI communicate TM4C123GH6PM with MCP4921

Part Number: TM4C123GH6PM

Tool/software: TI C/C++ Compiler

My object is transmitting data 5V from TM4C123GH6PM to MCP4921. My code build well but I can not get the value from pin of MCP4921. Anybody know is that my data transmit is correct or not?

Thank you so much.

My code:

#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/ssi.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"

//#define NUM_SSI_DATA 1

void SSI0_Interrupt(void);

uint32_t pui32DataTx;
uint32_t pui32DataRx;
uint32_t ui32Index;
volatile unsigned long g_ulSSI2RXTO = 0;

void
InitConsole(void)
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

GPIOPinConfigure(GPIO_PB0_U1RX);
GPIOPinConfigure(GPIO_PB1_U1TX);

SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);

GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);

UARTConfigSetExpClk(UART1_BASE, SysCtlClockGet(),115200,(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |UART_CONFIG_PAR_NONE));
UARTEnable(UART1_BASE);
}


int
main(void)
{


SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_16MHZ);

InitConsole();

UARTprintf("SSI ->\n");
UARTprintf(" Mode: SPI\n");
UARTprintf(" Data: 8-bit\n\n");

SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);

SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

GPIOPinConfigure(GPIO_PA2_SSI0CLK);
GPIOPinConfigure(GPIO_PA3_SSI0FSS);
GPIOPinConfigure(GPIO_PA4_SSI0RX);
GPIOPinConfigure(GPIO_PA5_SSI0TX);

GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 |
GPIO_PIN_2);

SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_3,
SSI_MODE_MASTER,2000000, 8);

SSIEnable(SSI0_BASE);
SSIIntEnable(SSI0_BASE,SSI_RXFF|SSI_RXTO);

while(SSIDataGetNonBlocking(SSI0_BASE, &pui32DataRx))
{
}
SSIIntClear(SSI0_BASE,SSI_RXFF|SSI_RXTO);

pui32DataTx = 0x00003005;

UARTprintf("Sent:\n ");

{UARTprintf("'%c' ", pui32DataTx);

SSIDataPut(SSI0_BASE, pui32DataTx);

}


while(SSIBusy(SSI0_BASE))
{
}

IntEnable(INT_SSI0);

while(g_ulSSI2RXTO == 0)
{
}
UARTprintf("\nReceived:\n ");

while(1)

{}

}

  • Hello Nguyen,

    You are using these lines of code for output of data, 

    pui32DataTx = 0x00003005;
    
    SSIDataPut(SSI0_BASE, pui32DataTx);

    But the device is configured as:

    SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_3,
    SSI_MODE_MASTER,2000000, 8);

    The SSIDataPut function says the following:

    //! \note The upper 32 - N bits of \e ui32Data are discarded by the hardware,
    //! where N is the data width as configured by SSIConfigSetExpClk().  For
    //! example, if the interface is configured for 8-bit data width, the upper 24
    //! bits of \e ui32Data are discarded.

    This means you are not outputting the full data provided to the function. Try using the buffer approached outlined in our spi_master.c file from the TivaWare peripheral example (I presume you used this as a base, as your code matches it quite well overall).

    Also I would recommend forgoing interrupts until you have the basic communication working. That way you have one less variable to deal with that could cause issues. The best approach here would be to start with just making sure you can send and receive via polling and then add in the interrupts after you got that working.

    Also you should make sure you have an oscilloscope or logic state analyzer to look at the SSI pins and ensure they are outputting the correct data. That is the best way to find out where issues may lay with SPI.

  • As a follow to Vendor Ralph's excellent code sleuthing (detection of a 32 bit value) being "attempted" - and the "Elimination of  Interrupts" (for now) - the following is offered:

    nguyen thi hai van said:
    My object is transmitting data 5V from TM4C123GH6PM to MCP4921.

    • With TM4C123 powered from 3V3 - any transmission of  "5V" - by the MCU - (absent a required level shifter)  proves unlikely!
    • Unstated is the supply voltage - applied to poster's "MCP4921."    This may prove of  "vital" importance - as illustrated (below)


    As the MCU's "SPI Output" will "peak" at/around 3V3 - AND as the MCP4921 requires "0.7 Vdd" minimum (to "recognize" a logic high - i.e. 3V5 - when powered from 5V) - this "5V powering of MCP - will surely, "cause problems."     To prevent such - the MCP4921 should be powered from the (same) 3V3 as employed by the MCU.     (which further aids by insuring that both ICs - Power up/down - together...)

    Should a scope not be easily/quickly "in the cards" (available) poster's  (temporarily) slowing the SPI data rate -  enables a number of Leds (current limited)  to "confirm the presence" of  SPI signals.

    As always - poster (appears) to be "learning SPI" via a (reasonably) advanced device.      (Sure Violation of  "KISS!")     First or early - SPI "mastery" - is far better achieved via the employ of a "small capacity, SPI-based, 3V3 powered, EEProm.     Starting w/a complex device - rarely (never?) proceeds w/out  (predictable)  "Pain & Suffering!"   (enforced upon user & hapless helper crüe - endlessly)

  • Thanks for your respond.I tried to use the buffer approached but no luck. 

    This is signal form SSI pins. So do you think where is my mistake?

    #define NUM_SSI_DATA 2

    void SSI0_Interrupt(void);

    uint32_t pui32DataTx[NUM_SSI_DATA];
    uint32_t pui32DataRx[NUM_SSI_DATA];
    uint32_t ui32Index;
    volatile unsigned long g_ulSSI2RXTO = 0;

    void
    InitConsole(void)
    {
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    GPIOPinConfigure(GPIO_PB0_U1RX);
    GPIOPinConfigure(GPIO_PB1_U1TX);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);
    GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    UARTConfigSetExpClk(UART1_BASE, SysCtlClockGet(),115200,(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |UART_CONFIG_PAR_NONE));

    UARTEnable(UART1_BASE);
    }

    int
    main(void)
    {

    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
    SYSCTL_XTAL_16MHZ);
    InitConsole();
    UARTprintf("SSI ->\n");

    UARTprintf(" Mode: SPI\n");
    UARTprintf(" Data: 8-bit\n\n");

    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    GPIOPinConfigure(GPIO_PA4_SSI0RX);
    GPIOPinConfigure(GPIO_PA5_SSI0TX);
    GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 |GPIO_PIN_2);

    SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_2,SSI_MODE_MASTER,20000, 8);

    SSIEnable(SSI0_BASE);
    SSIIntEnable(SSI0_BASE,SSI_RXFF|SSI_RXTO);
    while(SSIDataGetNonBlocking(SSI0_BASE, &pui32DataRx[0]))

    {
    }
    SSIIntClear(SSI0_BASE,SSI_RXFF|SSI_RXTO);

    pui32DataTx[0] = 0x30;
    pui32DataTx[1] = 0x03;

    UARTprintf("Sent:\n ");


    for(ui32Index = 0; ui32Index < NUM_SSI_DATA; ui32Index++)
    {
    UARTprintf("'%c' ", pui32DataTx[ui32Index]);

    SSIDataPut(SSI0_BASE, pui32DataTx[ui32Index]);

    }

    while(SSIBusy(SSI0_BASE))
    {
    }

    IntEnable(INT_SSI0);

    while(g_ulSSI2RXTO == 0)
    {
    }
    UARTprintf("\nReceived:\n ");

    }

    while(1)
    {

    }
    return 0;
    }

    void SSI0_Interrupt(void)
    {
    uint32_t ui32Status;

    ui32Status=SSIIntStatus(SSI0_BASE,1);

    if(ui32Status & SSI_RXFF|SSI_RXTO)
    {
    g_ulSSI2RXTO++;

    // for(ui32Index=0;ui32Index < NUM_SSI_DATA; ui32Index++)
    {
    SSIDataGet(SSI0_BASE, &pui32DataRx);
    }

    }
    SSIIntClear(SSI0_BASE, ui32Status);
    }

  • Hello Nguyen,

    That doesn't look like SPI signals at all. Not sure if your scope settings are incorrect, but if you are sure they are fine then I would say you aren't getting any output.

    I would again recommend to remove the interrupt functionality for now and make sure you can send/receive with polling first and foremost.
  • I would ask - in addition - why is the scope set to "50mV" - when the valid SPI signal high must exceed 2V (2000mV) - "forty times" poster's setting!
  • Thanks a lot for all helps. Yep, It seem to not transmit any thing. I am beginer and could you recommend me the method to check that I have SPI signal or not? Thanks in advance.
  • nguyen thi hai van said:
    could you recommend a method to check that I have SPI signal

    Visual review of your scope-cap - as noted by Ralph (and now myself) - is one "method" - to check for the presence of SPI signals.    You do not!    (have any signals - remotely close - to SPI)

    In addition - the display of (just one) of the (normal) 4 SPI signals - disallows the detection of ANY,  "Signal Timing Errors!"     (ideally you'd want to display all 4 signals - not just one)     Should you have (only) a 2 Channel Scope - that would require you to perform several different scope setups (and screen-caps) as follows:

    • SPI: CLK & FSS   (or GPIO generated CS)
    • SPI:  CLK & MOSI
    • SPI: CLK & MISO
    • SPI: MOSI & FSS (or GPIO generated CS)

    This reveals the "merit" of a 4 Channel Scope - yet  the scope's bandwidth should trump "number of channels."     (there ARE means to "massage" 4 channels from a 2 channel scope - yet bandwidth suffers.)

    KISS dictates that you exercise your MCU's "SPI based PINS" in their GPIO Output Mode - initially.    If unloaded - you should note fast (rise/fall) waveforms - and signals reaching above 3V0.   (not the 100mV or so - your scope cap earlier revealed)    

    You can assist such GPIO testing by writing simple, GPIO Toggle Code - which runs at/around 0.3Hz - 1Hz.     (at these slowed rates - even a DMM can note the signal transitions & levels)    Once the signal levels are confirmed - upon all 4 "SPI Pins" (set temporarily as GPIO) - only then should you reconfigure those SAME 4 Pins to SPI Mode - set to a SLOW  SPI Data Rate.

    You have yet to note the voltage powering MCP4921 - which WAS earlier requested!      And proves VITAL to your final success...    (MCP must be powered from 3V3  (same as the MCU)  and "NOT 5V" for you to have "any chance" for project success...)

    You can,  "Speed, Ease, Enhance" the efforts of your helper crüe (that's a high goal of yours - is it not) - by producing & providing - the (clearly) detailed scope caps, above...    Allez!

  • Yes. I already powered MCP 3.3V but then no work.

    As your suggestion I display 2 channel scope for SPI. Nothing I got. I think I have mistake with code actually. In fact, MCP just only receive signal from TM4C123 and not send any signal. Is that ok if I "comment out" the "receiving data" part in code of TM4C123 and just only send data by SPIDataPut? 

    And I changed

     while(1) //(SSIDataGetNonBlocking(SSI0_BASE, &pui32DataRx[0]))

    pui32DataTx[0] = 0x3F;
    pui32DataTx[1] = 0xFF;

    for(ui32Index = 0; ui32Index < NUM_SSI_DATA; ui32Index++)
    {
    UARTprintf("'%c' ", pui32DataTx[ui32Index]);

    SSIDataPut(SSI0_BASE, pui32DataTx[ui32Index]);
    }

    Do you know which mistake I could have?

  • nguyen thi hai van said:
    I already powered MCP 3.3V but then no work.

    My friend - your description of, "NO WORK" is of  "near zero" value!      Later - you "clarify" by noting,  "Nothing I got."     (which is still uncertain.)    

    Does that "nothing" indicate that you were able to view,  "NO SIGNALS at all"  - from EVEN ONE - of the 4 Scope Caps requested?     Have you confirmed that your scope is working - especially that it can adequately note a signal w/in the 3 Volt range?    (none of this is clear - nor has been provided...)

    Indeed - "IF" the MCP does not require you - to handle or process any data it may send - then your (famed)  "Send & Pray" method (may) succeed.   (yet remains - always - suspect.)

    Should you "comment out" SPIDataGet() - would appear "ok" - provided the SPI RX Buffer does NOT become "over-whelmed."    I don't use this part often enough to (really) know.

    STILL - of  GREATEST CONCERN - is,  "Why your scope appears unable (or is reported as such) to Display SPI Signals (or any signals) at/around  3 Volt levels!      Your best bet is to order those 4 SPI Pins into GPIO Output Mode - and Toggle each (at/around 1/2 Hz) - and probe w/your Scope - to confirm the presence of 3V Signals.   Only after that's been implemented - and confirmed - should you  return to SPI.  

    Such was past detailed - and has NOT (yet) been reported - and all Diagnosis DIES at that point!      You must provide the meaningful data requested - for others to (meaningfully) assist...

  • Thanks all! Finally, My code is work!

    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_memmap.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/ssi.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"
    #define NUM_SSI_DATA 2
    uint32_t pui32DataTx[NUM_SSI_DATA];
    char *pcChars = "SSI Master send data.";
    int32_t i32Idx;
    int main(void)
    {

    //
    // Set the clocking to run directly from the external crystal/oscillator.
    // TODO: The SYSCTL_XTAL_ value must be changed to match the value of the
    // crystal on your board.
    //

    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
    SYSCTL_XTAL_16MHZ);
    // Enable the SSI0 peripheral
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);


    //
    // For this example SSI0 is used with PortA[5:2]. The actual port and pins
    // used may be different on your part, consult the data sheet for more
    // information. GPIO port A needs to be enabled so these pins can be used.
    // TODO: change this to whichever GPIO port you are using.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    //
    // Configure the pin muxing for SSI0 functions on port A2, A3, A4, and A5.
    // This step is not necessary if your part does not support pin muxing.
    // TODO: change this to select the port/pin you are using.
    //
    GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    GPIOPinConfigure(GPIO_PA4_SSI0RX);
    GPIOPinConfigure(GPIO_PA5_SSI0TX);
    GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 |
    GPIO_PIN_2);
    //
    // Wait for the SSI0 module to be ready.
    //
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_SSI0))
    {
    }
    //
    // Configure the SSI.
    //
    SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
    SSI_MODE_MASTER, 2000000, 16);
    //
    // Enable the SSI module.
    //
    SSIEnable(SSI0_BASE);
    //
    // Send some data.
    //
    i32Idx = 0;
    pui32DataTx[0]=0x3400;
    while(1)
    {
    SSIDataPut(SSI0_BASE, pui32DataTx[0]);

    }
    }

  • Would it not  "HELP ALL HERE" - if you'd (at least somewhat)  DESCRIBE what you CHANGED - to achieve success?    

    There were SO MANY Posts - trying to assist you - it proves VERY HARD (now) to discover,  "Just what you changed & FIXED!"    

    Your identification of your fix - would be much appreciated - Mercî.

  • Yes, I used oscilloscope to observe signal of CLK and MOSI at same time. I had some mistake in my code and I already fixed it as the code in previous message.

  • Thanks for that update.    

    Might you simply,  "Color High-Light" your "Code Fixes" - while (via another color) High-Lighting  your (earlier) "Code Errors?"   (as illustrated, here)

    You are intimately aware of your code - and changes.      Most new readers - arriving this thread - will  (suffer)  a "long & detailed HUNT" - without the (simple/eased) highlighting - herein suggested...

    Again - glad you persisted & succeeded - your "ILLUSTRATING that SUCCESS" would prove  MOST BENEFICIAL...