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.

Help on implementing SPI on EK-TM4C1294XL

Other Parts Discussed in Thread: EK-TM4C1294XL, EK-TM4C129EXL, ENERGIA

Hello,

I am getting familiar with the EK-TM4C1294XL board, trying to learn some basic things about ARM Cortex-M4 MCUs.
I need some help after having spent the entire day trying to implement SPI on EK-TM4C1294XL board.

I have browsed through several similar topics on this forum and played a little according to the suggestions therein, however without success. That is why I decided to make a new post.

The SPI device is an Analog Devices ADXL362 accelerometer that is mounted on a small breakout PCB. I have used that device sucessfully with a Raspberry Pi in the past.

Connections are as follows: I use the pins of the stacking connectors X6 and X7:

PQ0: SCLK

PQ1: ~CS

PQ2: MOSI

PQ3: MISO


I use Open Bench Logic Sniffer on my laptop PC to spy on the SPI bus. The TiVa evaluation kit runs on my desktop PC.

The code I use is the following:

// InitSPI3() - initialize SPI on SSI3
// Based on code that is available at:
// e2e.ti.com/.../1429666
void
InitSPI3(uint32_t SystemClock, uint32_t SPIMode, uint32_t SPIBitRate)
{
	// The SSI3 peripheral must be enabled for use.
	MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3);
	MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);

	// Configure the pin muxing for SSI0 functions on port Q0, Q1, Q2, and Q3.
	MAP_GPIOPinConfigure(GPIO_PQ0_SSI3CLK);		// SCLK
	MAP_GPIOPinConfigure(GPIO_PQ1_SSI3FSS);		// ~CS
	MAP_GPIOPinConfigure(GPIO_PQ2_SSI3XDAT0);	// MOSI
	MAP_GPIOPinConfigure(GPIO_PQ3_SSI3XDAT1);	// MISO

	// Configure the GPIO settings for the SSI pins. This function also gives
	// control of these pins to the SSI hardware.
	// The pins are assigned as follows:
	// PQ2 - SSI3Tx
	// PQ3 - SSI3Rx
	// PQ1 - SSI3Fss
	// PQ0 - SSI3CLK
	MAP_GPIOPinTypeSSI(GPIO_PORTQ_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0);

	// Configure and enable the SSI port for SPI MASTER mode.
	MAP_SSIConfigSetExpClk(SSI3_BASE, SystemClock, SPIMode, SSI_MODE_MASTER, SPIBitRate, 8);
	//MAP_SSIAdvModeSet(SSI3_BASE, SSI_ADV_MODE_LEGACY);
	MAP_SSIAdvModeSet(SSI3_BASE, SSI_ADV_MODE_READ_WRITE);
	MAP_SSIAdvFrameHoldEnable(SSI3_BASE);
	MAP_SSIEnable(SSI3_BASE);
}

// used project 'hello' as a base 
int
main(void)
{
    ...

    uint32_t ui32ADXL362_ReadDevID[] = {0x0B, 0x00};
    uint8_t i = 0;
    ...

    //
    // Run from the PLL at 120 MHz.
    //
    g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
                SYSCTL_CFG_VCO_480), 120000000);

    //
    // Configure the device pins.
    //
    PinoutSet(false, false);

    ...

	// Initialize the SPI.
	// Settings are compatible with the ADXL362 accelerometer.
	// CPOL=CPHA = 0, f_SCLK, max = 1 MHz
	//
	InitSPI3(g_ui32SysClock, SSI_FRF_MOTO_MODE_0, 500000);
    ...
     SysCtlDelay(1);
     i = 0;
     while(i < 2)
     {
     	SSIDataPutNonBlocking(SSI3_BASE, *(ui32ADXL362_ReadDevID+i++));
     }
     SysCtlDelay(1);
     
     while(1)
     {
          ...
     }
}

I try to read the Device ID by sending byte sequence 0x0B , 0x00 on the SPI bus. Page 20 of AD's datasheet shows the following waveforms for reading from a single address:

However, what I see on the SPI bus is different:

In InitSPI() function, using:

MAP_SSIAdvModeSet(SSI3_BASE, SSI_ADV_MODE_LEGACY);

results in having the ~CS line going to HIGH between successive byte transfers, which is not the desired case;

and using:

MAP_SSIAdvModeSet(SSI3_BASE, SSI_ADV_MODE_READ_WRITE);
MAP_SSIAdvFrameHoldEnable(SSI3_BASE);

results in the above pattern EXCEPT for the end of transmission; ~CS line does not go to HIGH level . MISO line remains silent:

My question is:

is there any way to implement SPI correctly? What kind of detail am I missing?

I followed a suggestion here and here to use a GPIO pin as ~CS. Here is what I tried, albeit unsuccessfully:

void
InitSPI3(uint32_t SystemClock, uint32_t SPIMode, uint32_t SPIBitRate)
{
	// The SSI3 peripheral must be enabled for use.
	MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3);
	MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);

	// Configure the pin muxing for SSI0 functions on port Q0, Q1, Q2, and Q3.
	MAP_GPIOPinConfigure(GPIO_PQ0_SSI3CLK);		// SCLK
	//MAP_GPIOPinConfigure(GPIO_PQ1_SSI3FSS);	// ~CS - commented out that line
	MAP_GPIOPinConfigure(GPIO_PQ2_SSI3XDAT0);	// MOSI
	MAP_GPIOPinConfigure(GPIO_PQ3_SSI3XDAT1);	// MISO

	// Configure the GPIO settings for the SSI pins. This function also gives
	// control of these pins to the SSI hardware.
	// The pins are assigned as follows:
 	// PQ2 - SSI3Tx
	// PQ3 - SSI3Rx
	// PQ0 - SSI3CLK
        // Excluding PQ1 from the following function call-will make that a GPIO line
	MAP_GPIOPinTypeSSI(GPIO_PORTQ_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_0);

    // rest of function is same as above
}

int
main(void)
{
    uint32_t ui32ADXL362_ReadDevID[] = {0x0B, 0x00};
    uint8_t i = 0;

    //
    // Run from the PLL at 120 MHz.
    //
    g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
                SYSCTL_CFG_VCO_480), 120000000);

    //
    // Configure the device pins.
    //
    PinoutSet(false, false);

   ...

    //
    // Initialize the SPI.
    // Settings are compatible with the ADXL362 accelerometer.
    // CPOL=CPHA = 0, f_SCLK, max = 1 MHz
    //
    InitSPI3(g_ui32SysClock, SSI_FRF_MOTO_MODE_0, 500000);
    
    // Initalize ~CS as a GPIO pin.
    GPIOPinTypeGPIOOutput(GPIO_PORTQ_BASE, GPIO_PIN_1);

    ...
    GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, 0);
    SysCtlDelay(1);
    i = 0;
    while(i < 2)
    {
    	SSIDataPutNonBlocking(SSI3_BASE, *(ui32ADXL362_ReadDevID+i++));
    }
    SysCtlDelay(1);
    GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, 1);

    ...
}

