Hi, I'm using a pair of TM4C123G evaluation boards trying to get an SSI channel to work. These boards have TM4C123GH6PM microcontrollers. I'm using a recent version of Code Composer Studio and TivaWare 2.2.0.295.
Between the boards we have SSI1 clock connected, and SSI1 RX/TX crosswired - RX on board 1 connects to TX on board 2 and vice versa. I have two CCS projects, a SPI master and a SPI slave. I'm simply trying to transmit "1234" from master to slave twice a second. We've looked at the lines on a scope, we see a 1 MHz clock and 2 Hz data. From that it seems the master side is working as expected. This issue I have is on the slave. After setup I'm in a loop trying to read data, and the first call to SSIDataGet never returns. Code for both sides below. What am I doing wrong ?!
// SPI master #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" ///////////////////////////////////////////////////////////////////////////// void InitializeSystem() { // Set the clocking to run directly from the crystal. SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); // Initialize UART1 to 115200 baud, N-8-1 // UART1 : GPIO Port B : UART1RX = PB0 : UART1TX = PB1 SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); GPIOPinConfigure(GPIO_PB0_U1RX); GPIOPinConfigure(GPIO_PB1_U1TX); 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); } ///////////////////////////////////////////////////////////////////////////// void InitializeSSI1() { // Enable the SSI1 peripheral for use. SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1); // We have PD0 (SSI1 Clk), PD2 (SSI1 Rx), and PD3 (SSI1 Tx) connected. // (Odd thing, pins/ports for SSI1 are the same as SSI3 ?!) SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); // Configure the pin muxing for SSI functions GPIOPinConfigure(GPIO_PD0_SSI1CLK); GPIOPinConfigure(GPIO_PD1_SSI1FSS); GPIOPinConfigure(GPIO_PD2_SSI1RX); GPIOPinConfigure(GPIO_PD3_SSI1TX); // Configure the GPIO settings for the SSI pins. This function also gives // control of these pins to the SSI hardware. GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3); // Configure and enable the SSI port for SPI master mode. SSIDisable(SSI1_BASE); SSIConfigSetExpClk(SSI1_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 1000000, 8); // Advance mode settings. Legacy is default. I've seen several mentions // in technical forum discussions that when writing as SSI master, you // need "dummy" reads (in legacy mode)? //SSIAdvModeSet(SSI1_BASE, SSI_ADV_MODE_WRITE); // Enable the SSI module. SSIEnable(SSI1_BASE); // Read residual data from the SSI port so we don't read any junk. uint32_t RxData; while (SSIDataGetNonBlocking(SSI1_BASE, &RxData)) { } } ///////////////////////////////////////////////////////////////////////////// int main(void) { InitializeSystem(); InitializeSSI1(); // A call to SysCtlDelay with a delay count of 1 takes 3 clock cycles unsigned int nDelayOneMillisecond = (SysCtlClockGet() / 3) / 1000; const unsigned int nDelayCount = 500 /* milliseconds */ * nDelayOneMillisecond; const unsigned int Message[4] = { '1', '2', '3', '4' }; uint32_t RxData = 0; while (true) { // Transmit on SPI and UART every <n> milliseconds. SysCtlDelay(nDelayCount); for (unsigned int nByte = 0 ; nByte < 4 ; nByte++) { while (SSIDataGetNonBlocking(SSI1_BASE, &RxData)) {} SSIDataPut(SSI1_BASE, Message[nByte]); // SSIDataGetNonBlocking(SSI1_BASE, &RxData); UARTCharPut(UART1_BASE, (unsigned char)Message[nByte]); } } }
// SPI slave #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" ///////////////////////////////////////////////////////////////////////////// void InitializeSystem() { // Set the clocking to run directly from the crystal. SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); // Initialize UART1 to 115200 baud, N-8-1 // UART1 : GPIO Port B : UART1RX = PB0 : UART1TX = PB1 SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); GPIOPinConfigure(GPIO_PB0_U1RX); GPIOPinConfigure(GPIO_PB1_U1TX); 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); } ///////////////////////////////////////////////////////////////////////////// void InitializeSSI1() { // Enable the SSI1 peripheral for use. SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1); // We have PD0 (SSI1 Clk), PD2 (SSI1 Rx), and PD3 (SSI1 Tx) connected. // (Odd thing, pins/ports for SSI1 are the same as SSI3 ?!) SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); // Configure the pin muxing for SSI functions GPIOPinConfigure(GPIO_PD0_SSI1CLK); GPIOPinConfigure(GPIO_PD1_SSI1FSS); GPIOPinConfigure(GPIO_PD2_SSI1RX); GPIOPinConfigure(GPIO_PD3_SSI1TX); // Configure the GPIO settings for the SSI pins. This function also gives // control of these pins to the SSI hardware. GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3); // Configure and enable the SSI port for SPI slave mode. SSIDisable(SSI1_BASE); SSIConfigSetExpClk(SSI1_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_SLAVE, 1000000, 8); //SSIConfigSetExpClk(SSI1_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_SLAVE_OD, 1000000, 8); // Advance mode settings. Legacy is default. //SSIAdvModeSet(SSI1_BASE, SSI_ADV_MODE_LEGACY); // Enable the SSI module. SSIEnable(SSI1_BASE); // Read residual data from the SSI port so we don't read any junk. uint32_t RxData; while (SSIDataGetNonBlocking(SSI1_BASE, &RxData)) { } } ///////////////////////////////////////////////////////////////////////////// int main(void) { // Initialize the system InitializeSystem(); InitializeSSI1(); unsigned int nByte = 0; while (true) { // Get next charater on SPI and forward to UART SSIDataPut(SSI1_BASE, 0); // dummy write? SSIDataGet(SSI1_BASE, &nByte); UARTCharPut(UART1_BASE, (unsigned char)nByte); } }