Tool/software: Code Composer Studio
Hi,
I have been using the TM4C for a 6 months now and getting fairly familiar with it. In my design, I am trying to communicate between two TM4C's using QUAD or BI SSI mode. I am unable to get the advanced quad or BI SSI modes to work..?
I am able to communicate using non-advanced modes, but I am not able to communicate using advanced modes such as SSI_ADV_MODE_QUAD_READ, or SSI_ADV_MODE_QUAD_WRITE. Here are more specifics:
- Both TM4C's have their SSI0 connected to the other TM4C's SSI2, and SSI1 to SSI3. (Thus we can have two quad channels to read, and to quad channels to write).
- For my simplified code (shown below), I am trying to write to SSI0 on the first TM4C (Master) to the second TM4C (slave). the Second TM4C will read on SSI2.
- The write operations return normally, I can confirm using a logic analyzer that write operation seems to be working, as I can see the clock signal at 2MHz, as well as the data values being transferred.
- The read operations block, and never returns.
I am not sure why the read operation is failing.. I am wondering if I have to use a special mode (such as Freescale SPI Format)? Or if there is some other setting that is incorrectly set.?
/*
* Process_SSI.c
*
* This process is for sending and receiving SPI data
*
* We will setup the following
* SSI0 - Write, quad SPI
* SSI1 - Write, quad SPI
* SSI2 - Read, quad SPI
* SSI3 - Read, quad SPI
*
* Created on: Jul 1, 2019
*/
#include <stdint.h> // Standard integers
#include <stdio.h> // Standard integers
#include <stdbool.h> // Standard boolean
#include <driverlib/gpio.h>
#include <driverlib/ssi.h>
#include <driverlib/sysctl.h>
#include <SystemClock.h>
#include "Process_SPI.h"
#include "driverlib/pin_map.h" // Mapping of peripherals to pins for all parts
#include "driverlib/rom.h" // Macros to facilitate calling functions in the ROM
#include "inc/hw_memmap.h" // Base addresses
#include "inc/hw_gpio.h" // GPIO control register offsets
#include "msgqueue.h"
#define SPI_BIT_RATE 2000000
void Process_SPI_Init(uint32_t masterMode);
void Process_SPI_InitMaster()
{
Process_SPI_Init(SSI_MODE_MASTER);
}
void Process_SPI_InitSlave()
{
Process_SPI_Init(SSI_MODE_SLAVE);
}
/**
* mode = SSI_MODE_MASTER or SSI_MODE_SLAVE
*/
void Process_SPI_Init(uint32_t masterMode)
{
//
// The SSI0 peripheral must be enabled for use.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2);
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3);
//
// For this SSI0 is used with PortA[7:2]. GPIO port A needs to be enabled so these pins can be used.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);
//
// Configure the pin muxing for SSI0 functions
//
GPIOPinConfigure(GPIO_PA2_SSI0CLK);
GPIOPinConfigure(GPIO_PA3_SSI0FSS);
GPIOPinConfigure(GPIO_PA4_SSI0XDAT0);
GPIOPinConfigure(GPIO_PA5_SSI0XDAT1);
GPIOPinConfigure(GPIO_PA6_SSI0XDAT2);
GPIOPinConfigure(GPIO_PA7_SSI0XDAT3);
// Configure the pin muxing for SSI1 functions
GPIOPinConfigure(GPIO_PB5_SSI1CLK);
GPIOPinConfigure(GPIO_PB4_SSI1FSS);
GPIOPinConfigure(GPIO_PE4_SSI1XDAT0);
GPIOPinConfigure(GPIO_PF0_SSI3XDAT1);
GPIOPinConfigure(GPIO_PD4_SSI1XDAT2);
GPIOPinConfigure(GPIO_PD5_SSI1XDAT3);
// Configure the pin muxing for SSI2 functions
GPIOPinConfigure(GPIO_PD2_SSI2FSS);
GPIOPinConfigure(GPIO_PD3_SSI2CLK);
GPIOPinConfigure(GPIO_PD1_SSI2XDAT0);
GPIOPinConfigure(GPIO_PD0_SSI2XDAT1);
GPIOPinConfigure(GPIO_PD7_SSI2XDAT2);
GPIOPinConfigure(GPIO_PD6_SSI2XDAT3);
// Configure the pin muxing for SSI3 functions
GPIOPinConfigure(GPIO_PF2_SSI3FSS);
GPIOPinConfigure(GPIO_PF3_SSI3CLK);
GPIOPinConfigure(GPIO_PF1_SSI3XDAT0);
GPIOPinConfigure(GPIO_PF0_SSI3XDAT1);
GPIOPinConfigure(GPIO_PP0_SSI3XDAT2);
GPIOPinConfigure(GPIO_PP1_SSI3XDAT3);
//
// 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:
// PA7 - SSI0 Dat3
// PA6 - SSI0 Dat2
// PA5 - SSI0 Dat1
// PA4 - SSI0 Dat0
// PA3 - SSI0Fss
// PA2 - SSI0CLK
//
GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_7 | GPIO_PIN_6 |GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2);
GPIOPinTypeSSI(GPIO_PORTB_BASE, GPIO_PIN_4 | GPIO_PIN_5);
GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_7 | GPIO_PIN_6 |GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0);
GPIOPinTypeSSI(GPIO_PORTE_BASE, GPIO_PIN_5 | GPIO_PIN_4);
GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0);
GPIOPinTypeSSI(GPIO_PORTP_BASE, GPIO_PIN_1 | GPIO_PIN_0);
//
// 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.
SSIConfigSetExpClk(SSI0_BASE, System_Clock_GetFrequency(), SSI_FRF_MOTO_MODE_0, masterMode, SPI_BIT_RATE, 8);
SSIConfigSetExpClk(SSI1_BASE, System_Clock_GetFrequency(), SSI_FRF_MOTO_MODE_0, masterMode, SPI_BIT_RATE, 8);
SSIConfigSetExpClk(SSI2_BASE, System_Clock_GetFrequency(), SSI_FRF_MOTO_MODE_0, masterMode, SPI_BIT_RATE, 8);
SSIConfigSetExpClk(SSI3_BASE, System_Clock_GetFrequency(), SSI_FRF_MOTO_MODE_0, masterMode, SPI_BIT_RATE, 8);
// Configure the SSI module for advanced mode quad SPI -- when I turn this on, it doesn't work!!?
// SSIAdvModeSet(SSI0_BASE,SSI_ADV_MODE_QUAD_READ);
// SSIAdvModeSet(SSI1_BASE,SSI_ADV_MODE_QUAD_READ);
// SSIAdvModeSet(SSI2_BASE,SSI_ADV_MODE_QUAD_WRITE);
// SSIAdvModeSet(SSI3_BASE,SSI_ADV_MODE_QUAD_WRITE);
SSIClockSourceSet(SSI0_BASE, SSI_CLOCK_SYSTEM);
SSIClockSourceSet(SSI1_BASE, SSI_CLOCK_SYSTEM);
SSIClockSourceSet(SSI2_BASE, SSI_CLOCK_SYSTEM);
SSIClockSourceSet(SSI3_BASE, SSI_CLOCK_SYSTEM);
//
// Enable the SSI0 module.
//
SSIEnable(SSI0_BASE);
SSIEnable(SSI1_BASE);
SSIEnable(SSI2_BASE);
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.
//
uint8_t pui32DataRx[16];
while(SSIDataGetNonBlocking(SSI2_BASE, &pui32DataRx[0]))
{
}
while(SSIDataGetNonBlocking(SSI3_BASE, &pui32DataRx[0]))
{
}
}
uint32_t totalBytesRx;
Process_SPI_TestRead()
{
uint8_t pui32DataRx[16];
int bytesRead = 0;
int i;
for (i = 0; i < 16; i ++)
{
SSIDataGet(SSI2_BASE, &pui32DataRx[i]);
bytesRead++;
}
totalBytesRx+=bytesRead;
if (bytesRead > 0)
{
Msgqueue_LogQue(&msgQueue,MAIN_LOG,"SSI Read Some Bytes %d, %d\n", bytesRead, totalBytesRx);
}
}
uint32_t totalBytesTx;
Process_SPI_TestWrite()
{
uint8_t pui32DataTx[16];
uint32_t i = 0;
int bytesWritten = 0;
for (i = 0; i < 16; i ++)
{
pui32DataTx[i] = i+10;
SSIDataPut(SSI0_BASE, &pui32DataTx[i]);
bytesWritten++;
}
totalBytesTx += bytesWritten;
Msgqueue_LogQue(&msgQueue,MAIN_LOG,"Sent Bytes %d, %d\n", bytesWritten, totalBytesTx);
}