Hello,
I am a student working on a senior design project utilizing the Tiva tm4c123gh6pm arm processor and am struggling to get the SPI slave interface to work correctly.
So far I have used an example from this form post, https://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/302734?SPI-Slave-problem
and modified it to use SSI0 instead of SSI2. When testing the code I cannot read more than one byte from the master, a raspberry pi, before the Tiva hangs in an infinite loop in the function SSIDataGet() shown below waiting for data. The master has the clock set to 122kHz.
void SSIDataGet(uint32_t ui32Base, uint32_t *pui32Data) { // // Check the arguments. // ASSERT(_SSIBaseValid(ui32Base)); // // Wait until there is data to be read. // while(!(HWREG(ui32Base + SSI_O_SR) & SSI_SR_RNE)) // hangs here forever { } // // Read data from SSI. // *pui32Data = HWREG(ui32Base + SSI_O_DR); }
The oscilloscope output shows the data as being sent correctly but it seems it is not being processed by the Tiva and I am unsure as how to fix this.
Channel 1 is clk, 2 is MOSI, 3 is MISO, 4 is CS.
Any advice would be greatly appreciated, here is my full code below.
//***************************************************************************** // // spi_slave.c - Example demonstrating how to configure RX timeout interrupt in // SPI slave mode. // // Copyright (c) 2013 Texas Instruments Incorporated. All rights reserved. // TI Information - Selective Disclosure // //***************************************************************************** #include <stdbool.h> #include <stdint.h> #include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "inc/hw_ssi.h" #include "inc/hw_types.h" #include "driverlib/ssi.h" #include "driverlib/gpio.h" #include "driverlib/interrupt.h" #include "driverlib/sysctl.h" #include "driverlib/pin_map.h" #include "driverlib/uart.h" #include "utils/uartstdio.h" //***************************************************************************** // //! \addtogroup ssi_examples_list //! <h1>SPI Slave (spi_slave)</h1> //! //! This example configures the SSI0 as SPI Master, SSI2 as SPI Slave on an //! EK-LM4F232 evaluation board. RX timeout interrupt is configured for SSI2. //! Three characters are sent on the master TX, then SSI2 RX timeout interrupt //! is enabled. The code then waits for the interrupt to fire. Once the //! interrupt is fired the data from slave RX FIFO is read and compared to the //! transmitted packet and the appropriate status is displayed. If everything //! goes well you should see a "Test Passed." message on the terminal window. //! The status messages are transmitted over UART0 at 115200 baud and 8-n-1 //! mode. //! //! This example uses the following peripherals and I/O signals on EK-LM4F232. //! You must review these and change as needed for your own board: //! - SSI0 peripheral //! - GPIO Port A peripheral (for SSI0 pins) (available near the SD card slot) //! - SSI0CLK - PA2 //! - SSI0Fss - PA3 //! - SSI0Rx - PA4 //! - SSI0Tx - PA5 //! //! - SSI2 peripheral //! - GPIO Port M peripheral (for SSI2 pins) (available right below the OLED) //! - SSI2CLK - PH4 //! - SSI2Fss - PH5 //! - SSI2Rx - PH6 //! - SSI2Tx - PH7 //! //! For this example to work, the following connections are needed on the //! EK-LM4F232 evaluation board. //! - SSI0CLK(PA2) - SSI2CLK(PH4) //! - SSI0Fss(PA3) - SSI0Fss(PH5) //! - SSI0Rx(PA4) - SSI2Tx(PH7) //! - SSI0Tx(PA5) - SSI2Rx(PH6) //! //! 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. //! - SSI2IntHandler. //! // //***************************************************************************** //***************************************************************************** // // Number of bytes to send and receive. // //***************************************************************************** #define NUM_SSI_DATA 7 //***************************************************************************** // // Global variables used in interrupt handler and the main loop. // //***************************************************************************** volatile unsigned long g_ulSSI0RXTO = 0; unsigned long g_ulDataRx0[NUM_SSI_DATA] = {0}; //***************************************************************************** // // Interrupt handler for SSI0 peripheral in slave mode. It reads the interrupt // status and if the interrupt is fired by a RX time out interrupt it reads the // SSI0 RX FIFO and increments a counter to tell the main loop that RX timeout // interrupt was fired. // //***************************************************************************** void SSI0IntHandler(void) { unsigned long ulStatus = 0, ulIndex = 0; // // Read interrupt status. // ulStatus = SSIIntStatus(SSI0_BASE, 0); // // Check the reason for the interrupt. // if(ulStatus & SSI_RXTO) { // // Interrupt is because of RX time out. So increment counter to tell // main loop that RX timeout interrupt occurred. // g_ulSSI0RXTO++; // // Read NUM_SSI_DATA bytes of data from SSI2 RX FIFO. // for(int ulIndex = 0; ulIndex < NUM_SSI_DATA; ulIndex++){ SSIDataGet(SSI0_BASE, &g_ulDataRx0[ulIndex]); } } // // Clear interrupts. // SSIIntClear(SSI0_BASE, ulStatus); } //***************************************************************************** // // This function sets up SPI0 to be used as Master in freescale mode. // //***************************************************************************** void InitSPI0(void) { // // The SSI0 peripheral must be enabled for use. // SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0); // // For this example SSI0 is used with PortA[5:2]. GPIO port A needs to be // enabled so these pins can be used. // 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. // 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 // GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2); // // Configure and enable the SSI0 port for SPI slave mode. // SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_SLAVE, 122000, 8); // // Enable the SSI0 module. // SSIEnable(SSI0_BASE); } int main(void) { SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); InitSPI0(); SSIDataPut(SSI0_BASE, 0xED); // rx interrupt SSIIntEnable(SSI0_BASE, SSI_RXTO); IntEnable(INT_SSI0); while(1); // debug halt here and check buffer }