..?

i need to make this simple thing work, therefore I really count on your kind assistance.

  • Hi,

    First I would note the advanced mode in SSI is for sd-cards only and does "not work" with your device. It is recommended to use first the good working example provided by TI in your driverlib folder/examples/peripherals/SSI/spi_master.c file. Make a project with this file first, run it without any modifications first and analyze it with your tools. An oscilloscope also helps. Then change the ports/pins as needed.

    Also worth to read the user manual and driverlib functions, even the comments written before each function. Take care about the macro definitions found there.

    Petrei

  • George Metaxas said:
    i (I) need to make this simple thing work

    Climbing Mt. Everest proves simple - "taming" the multi-byte (demanding SPI mechanism) of the ADXL362 accelerometer - perhaps not so much.

    Friend Petrei provides his usual expert advice - which I fully second.

    Yet - when we learn to sail - is it wise to "lose sight" of the familiar coastline?    Many (most) - of those still afloat/breathing - would say, "No!"

    You've violated the great safety & comfort of, "KISS."    Petrei suggests your detailed/focused review of existing, "known good" SPI examples.   Roger that.    And - in honor of KISS - would your learning & confidence building not greatly increase by starting with a far simpler, "SPI-based" device?    (i.e. a small capacity, SPI EEprom or similar)

    Your more advanced "RPi" board "automates" much of SPI's multi-byte, "fine detail."    And you pay for that when you venture to these shores - where you must instead, "tease out" such exacting SPI data & device timing requirements - as demanded by ADXL & friends.

    Again as Petrei suggests - use of a decent scope (some storage capability)  [logic analyzer or SPI bus "sniffer" even better] will free you from "sailing (or coding) blind."   Usually my small tech team does best by mastering, "one small step at a time" - then building upon (expanding) that small gain in a systematic (and always logged/recorded/"paper trail") fashion...  

    In your case - a "simple" single SPI byte transfer - should be your initial goal.   Only when that's fully mastered - should you extend to 2 bytes - and then further...

    While you've designated this, "ADXL via SPI" task as, "simple" - your method of attack, "Not so much."    And here, now - may lie a truly effective, "simpler" way...

  • Dear Petrei and cb1_mobile, thank you for your answers. Honestly, I am familiar with the SPI protocol and I have used that in some designs *but* running on simpler MCU platforms.

    In fact, I am not "sailing blind"; it is a pity that the WYISIWYG editor did not display the snapshots from Open Logic Sniffer that I pasted therein.

    I am trying to climb the leanring curve very fast and am stumbling into details. I admit that I should have taken a simpler approach and this is what I am going to do right now, following the suggestion of Petrei. I will notify you of the results.

  • Hi,

    To make your life harder- if you like hacking - see this link, with a code example.

    Petrei

  • Diving immediately - into a, "not so simple" application - most always results in delay, pain, frustration - just as you report.

    Glad to see that you've (now) switched to, "simpler approach" - yet there's no mention of "smaller/simpler SPI target" - which best serves to build your capability, knowledge & confidence.

    Rome was not built in one day - although that was (likely) tried.    So too - ADXL often requires "building block approach" - starting with "simple SPI slave" so that one may truly master the (often) complex "write" & simultaneous "read" enforced by SPI.

    Shortcuts - on the high sea (or here) - too often yield, "Quite the opposite."

  • I found out what was going on...

    First of all, thanks to Petrei and cb1_mobile for their help to work that around.

    The aim of my experiment was to send a command to ADXL362 through SPI that would read its device iD. In particular, the command byte sequence is 0x0B 0x00 and the device ID that should be returned is 0xAD.

    During one of my several attempts to find out what was going on using my Open Bench Logic Sniffer, I noticed that the MISO line was not silent; it contained exactly what it should! The next glance was on my desktop / workbench and I noticed that the clip that was supposed to be hooked on SCLK node had slipped off. I repeated the capture several times with and without the clock signal and confirmed that when the SCLK signal was connected to the small logic analyzer, no data were on the MISO line.I checked the contents of the variables that I use and confirmed that their values were correct.

    The accelerometer is mounted on a small PCB that in turn is connected to headers X6 and X7 of my EK-TM41294XL board using a piece of ribbon cable about 10 cm long. In general, the logic analyzer I am using is very sensitive to the stray capacitance of my hand, as I noticed while getting acquainted with it. Therefore, I think that the problems encountered had to do partly with wrong configuration of the SSI as SPI and partly to issues with my experimental setup.

    Here is the code that works OK for the moment; I took project "hello" as a base and modified contents accordingly, based on the spi_master.c example that Petrei and cb1_mobile suggested me to look at.

    //*****************************************************************************
    //
    // SPI_demo.c - Simple SPI communications example using ADXL362 accelerometer.
    //
    // Based on hello.c project of TI - (c) 2013-2014 Texas Instruments Incorporated.
    //
    //*****************************************************************************
    
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "driverlib/gpio.h"
    #include "drivers/pinout.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/ssi.h"
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"
    #include "drivers/buttons.h"
    
    //*****************************************************************************
    //
    //! \addtogroup example_list
    //! <h1>Hello World (hello)</h1>
    //!
    //! An SPI communications example using the ADXL362 accelerometer.
    //! First, the device ID of the accelerometer is read;
    //!
    //! Open a terminal with 115,200 8-N-1 to see the output for this demo.
    //
    //*****************************************************************************
    
    // Number of bytes to send and receive.
    #define NUM_SSI_DATA            3
    
    // System clock rate in Hz.
    uint32_t g_ui32SysClock;
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
    }
    #endif
    
    //*****************************************************************************
    //
    // 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.
        //
        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.
        //
        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.
        //
        GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
        //
        // Initialize the UART for console I/O.
        //
        UARTStdioConfig(0, 115200, 16000000);
    }
    //*****************************************************************************
    //
    // Configure SSI3 in master Freescale (SPI) mode using polling method.
    //
    //*****************************************************************************
    int
    main(void)
    {
        uint32_t pui32DataTx[NUM_SSI_DATA];
        uint32_t pui32DataRx[NUM_SSI_DATA];
        uint32_t ui32Index;
    
        //
        // Run from the PLL at 120 MHz.
        //
        g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                    SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
                    SYSCTL_CFG_VCO_480), 120000000);
    
        //
        // Configure the device pins.
        //
        PinoutSet(false, false);
        //
        // 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();
    
        //
        // The SSI3 peripheral must be enabled for use.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3);
    
        //
        // For this example SSI3 is used with PortQ[0:3].
        // GPIO port Q needs to be enabled so these pins can be used.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
    
        //
        // Configure the pin muxing for SSI3 functions on port Q0, Q1, Q2 and Q3.
        // This step is not necessary if your part does not support pin muxing.
        //
        GPIOPinConfigure(GPIO_PQ0_SSI3CLK);	// SCLK
        GPIOPinTypeGPIOOutput(GPIO_PORTQ_BASE, GPIO_PIN_1);	// ~CS - configure it as GPIO output
        GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, GPIO_PIN_1);	// ~CS - set it to logic HIGH
        GPIOPinConfigure(GPIO_PQ2_SSI3XDAT0);	// MOSI
        GPIOPinConfigure(GPIO_PQ3_SSI3XDAT1);	// MISO
    
        //
        // 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:
        //      PQ3 - SSI0Rx
        //      PQ2 - SSI0Tx
        //      PQ1 - SSI0Fss
        //      PQ0 - SSI0CLK
        //
        GPIOPinTypeSSI(GPIO_PORTQ_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_0);
    
        //
        // Configure and enable the SSI port for SPI master mode.  Use SSI3,
        // system clock supply, idle clock level low and active low clock in
        // Freescale SPI mode, master mode, 1 MHz 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.
        //
        SSIConfigSetExpClk(SSI3_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_0,
                           SSI_MODE_MASTER, 1000000, 8);
    
        //
        // Enable the SSI0 module.
        //
        SSIEnable(SSI3_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(SSI3_BASE, &pui32DataRx[0]))
        {
        }
    
        //
        // Initialize the data to send.
        //
        pui32DataTx[0] = 0x0B;	// read mode
        pui32DataTx[1] = 0x00;	// register address to read
        pui32DataTx[2] = 0x00;	// dummy byte to generate SCLK for reading 1 byte from MISO
    
        //
        // Send 3 bytes of data.
        //
        GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, 0);	// ~CS - set it to logic LOW - start of transmission
        SysCtlDelay(1);
        for(ui32Index = 0; ui32Index < NUM_SSI_DATA; ui32Index++)
        {
        	SSIDataPut(SSI3_BASE, pui32DataTx[ui32Index]);
        	SSIDataGet(SSI3_BASE, &pui32DataRx[ui32Index]);
        }
    
        //
        // Wait until SSI3 is done transferring all the data in the transmit FIFO.
        //
        while(SSIBusy(SSI3_BASE))
        {
        }
    
        SysCtlDelay(1);
        GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, GPIO_PIN_1);	// ~CS - set it to logic HIGH - end of transmission
    
        // Now check the contents of pui32DataRx
        UARTprintf("Checking TX and RX data...\n");
        UARTprintf("i\tTX\tRX\n");
        UARTprintf("--------------------------\n");
        for(ui32Index = 0 ; ui32Index < NUM_SSI_DATA ; ui32Index++)
        {
        	UARTprintf("%d\t'%c'\t'%c'\n", 	ui32Index,
        									*(pui32DataTx+ui32Index),
        									*(pui32DataRx+ui32Index));
        }
    
        //
        // Return no errors
        //
        return(0);
    }
    

    As a next step, I will create some convenience functions as I have done on other platforms and continue with getting measurement data from the accelerometer.

  • Good for you, Sir.     As (so) long noted - KISS most always, "Speeds, Eases, Enhances" design/development - exactly as you (now) report!

  • Hello George,

    Just noticed that the first post had

    GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, 1);

    and the second working post had

    GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, GPIO_PIN_1);



    Regards
    Amit
  • In amplification of Amit's note (just above) that 3rd (last) parameter w/in "GPIOPinWrite()" must assign the cumulative, "bit position value" - which will then operate against those bits represented by the 2nd (mid) parameter.   Clear?    (as mud?)

    For example - if 2nd parameter is GPIO_PIN_3 - and we wish to "Set" that bit - parameter 3 would contain the value "8" - which may be represented as, "GPIO_PIN_3."

    Likewise - should the desired port output include bits 7 & 0 - 2nd (and 3rd) parameters must (at minimum) include "129."    (or - if carpal tunnel is unfeared - always delightful, "GPIO_PIN_0 | GPIO_PIN_7" works (and exhausts) as well...   

    When the "entire port byte" is desired - parameter 2 rises to 0xFF - potentially including each/every port bit - again based upon parameter 3's (limiting) value.

  • Amit and cb1, thank you both for your suggestions. Some typos were corrected and everything works OK now.
  • i have come up with another problem to work out.

    Up to now, I have managed to write and read data successfully on the SPI bus where an ADXL362 accelerometer is connected.

    I am working on having the SPI bus polled at a constant rate using SysTick interrupt. I tried to have 100 ticks per second, then 10 but without any apparent difference so far.  Please scroll down for my code.

    In the SysTick interrupt service routine (handler), I blink LED D2 on EK-TM4C1294XL with a period of 2 s (on for 1 s, then off for 1 s and so on); moreover, I moved the SPITransfer() function call inside that handler.

    However, the problem is that even though I write the correct command on the MOSI line, the MISO line returns all zeros. Here is a screenshot from my logic analyzer showing that a transaction lasts for 95.7 us:

    Without changing anything else in the code, when I move the SPITransfer() back into the while(1) loop in the main() function, everything works OK - but not at a known constant rate, of course.

    Your ideas to work around that issue are more than welcome.

    Code:

    //*****************************************************************************
    //
    // SPI_demo.c - Simple SPI communications example using ADXL362 accelerometer.
    //
    // Based on hello.c project of TI - (c) 2013-2014 Texas Instruments Incorporated.
    //
    //*****************************************************************************
    
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_uart.h"	// added by GM
    #include "driverlib/fpu.h"	// added by GM
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"	// added by GM
    #include "drivers/pinout.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"	// added by GM
    #include "driverlib/ssi.h"
    #include "driverlib/udma.h"	// added by GM
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"
    #include "drivers/buttons.h"
    
    //*****************************************************************************
    //
    //! \addtogroup example_list
    //! <h1>Hello World (hello)</h1>
    //!
    //! An SPI communications example using the ADXL362 accelerometer.
    //! First, the device ID of the accelerometer is read;
    //!
    //! Open a terminal with 115,200 8-N-1 to see the output for this demo.
    //
    //*****************************************************************************
    
    // Number of bytes to send and receive.
    #define NUM_SSI_DATA            3
    
    //*****************************************************************************
    //
    // The number of SysTick ticks per second used for the SysTick interrupt.
    //
    //*****************************************************************************
    #define SYSTICKS_PER_SECOND     10 // I changed that from 100 to 10 for testing
    
    // System clock rate in Hz.
    uint32_t g_ui32SysClock;
    
    //*****************************************************************************
    //
    // The number of seconds elapsed since the start of the program.  This value is
    // maintained by the SysTick interrupt handler.
    //
    //*****************************************************************************
    static uint32_t g_ui32Seconds = 0;
    
    // SPI TX and RX buffers
    uint32_t pui32DataTx[10];
    uint32_t pui32DataRx[10];
    
    // Variables to store values for X, Y, Z and temperature readings
    uint32_t ui32Index, ui32X, ui32Y, ui32Z, ui32Temp;
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
    }
    #endif
    
    //*****************************************************************************
    //
    // 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.
        //
        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.
        //
        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.
        //
        GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
        //
        // Initialize the UART for console I/O.
        //
        UARTStdioConfig(0, 115200, 16000000);
    }
    //*****************************************************************************
    //
    // Configure SSI3 in master Freescale (SPI) mode using polling method.
    //
    //*****************************************************************************
    void
    InitSPI(void)
    {
        uint32_t pui32Rx[10];
        //
        // The SSI3 peripheral must be enabled for use.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3);
    
        //
        // For this example SSI3 is used with PortQ[0:3].
        // GPIO port Q needs to be enabled so these pins can be used.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
    
        //
        // Configure the pin muxing for SSI3 functions on port Q0, Q1, Q2 and Q3.
        // This step is not necessary if your part does not support pin muxing.
        //
        GPIOPinConfigure(GPIO_PQ0_SSI3CLK);	// SCLK
        GPIOPinTypeGPIOOutput(GPIO_PORTQ_BASE, GPIO_PIN_1);	// ~CS - configure it as GPIO output
        GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, GPIO_PIN_1);	// ~CS - set it to logic HIGH
        GPIOPinConfigure(GPIO_PQ2_SSI3XDAT0);	// MOSI
        GPIOPinConfigure(GPIO_PQ3_SSI3XDAT1);	// MISO
    
        //
        // 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:
        //      PQ3 - SSI0Rx
        //      PQ2 - SSI0Tx
        //      PQ1 - SSI0Fss
        //      PQ0 - SSI0CLK
        //
        GPIOPinTypeSSI(GPIO_PORTQ_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_0);
    
        //
        // Configure and enable the SSI port for SPI master mode.  Use SSI3,
        // system clock supply, idle clock level low and active low clock in
        // Freescale SPI mode, master mode, 1 MHz 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.
        //
        SSIConfigSetExpClk(SSI3_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_0,
                           SSI_MODE_MASTER, 1000000, 8);
    
        //
        // Enable the SSI0 module.
        //
        SSIEnable(SSI3_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(SSI3_BASE, &pui32Rx[0]))
        {
        }
    }
    
    void
    CS_Low(void)
    {
    	GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, 0);
    }
    
    void
    CS_High(void)
    {
    	GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, GPIO_PIN_1);
    }
    
    void
    SPITransfer(uint32_t* pui32TX, uint32_t* pui32RX, uint32_t NoOfTXBytes, uint32_t NoOfRXBytes)
    {
        uint32_t i = 0;
        uint32_t temp;
    
        CS_Low();	// ~CS - set it to logic LOW - start of transmission
        SysCtlDelay(10);
        while(i < NoOfTXBytes+NoOfRXBytes)
        {
        	temp = (i < NoOfTXBytes) ? *(pui32TX+i) : 0x00;
        	SSIDataPut(SSI3_BASE, temp);
        	SSIDataGet(SSI3_BASE, pui32RX+i);
        	i++;
        }
    
        //
        // Wait until SSI3 is done transferring all the data in the transmit FIFO.
        //
        while(SSIBusy(SSI3_BASE))
        {
        }
    
        SysCtlDelay(10);
        CS_High();	// ~CS - set it to logic HIGH - end of transmission
    }
    
    void
    SysTickHandler(void)
    {
        static uint32_t ui32TickCount = 0;
        uint32_t temp;
    
        //
        // Increment the tick counter.
        //
        ui32TickCount++;
    
        SPITransfer(pui32DataTx, pui32DataRx, 2, 8);
    
        //
        // If the number of ticks per second has occurred, then increment the
        // seconds counter.
        //
        if(!(ui32TickCount % SYSTICKS_PER_SECOND))
        {
            g_ui32Seconds++;
            temp = GPIOPinRead(GPIO_PORTN_BASE, GPIO_PIN_0);
            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, GPIO_PIN_0 ^ temp);	// toggle LED0
        }
    }
    
    int
    main(void)
    {
        //
        // Run from the PLL at 120 MHz.
        //
        g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                    SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
                    SYSCTL_CFG_VCO_480), 120000000);
    
        //
        // Configure the device pins.
        //
        PinoutSet(false, false);
    
        //
        // Enable the GPIO port that is used for the on-board LED.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
    
        //
        // Enable the GPIO pins for the LED (PN0).
        //
        ROM_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0);
    
        //
        // 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();
    
        // Initializing SSI as SPI
        InitSPI();
    
        // Read the ADXL326 Device ID (should be 0xAD - probably for "Analog Devices")
        pui32DataTx[0] = 0x0B;	// read mode
        pui32DataTx[1] = 0x00;	// register address to read
        pui32DataTx[2] = 0x00;	// dummy byte to generate SCLK for reading 1 byte from MISO
    
        SPITransfer(pui32DataTx, pui32DataRx, 2, 1);
    
    
        // ADXL362 Software Reset
        pui32DataTx[0] = 0x0A;	// write mode
        pui32DataTx[1] = 0x1F;	// register address to write
        pui32DataTx[2] = 0x52;	// data to write (0x52 = 'R' for Reset)
    
        SPITransfer(pui32DataTx, pui32DataRx, 3, 0);
    
        // ADXL362 set to Measurement Mode
        pui32DataTx[0] = 0x0A;	// write mode
        pui32DataTx[1] = 0x2D;	// register address to write
        pui32DataTx[2] = 0x02;	// data to write (0x02 to enter measurement mode)
    
        SPITransfer(pui32DataTx, pui32DataRx, 3, 0);
    
    	// Now check the contents of pui32DataRx
    	UARTprintf("Checking data...\n");
    	UARTprintf("X\tY\tZ\tTemp.\n");
    	UARTprintf("--------------------------\n");
    
        // Read X. Y. Z and temperature data from ADXL362
        pui32DataTx[0] = 0x0B;	// read mode
        pui32DataTx[1] = 0x0E;	// register address to write
        ui32Index = 2;
    
        //
        // Configure SysTick to occur SYSTICKS_PER_SECOND times per second,
        // to use as a time reference.  Enable SysTick to generate interrupts.
        //
        SysTickPeriodSet(g_ui32SysClock / SYSTICKS_PER_SECOND);
        SysTickIntRegister(SysTickHandler);
        SysTickIntEnable();
        SysTickEnable();
    
        while(1)
        {
        	// I commented that out and moved it inside the SysTickHandler() function	
        	//SPITransfer(pui32DataTx, pui32DataRx, 2, 8); 
    
        	ui32X = *(pui32DataRx+ui32Index+0) | *(pui32DataRx+ui32Index+1) << 8;
        	ui32Y = *(pui32DataRx+ui32Index+2) | *(pui32DataRx+ui32Index+3) << 8;
        	ui32Z = *(pui32DataRx+ui32Index+4) | *(pui32DataRx+ui32Index+5) << 8;
        	ui32Temp = *(pui32DataRx+ui32Index+6) | *(pui32DataRx+ui32Index+7) << 8;
    
        	UARTprintf("%d\t%d\t%d\t%d\n", 	ui32X, ui32Y, ui32Z, ui32Temp);
        }
    }
    

  • Hello George

    Why not at a constant rate in main if you take out the SysTick Handler? The SPI Transfers take the same time on the bus. The computation of X,Y,Z and Temp take the same time and so does the Print function to complete.

    Can you attach a snapshot of the working case as well?

    Also did you try to erase the flash, power cycle the system and then attempt the SysTick based transfer?

    Regards
    Amit
  • Hi Amit, I will attach a snapshot of the working version later today. I will try erasing the flash memory, powering off and on the board and then programming it again.
    I want to use SysTick as a periodic polling mechanism and push it to the limit. I want to read samples from the device attached to the SPI bus at a known and constant data rate. After mastering this, I would want to get acquainted with DMA and have a working version with this.
  • George Metaxas said:
    I want to use SysTick as a periodic polling mechanism and push it to the limit

    Perhaps "SysTick" does not best meet your objective - it is not famed for high repeatability nor high speed.

    Conventional MCU timer is likely to far better serve your desire...   (that's been covered many times - forum search will inform/advise...)

  • Here I am again... After having played with my system I found out the following:

    When stepping over each line of the code, the system works as expected, with the accelerometer returning data when it is read.

    When stepping one or two of the first lines and then letting the code run freely, the accelerometer returns all zeros.

    I thought that the software reset that i invoke might need some time to establish itself in the accelerometer chip; I did not search the Web thoroughly about it, but did not find anything relevant to it; I just imagined that. Anyway, I put some delay after the software reset command:

        // ADXL362 Software Reset
        pui32DataTx[0] = 0x0A;	// write mode
        pui32DataTx[1] = 0x1F;	// register address to write
        pui32DataTx[2] = 0x52;	// data to write (0x52 = 'R' for Reset)
    
        SPITransfer(pui32DataTx, pui32DataRx, 3, 0);
        SysCtlDelay(500); // this s the delay I put; value by experimentation

    EDIT: I came back checking this and found out that the most recent revision of ADXL362's datasheet states that, after soft reset, a delay of at least 0.5 ms must be held. I calculated things and increased the delay to 40000, that corresponds to 1 ms of delay:

    SysCtlDelay(40000); // 1 ms > 0.5 ms

    With this, the ADXL362 works correctly now.

    I use RealTerm as a serial port terminal to read out the data that are written to the UART. It seems to be a little buggy, but it is sufficient for my job.

    I load the code with F11 in CCS, step over one or two lines of code, then clicking on 'Stop' button to let code run freely. I noticed that when I press the RESET switch button on EK-TM4C1294XL board all I get on RealTerm is a bunch of zeros; when I press the RESET switch again, I get the values I expect to.

    Strange, isn't it? There is something here that I am overlooking. Can you please help me with that?

    As far as timing diagrams are concerned, here are some screenshots from my logic analyzer:

    I use 10000 SysTicks per second.

    I pushed the SPI clock frequency up to 5 MHz:

  • George, others,

    OK, head is spinning. Trying to implement the simplest example of SPI ( an MFRC522 RFID card ) on the EK-TM4C129EXL:

    May I ask for some pearls of wisdom regarding First Principles here? Not even sure I've got pin mapping correct. I've been using the ENCPDT section of pinmap.h in an attempt to divine the answers

    I'm trying to use SSI2 on Port D - using BoosterPack 1 pin headers. Additionally, the card uses a RESET pin; have no idea how to interface with this.

    ( Please note - I do have a working model in Energia; I'm trying now to do this the Tiva driver way... )

        // LOU MOD: We're using SSI2 on PortD
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    
        //
        // Configure the pin muxing for SSI2 functions on port D
        // LOU MOD: we're using SSI2 on the EK-TM4C129EXL
        //
        GPIOPinConfigure(GPIO_PD3_SSI2CLK); // SCLK
        // LOU MOD: Using SDA -> PN3 (CS Other)
        // GPIO_PN3_U2CTS   ????
        GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_1); // ~CS - configure it as GPIO output
        GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, GPIO_PIN_1);  // ~CS - set it to logic HIGH
        GPIOPinConfigure(GPIO_PD1_SSI2XDAT0);   // MOSI
        GPIOPinConfigure(GPIO_PD0_SSI2XDAT1);   // MISO
    
        //
        // 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:
        //      Port Q                    Port D
        //      PQ3 - SSI0Rx        PD0 - SSI2Rx
        //      PQ2 - SSI0Tx         PD1 - SSI2Tx
        //      PQ1 - SSI0Fss       PN3 ??
        //      PQ0 - SSI0CLK      PD3 - SSI2CLK
        //                                     PC6 - RST
        //
        GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_0);

    My simple-minded first task is to read VersionReg register (address 37h) - getting back an 8-byte version string.

    I know a couple of you will have suggestions directly on-point.

  • Hello George

    I would suggest checking the software for the following TI Design. It uses the Advanced mode for communicating with a serial flash memory and the CS's work as expected.

    www.ti.com/.../TIDM-TM4C129SDRAMNVM
  • Thanks, Amit,
    I'm looking into it now...
    Along the way, may have found a bug in CCSv7 when invoking the ARM linker - will post to appropriate area...

    Lou, by the way. ( I was hoping to pick George's brain on this; he seems to have done almost exactly what I'm trying here. )
  • "Mousing over" poster George's "log in" reveals "quiet" - for beyond the past year.

    All of these serial bus exercises are aided greatly by your ability to monitor & capture the bus transactions. Scopes & Logic Analyzers are preferred - there may be less accurate "PC sniffers" which may function - as well.

    Slowed data rates is the preferred method to start such investigation - as is the use of the "simplest" SPI slave - usually a (very) small 8 pin memory IC... Adding complexity - far too early - is a sure violation of, "First Principles." (and friend KISS!)
  • Of course, yes; I did note George's absence - worth a try, right? (!)

    Yes, point taken on KISS and reductionism. Have no tiny SPI ICs to play with at the moment - until I get one...

    In fact, I think I'm pretty close. Pinouts are my biggest challenge at the moment. Software task - simply reading a version number from a register - will feel like landing on the moon...

    Logic Analyzer: Yes, the need is making itself clear. All development is on MacOS. Have pinged a couple of guys about these - whaddaya think? : https://www.saleae.com

  • Just as "One MCU vendor - ONLY & forever" is clearly unwise - a far broader search of scopes/analyzers would prove to your advantage - would it not?      Would not your visit to the "major" instrument makers provide greater insight into the range of performance and relative pricing of such?    Firm you mention is (very) small - unlikely to be "authorized" disty of leading firm instruments.

    When you note, "Pinouts as biggest challenge" - pardon - but you've "created that mess!"      These booster packs have added great Connection complications - where (many/most) could have been avoided.    Really - you have no need (beyond your ongoing torment) to employ such "boosters" (really, "retarders" imo) at this early stage...

    If you are "In compliance w/KISS" your purchase of a low capacity SPI memory and a small "holding" pcb - and a (very) short length of interconnect cable - reduces pinouts to "less than trivial."    While vendor's (famed) "booster" is, "Nowhere in play" - note that your connections have been vastly broadened & eased - some may (even) note they've been "Boosted."

    Indeed those "booster packs" boost something - but too often the objective is FAR EASIER & FASTER OBTAINED by a "Geo or Lou Custom Pack" (Non-Boosted) which simply, "Accomplishes your "Singular" Mission!"      (the mish-mash of interconnect restrictions - inflicted by "boost" - has caused your issue - and is EASILY SOLVED - by boost's rejection/replacement!)    KISS Rules - boost - not so much...

  • Hello folks, I have been away for quite long, but I did not forget the nice experience I had while developing a test application for some MEMS sensors last year; Amit, cb1, Petrei and others had helped me a lot then.

    Lou, I went through your code excerpt and noticed the following:

    GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_1); // ~CS - configure it as GPIO output (GM: you intend to use PD1 as ~CS)
    GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, GPIO_PIN_1);  // ~CS - set it to logic HIGH 
    GPIOPinConfigure(GPIO_PD1_SSI2XDAT0);   // MOSI (GM: but despite this, you want to have MOSI on PD1, which is the SPI function on that pin)

    You must use another pin for ~CS - for example, PN2, PN3 or PP2 as I can see on page 2 of the Quick Start Guide for your Launchpad. Just a GPIO pin that is driven LOW when a data transaction starts and HIGH when a transaction ends works OK.

    I strongly recommend to go through the code excerpt I had published in this post (in the beginning of the post). This is working code that you can modify by replacing Port Q with your Port D - or whatever is convenient. (The problem then was due to incorrect cabling; firmware on MCU was OK and since then it runs with no problems, AFAIK.)

    Hope the above can help you.

    PS:

    (a) About ~RESET pin on your NFC card, I do not know anything about that specific card but I would have a GPIO pin connected to it, driven HIGH at all times and LOW to reset that card. For example, use a pin on the same header that bears the SPI signals, like PP2 and anythig that is available to use, i.e. is not used anywhere else. Configure that pin as output and set it HIGH by default. Drive that pin LOW to reset your NFC card. In this way, your microcontroller resets the NFC card whenever you want - you program it to do so.

    (b) About logic analyzers: Yes, those devices are OK; I personally use this one: Open Bench Logic Sniffer

  • Those 'connection complications' are what I'm running into.

    Again, it's just a matter of honest naïvete; I assumed the booster pack connections were the perfectly reasonable place to start.

    Yes, will mount this bad boy up to a breadboard tomorrow. Yes, working 7 days a week on this...

    Have no SPI memory chips yet in hand; want to recommend a few? I have some QFN and TSSOP adapter cards coming in I could make use of.
  • Hello George,

    After a year's (escape) you return - and if I may note - in a very BIG & Helpful Way! Bravo - you really represent the best "spirit" of the forum.
    It is rare to be "thanked" - especially after poster's, "mission has been accomplished."

    Yet you were kind & caring enough to, "Aid another" (likely many others) and give thanks - reveals great character - highly impressive...
  • Lou (multi E),

    Recall the adage, "He who assumes."     Your use of the forum Search Box reveals the masses (so often) impacted by "booster Violations of KISS" - especially so in the ability to properly "inter-connect!"    If one can NOT connect - what has been boosted? (beyond: frustration, disappointment, delay etc.)

    As you continue your efforts - your use of "Forum Search" should prove second nature - "He who does NOT study history - is "doomed" to repeat it."      (George Santayana)

    As to SPI - sure I could "recommend" - but that trades "my effort/know how" for yours - does it not?     Either "hobby disty" (Mou or DK) has an extensive (again, same theme, Search Box) which quickly, easily locates such components - AND provides "P & D." (price/delivery)    and full specs...

    May I note that - once again - KISS is "curb kicked" (that Lou tendency is revealing) by use of QFN & TSSOP - that's just Krazy!       Those disty searches enable your specification of FAR Simpler Devices (i.e. DIP or SOIC - and also suitable "holding proto boards" for both) for "Prototyping" - that's what your goal is for now - is it not?

    Adding complexity will NOT prove your friend - should be resisted at every turn/bend - even if such IS your tendency - especially if such IS your tendency... (Lou (multi E) may be modified to "Lou KISS" - which "reminds" & proves less "inflating!")      (we "get" your issue w/some EEs...)

  • George!

    First, I must thank you for returning from your sabbatical(!) to help the intrepid noob here... Your input has helped a lot. I'm chipping away at the iceberg little by little.

    Following your suggestion, I seem to have SSI3 more or less properly set up on Port Q

        GPIOPinConfigure(GPIO_PQ0_SSI3CLK);     // SCLK
        GPIOPinConfigure(GPIO_PQ1_SSI3FSS);     // CS
        GPIOPinConfigure(GPIO_PQ2_SSI3XDAT0);   // MOSI
        GPIOPinConfigure(GPIO_PQ3_SSI3XDAT1);   // MISO
    
        // Initalize ~CS as a GPIO pin.
        GPIOPinTypeGPIOOutput(GPIO_PORTQ_BASE, GPIO_PIN_1);
    
        // Initalize RESET as a GPIO pin. No idea if this works!
        // PM6 is PortM PIN 6 ??
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOM);
        GPIOPinTypeGPIOOutput(GPIO_PORTM_BASE, GPIO_PIN_6); // This is true _because_ it's 'PM6' ?
        // driven HIGH at all times and LOW to reset it (George).
        // This creates trouble: GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_6, 1);   // set RESET High

    ( though I'm clearly still fumbling with RESET )
    With above line commented, I do get some kind of 'response' from SPI:

    SSI ->
     Mode: SPI
     Data: 8-bit

    Sent:
     's' 'p' 'i' 

    Received:
     'u' 'y' 'x'

    However, when I try to write anything to GPIO_PIN_6, I get no error, but no output from code...

    Dare I try a couple of straight-up questions?
    By what logic/model does GPIOPinTypeSSI 'know' these pin names?
    How are they (reverse) ordered as they are?
    How would one alias the names of these pins? IE, making GPIO_PIN_6 == RESET_DEVICE_1 or similar?

    Meanwhile, I've found some good example code for the MFRC522 on another platform - thanks Kyle Smith! - which I think I should try to 'translate'. still trying to understand the TivaWare approach to this:

    ( just figuring out how to read the VersionReg  0x37 would probably get me off the ground. )

    /*
     * Function Name:Write_MFRC5200
     * Function Description: To a certain MFRC522 register to write a byte of data
     * Input Parameters:addr - register address; val - the value to be written
     * Return value: None
     */
    void Write_MFRC522(uchar addr, uchar val) {
      uint32_t rx_bits;
    
      // set the select line so we can start transferring
      MSS_SPI_set_slave_select( &g_mss_spi1, MSS_SPI_SLAVE_0 );
    
      // even though we are calling transfer frame once, we are really sending
      // two 8-bit frames smooshed together-- sending two 8 bit frames back to back
      // results in a spike in the select line which will jack with transactions
      // - top 8 bits are the address. Per the spec, we shift the address left
      //   1 bit, clear the LSb, and clear the MSb to indicate a write
      // - bottom 8 bits are the data bits being sent for that address, we send
      //   them as is
      rx_bits = MSS_SPI_transfer_frame( &g_mss_spi1, (((addr << 1) & 0x7E) << 8) |  val );
    
      // clear the select line-- we are done here
      MSS_SPI_clear_slave_select( &g_mss_spi1, MSS_SPI_SLAVE_0 );
    
      // burn some time
      // volatile uint32_t ticks;
      // for(ticks=0; ticks < 5000; ++ticks);
    }
    
    
    /*
     * Function Name:Read_MFRC522
     * Description: From a certain MFRC522 read a byte of data register
     * Input Parameters: addr - register address
     * Returns: a byte of data read from the
     */
    uchar Read_MFRC522(uchar addr) {
      uint32_t rx_bits;
    
      // set the select line so we can start transferring
      MSS_SPI_set_slave_select( &g_mss_spi1, MSS_SPI_SLAVE_0 );
    
      // even though we are calling transfer frame once, we are really sending
      // two 8-bit frames smooshed together-- sending two 8 bit frames back to back
      // results in a spike in the select line which will jack with transactions
      // - top 8 bits are the address. Per the spec, we shift the address left
      //   1 bit, clear the LSb, and set the MSb to indicate a read
      // - bottom 8 bits are all 0s on a read per 8.1.2.1 Table 6
      rx_bits = MSS_SPI_transfer_frame( &g_mss_spi1, ((((addr << 1) & 0x7E) | 0x80) << 8) | 0x00 );
    
      // clear the select line-- we are done here
      MSS_SPI_clear_slave_select( &g_mss_spi1, MSS_SPI_SLAVE_0 );
    
      // burn some time
      // volatile uint32_t ticks;
      // for(ticks=0; ticks < 5000; ++ticks);
    
        return (uchar) rx_bits; // return the rx bits, casting to an 8 bit int and chopping off the upper 24 bits
    }

    Thanks again for help you've offered already.

  • Oh, I'm using the search box like a madman, believe me. One of your earlier posts on bitbanging the blinky example saved me a lot of time, eg.

    Not to worry, I'm not using any QFN or TSSOP packages to 'test' SPI!! ( but do have these adapters around for other purposes )

    Am trying to step through the process methodically; tests are often one line of code at a time...

    As to the multitude of 'EEEEs':

    First, it's meant to be a clear distinction from the more normal 'EE' - there are probably more than a few of you here who've actually earned those two EEs...

    No, mine was meant to communicate a bit more of 'EEEE! Hair on fire!' - or similar (!) - because that's what this ride has felt like so far!

    ;) 

  • LouEEEE! said:
    Hair on fire!' - or similar (!) - because that's what this ride has felt like so far!

    I'll propose that our local, non-denominational, "Prayer Group" - offer one up in your behalf - our next session.      (perhaps even before the wine (really) kicks in - and (some) forget, "why we've rented this fine hall...")

    Your mastery of "Disty Search Box" and success in finding "DIP or SOIC" (small - very small capacity) EEprom deserves mention.     This as even "one line of code - aimed at a complex device - may over-challenge."      

    You past spoke of "idiot boss" - that suggests that "after hours" you may appropriate a basic scope (from your firm) - and confirm the SPI signals "are" as you wished.     Such proves SO important - the feedback provided "propels your learning" as it arrives SO quickly & convincingly...    (immediacy of  "accurate feedback" is highly sought & valued - throughout the educational/learning process)

    While the, "feeling" - provoked by the ride -  often "ignites" your "hair-care product" - I stand by the "natural" reinforcement encoded w/in,  "Lou_KISS."      That "tendency" towards the complex is unlikely to be recognized or corrected by "EEEE."      Replacement w/the far more, meaningful/guiding,  "KISS" appears a productive upgrade...

  • Good Morning from Greece! It is a rare moment when I can sit in front of my desktop PC to do 2-3 things before getting some sleep...

    Lou, I checked your code excerpt quickly and found the following:

    // This creates trouble: GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_6, 1);   // set RESET High
    
    // To set PM6 HIGH:
    GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_6, GPIO_PIN_6);   // set RESET High
    // To set PM6 LOW:
    GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_6, 0);   // set RESET Low
    
    // Same thing goes for ~CS as well and any other GPIO pin

    To be 100% sure about ~CS functionality, I would replicate what I have done in the past: configure pin PQ1 as GPIO, forgetting all about SSI and so on - like this:


    // CS_Low()
    //
    // Pulls ~CS line LOW to indicate the start of an SPI transaction.
    void CS_Low(void)
    {
        ROM_GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, 0);
    }

    // CS_High()
    //
    // Pulls ~CS line HIGH to indicate the end of an SPI transaction.
    void CS_High(void)
    {
        ROM_GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, GPIO_PIN_1);
    }

    // InitSPI(void) // // Configures SSI3 in master Freescale (SPI) mode using polling method. // Uses PQ1 to drive the ~CS line. void InitSPI(void) { // The SSI3 peripheral must be enabled for use. ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3); // For this example SSI3 is used with PortQ[0:3]. // GPIO port Q needs to be enabled so these pins can be used. ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ); ROM_GPIOPinTypeGPIOOutput(GPIO_PORTQ_BASE, GPIO_PIN_1); // ~CS - configure it as GPIO output ROM_GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, GPIO_PIN_1); // ~CS - set it to logic HIGH // Configure the pin muxing for SSI3 functions on port Q0, Q2 and Q3. // This step is not necessary if your part does not support pin muxing. ROM_GPIOPinConfigure(GPIO_PQ0_SSI3CLK); // SCLK ROM_GPIOPinConfigure(GPIO_PQ2_SSI3XDAT0); // MOSI ROM_GPIOPinConfigure(GPIO_PQ3_SSI3XDAT1); // MISO // 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: // PQ3 - SSI0Rx // PQ2 - SSI0Tx // PQ1 - SSI0Fss // PQ0 - SSI0CLK ROM_GPIOPinTypeSSI(GPIO_PORTQ_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_0); // Configure and enable the SSI port for SPI master mode. Use SSI3, // system clock supply, idle clock level low and active low clock in // Freescale SPI mode, master mode, 1 MHz 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. ROM_SSIConfigSetExpClk(SSI3_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 1000000, 8); // Enable the SSI3 module. ROM_SSIEnable(SSI3_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(ROM_SSIDataGetNonBlocking(SSI3_BASE, &pui8DataRx[0])) { } }

    As far as code "translation" for the NFC module is concerned, try to do it after ensuring that you can send and receive bytes over SPI reliably. It won't be that difficult...

    Let me and the other colleagues know of your efforts and results.

  • George!

    You're golden - and thanks again for the help here...

    I do have basic SPI comms working - the 3-byte, 8-bits per frame example in spi_master.

    I hope to be getting back to this later tonight myself - yes, regular workday first, then fun stuff in the wee hours - will try your suggestions. Like moving CS out of SPI 'block' altogether. I'll follow the same pattern in implementing the RESET on this bad boy...

    ( Yes, had noted that syntax to set a pin high - GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, GPIO_PIN_1) - in postings by You, cb1_mobile, Daniel Vamos...  Interesting. Right, not quite as simple as passing a '1' to it... )

    My current minor (I think?) task is in converting the 8-bit frame size to the 16 required by the MFRC522.

    After I get any 16-bit frames moving around, I'll move to next item. Great Fun!

    Thanks again! 

  • Sigh - while poster George is indeed "great" - it is revealed that the (always) helpful KISS has - once more - been "Curb-Kicked" and that cannot be good. There appears no mention of the "success" achieved w/simple, propelling, SPI EEprom - thus that confidence/familiarity builder (i.e. REAL LAUNCH) has been rejected.

    The report of, "basic SPI comms working" does not register as (especially) compelling. SPI is a bi-directional bus - and "working" MUST mean that a "Commanded SPI Transmit" is "Answered by a properly responding SPI Slave." Might it be that such "report of working" is (somewhat) premature? (I'd wager the "spare" car - not quite the farm (yet).)

  • OK, just in case you might have thought I wasn't listening...

    cb1_mobile, in the interest of 'KISS': During what must have looked like a sabbatical, I've acquired a logic analyzer, and am trying this on an EEPROM chip - though perhaps not the simplest, at least one pretty well documented - the Microchip 25LC1024. I've been able to 'monkey do' based on a lot of examples floating around.

    George, have implemented your suggestion about breaking out control of CS line, and can demonstrate clear High/Low control over it.

    Have been doing most testing in SSI_FRF_MOTO_MODE_0, but get only 00s on MISO. Running with With polarity reversed MOTO_MODE=1, I get something on MISO, but still nothing useful. Trace attached.

    In overview, the logic is:

    Open the Write Enable Latch 0x06

    Write command 0x02, then write data 0xAA to address '42' - 25LC1024 requires 24-bit addresses

    Attempt to read (0x03) from same address results in only tears...

    I can post explicit code snippet in a few hours if this helps, but does anything jump out at anyone?

  • LouEEEE! said:
    Microchip 25LC1024. [Requires 24 bit address!]   I've been able to 'monkey do' based on a lot of examples floating around.

    My friend - recommendations presented are done so w/good consideration - and your (choice) of, "Examples floating around" has, "kicked "KISS!" forcefully to the curb!"       As a manager - why would you choose such over the personal attention (and gentle direction) you receive here - from one, (skilled, experienced, connected & driven enough) to co-found - then take Tech Firm PUBLIC?     At the minimum - you could have acquired: ONE small device, as directed - and ONE humongous one - guaranteed to over-challenge.     (as it has - as (easily) predicted!)

    Use of the smallest/simplest EEprom - surely  NOT one demanding a 24 bit address - had far greater chance of success!        (I am aware of course of the "uber compelling" nature of such, "Examples floating around" - yet w/the markedly diminished vendor presence here - you might (somewhat/slightly) consider the requests of your (remaining) "outlaw" staff.

    Should you choose "KISS" - I'll try (as able) to assist.       Absent that - I cannot & will not encourage, "Anti-KISS."       Perhaps your skilled,  "Examples floating around" crüe can offer their (floating) assistance...

  • Oh, I thought this was sufficiently simple... ( Especially as we have these parts, and are likely to use/want such things )

    Yikes! I've been shunned! And before I've even had a chance to explain chasse au dahu? !!

  • True that - we "outsiders" must attend to rigorous, "Profit Making" - and arrive here on (brief breaks, or while (for pay) data is being collected) and our "undue exercising" serves NONE here...

    Again you make mention of, "We have these parts" - yet is it not (curious) that "we" prove little available - or able/interested - to guide & direct your efforts?