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: TM4C123GXL Launchpad -MCP4131 SPI Communication using KEIL uVision

Part Number: TM4C123GH6PM
Other Parts Discussed in Thread: ENERGIA

Tool/software: TI C/C++ Compiler

I tried to interface the Digital Potentiometer MCP4131 with the Tiva TM4C123GXL LaunchPad through SPI. An LED was connected to the output of MCP4131. Referring the data sheet and videos the code was written, compiled and programmed using Keil uvision5. SPI pins were not giving any signals when checked using DSO. The code is as given below. Please find out the error and devise a solution.

#include <stdint.h>
#include <stdlib.h>
#include "TM4C123GH6PM.h"



void spi_master_ini(void){
SYSCTL->RCGCSSI|=(1<<2); 
SYSCTL->RCGC2|=(1<<1); 
GPIOB->AFSEL|=(1<<4)|(1<<6)|(1<<7);
GPIOB->AFSEL&=~(1<<5);
GPIOB->PCTL|=(2<<16)|(2<<20)|(2<<24)|(2<<28);
GPIOB->DEN|=(1<<4)|(1<<5)|(1<<6)|(1<<7);
GPIOB->DIR|=(1<<5);
GPIOB->PUR|=(1<<4)|(1<<5)|(1<<6)|(1<<7);
SSI2->CR1&=(1<<1);
SSI2->CR1=0x00000000; 
SSI2->CC=0x00; 
SSI2->CPSR=8; 
SSI2->CR0=(0x7<<0); 
SSI2->CR1|=(1<<1); 
}

void SPI_write(uint8_t data){
SSI2->DR=data; 
while((SSI2->SR&(1<<0))==0); 
}



int main(){

SystemInit();
spi_master_ini();
GPIOB->DATA|=(1<<5);
GPIOB->DATA&=~(1<<5);
SPI_write(0x00);
for(int j=0;j<128;j++)
SPI_write(j);

for(int i=0;i<15;i++)
GPIOB->DATA|=(1<<5);
while(1)
{
GPIOB->DATA&= ~(1<<5);
SPI_write(0x00);//sending string
for(int j=0;j<128;j++)
SPI_write(j);
for(int i=0;i<15;i++)
GPIOB->DATA|=(1<<5);
}
return(0);
}

  • Hello SruMo,

    You should be using TivaWare for this application. Please download it from: http://www.ti.com/tool/SW-TM4C

    There are examples for SPI in [Install Path]\TivaWare_C_Series-2.1.4.178\examples\peripherals\ssi
  • I tried that way too early....I made modification in the spi_master.c program and tried to implement the interfacing...Still it was not working..Can you suggest why the code I posted is not working ?

  • Hello SruMo,

    First of all, you should go back to TivaWare if you want support for this.

    Secondly, start with the basic TivaWare examples and see that you can get communication on SPI verified.

    Once you have this done, then attach your application specific device and review the device's datasheet to ensure SPI is configured. If you do these steps correctly, then you should get communication. If you are not, then please post which example you tested with for a baseline that you have configured SPI with TivaWare correctly, and then list what changes were made to interface your device to the previously working example along with the source code.
  • Hi Ralph,
    Thankyou for your valuable suggestions. I will follow your steps and get back to you..Initially I couldn't obtain SPI signals for any of the examples..Nyways will try once again . I was able to establish the SPI communication between the digital pot and another board..So it's the TIVA board Code that I have to work on..
  • Hi,
    I tried to execute SPI code in KEIL and Energia. According to the datasheet of mcp4131, 16 bit command is to be sent to the pot to write value to the wiper register. 0x00 and 0x7E sent in two steps to write a value 126. SPI_Master.c Code in example of TIVA Launchpad is modified for the same. Still the communication is not working. Is SPI communication using TM4C123 board this much difficult to establish? Please provide suitable solution to get the communication established

    //*****************************************************************************
    //
    // spi_master.c - Example demonstrating how to configure SSI0 in SPI master
    // mode.
    //
    // Copyright (c) 2010-2016 Texas Instruments Incorporated. All rights reserved.
    // Software License Agreement
    //
    // 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.
    //
    // This is part of revision 2.1.3.156 of the Tiva Firmware Development Package.
    //
    //*****************************************************************************

    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.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"

    //*****************************************************************************
    //
    //! \addtogroup ssi_examples_list
    //! <h1>SPI Master (spi_master)</h1>
    //!
    //! This example shows how to configure the SSI0 as SPI Master. The code will
    //! send three characters on the master Tx then polls the receive FIFO until
    //! 3 characters are received on the master Rx.
    //!
    //! This example uses the following peripherals and I/O signals. You must
    //! review these and change as needed for your own board:
    //! - SSI0 peripheral
    //! - GPIO Port A peripheral (for SSI0 pins)
    //! - SSI0Clk - PA2
    //! - SSI0Fss - PA3
    //! - SSI0Rx - PA4
    //! - SSI0Tx - PA5
    //!
    //! The following UART signals are configured only for displaying console
    //! messages for this example. These are not required for operation of SSI0.
    //! - UART0 peripheral
    //! - GPIO Port A peripheral (for UART0 pins)
    //! - UART0RX - PA0
    //! - UART0TX - PA1
    //!
    //! This example uses the following interrupt handlers. To use this example
    //! in your own application you must add these interrupt handlers to your
    //! vector table.
    //! - None.
    //
    //*****************************************************************************

    //*****************************************************************************
    //
    // Number of bytes to send and receive.
    //
    //*****************************************************************************
    //#define NUM_SSI_DATA 3

    //*****************************************************************************
    //
    // This function sets up UART0 to be used for a console to display information
    // as the example is running.
    //
    //*****************************************************************************
    void
    InitConsole(void)
    {
    //
    // Enable GPIO port A which is used for UART0 pins.
    // TODO: change this to whichever GPIO port you are using.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    //
    // Configure the pin muxing for UART0 functions on port A0 and A1.
    // 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_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);

    //
    // Enable UART0 so that we can configure the clock.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    //
    // Use the internal 16MHz oscillator as the UART clock source.
    //
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);

    //
    // Select the alternate (UART) function for these pins.
    // TODO: change this to select the port/pin you are using.
    //
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    //
    // Initialize the UART for console I/O.
    //
    UARTStdioConfig(0, 115200, 16000000);
    }

    //*****************************************************************************
    //
    // Configure SSI0 in master Freescale (SPI) mode. This example will send out
    // 3 bytes of data, then wait for 3 bytes of data to come in. This will all be
    // done using the polling method.
    //
    //*****************************************************************************
    int main(void)
    {
    #if defined(TARGET_IS_TM4C129_RA0) || \
    defined(TARGET_IS_TM4C129_RA1) || \
    defined(TARGET_IS_TM4C129_RA2)
    uint32_t ui32SysClock;
    #endif

    //
    // 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.
    //
    #if defined(TARGET_IS_TM4C129_RA0) || \
    defined(TARGET_IS_TM4C129_RA1) || \
    defined(TARGET_IS_TM4C129_RA2)
    ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
    SYSCTL_OSC_MAIN |
    SYSCTL_USE_OSC), 25000000);
    #else
    SysCtlClockSet(SYSCTL_SYSDIV_20 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
    SYSCTL_XTAL_16MHZ);
    #endif

    //
    // Set up the serial console to use for displaying messages. This is
    // just for this example program and is not needed for SSI operation.
    //
    InitConsole();

    //
    // Display the setup on the console.
    //
    UARTprintf("SSI ->\n");
    UARTprintf(" Mode: SPI\n");
    UARTprintf(" Data: 8-bit\n\n");

    //
    // The SSI0 peripheral must be enabled for use.
    //
    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);

    //
    // Configure the GPIO settings for the SSI pins. This function also gives
    // control of these pins to the SSI hardware. Consult the data sheet to
    // see which functions are allocated per pin.
    // The pins are assigned as follows:
    // PA5 - SSI0Tx
    // PA4 - SSI0Rx
    // PA3 - SSI0Fss
    // PA2 - SSI0CLK
    // TODO: change this to select the port/pin you are using.
    //
    GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 |
    GPIO_PIN_2);

    //
    // Configure and enable the SSI port for SPI master mode. Use SSI0,
    // system clock supply, idle clock level low and active low clock in
    // freescale SPI mode, master mode, 1MHz SSI frequency, and 8-bit data.
    // For SPI mode, you can set the polarity of the SSI clock when the SSI
    // unit is idle. You can also configure what clock edge you want to
    // capture data on. Please reference the datasheet for more information on
    // the different SPI modes.
    //
    #if defined(TARGET_IS_TM4C129_RA0) || \
    defined(TARGET_IS_TM4C129_RA1) || \
    defined(TARGET_IS_TM4C129_RA2)
    SSIConfigSetExpClk(SSI0_BASE, ui32SysClock, SSI_FRF_MOTO_MODE_0,
    SSI_MODE_MASTER, 1000000, 8);
    #else
    SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
    SSI_MODE_MASTER, 1000000, 8);
    #endif

    //
    // Enable the SSI0 module.
    //
    SSIEnable(SSI0_BASE);

    //
    // Read any residual data from the SSI port. This makes sure the receive
    // FIFOs are empty, so we don't read any unwanted junk. This is done here
    // because the SPI SSI mode is full-duplex, which allows you to send and
    // receive at the same time. The SSIDataGetNonBlocking function returns
    // "true" when data was returned, and "false" when no data was returned.
    // The "non-blocking" function checks if there is any data in the receive
    // FIFO and does not "hang" if there isn't.
    //
    // while(SSIDataGetNonBlocking(SSI0_BASE, &pui32DataRx[0]))
    // {
    // }

    // //
    // // Initialize the data to send.
    // //
    // pui32DataTx[0] = 's';
    // pui32DataTx[1] = 'p';
    // pui32DataTx[2] = 'i';

    // //
    //
    // Send 3 bytes of data.
    //
    // for(ui32Index = 0; ui32Index < NUM_SSI_DATA; ui32Index++)
    // {
    //
    // Display the data that SSI is transferring.
    //
    // UARTprintf("'%c' ", pui32DataTx[ui32Index]);

    //
    // Send the data using the "blocking" put function. This function
    // will wait until there is room in the send FIFO before returning.
    // This allows you to assure that all the data you send makes it into
    // the send FIFO.
    //
    SSIDataPut(SSI0_BASE, 0x00);
    SSIDataPut(SSI0_BASE, 0x7E);
    // }

    //
    // Wait until SSI0 is done transferring all the data in the transmit FIFO.
    //
    while(SSIBusy(SSI0_BASE))
    {
    }

    //for(ui32Index = 0; ui32Index < NUM_SSI_DATA; ui32Index++)
    //{
    //
    // Receive the data using the "blocking" Get function. This function
    // will wait until there is data in the receive FIFO before returning.
    //
    // SSIDataGet(SSI0_BASE, &pui32DataRx[ui32Index]);

    //
    // Since we are using 8-bit data, mask off the MSB.
    //
    // pui32DataRx[ui32Index] &= 0x00FF;

    //
    // Display the data that SSI0 received.
    //
    // UARTprintf("'%c' ", pui32DataRx[ui32Index]);
    //}

    //
    // Return no errors
    //
    return(0);
    }
  • Earlier you reported that your DSO saw no output from your chosen SPI pins.

    Is this (still) the condition? Does this lack of output inflict SPI_Clock & SPI_MOSI as well as SPI_CS? (FSS here)

    If you (are) now achieving SPI output - have you "matched" the MCU's SPI format to that required by your slave device? That's critical for your success.
  • Hello SruMo,

    As cb1 is asking, we don't understand the state of your SPI communication...

    SruMo said:
    Still the communication is not working.

    Okay, what is not working? Are you getting any bytes out? How are you monitoring the SPI lines? Can you provide any oscilloscope captures of what is currently occurring with the SPI lines?

    We really don't have much to work from here... the code you posted may help later when we understand what is failing, but you need to describe in much more detail what is failing exactly.

  • And - if I may - we really do NOT benefit from the "extra monitoring function provided by the UART." (it has NOT provided much help here - has it?)

    UART and all other (extraneous) code does "bombard your helper crüe w/more data" - thus tends to increase workload WHILE obscuring your REAL SPI code.     Neither works toward your benefit - even w/motivated helper assistance.

    You must (always) realize that vendor (and we outsiders) cannot see nor touch your system - we rely ENTIRELY upon your communicating, "Vital Facts" so that we may make the best possible diagnosis.

    While "Brevity of Code" is important (i.e. just the MCU Set-Up and essential SPI code portions ... we really don't need vendor's legal "boiler-plate", too) the opposite holds true for your "narrative/description" of what EXACTLY is Failing - what you've done to confirm that - how & where you've measured - all prove VITAL.    (again - we are not "by your side" - we rely upon your power of description to be able to assist...)

    Earlier you noted that you achieved "success" w/another MCU board talking to your digital pot.    Unknown is "How you are powering (both) your "4C123 board" AND your digital pot?"    Does the remote device receive full power/voltage when the transaction is attempted?   (really?)    Have you "ohmed out" continuity between the 4 MCU SPI pins and the 4 Slave pins?   (really?)

    If a scope is available - may we see the SPI data arriving "At the Slave" during your initial addressing of the slave?   (are you sure that you understand the "7 bit addressing scheme dictated by I2C" - and its implementation by the TM4C family?)    (especially by the TM4C family!)    This is why a Scope Cap is SO IMPORTANT!     Should you "foul" the slave address - you/Ralph & I may be here, "forever!"

  • HI,
    My issue was solved by modifying the mcp4131-TM4c123 program in Energia by using new altSPI.h got from Energia forum. But SPI program written using KEIL which i posted above didnt work at all for me. I was not getting any bytes from SPI clock, SPI_FSS AND MOSI on the logic analyser. But now i have achieved the bytes and clock in the way needed for the application and the digital pot was successfully interfaced with the help of new program written in Energia.  Thank you.