Hi all,
I'm an engineering student who has some experience programming arduinos. I've had a project involving an EK-TM4C123GXL thrown on me. My goal is to set up the EK-TM4C123GXL as an SPI slave and an Arduino Mega 2560 as an SPI master. I've read through the user manual and a lot of other E2E posts, but I'm having no luck sending anything from the Arduino to the EK-TM4C123GXL. I've attached my code I have for both the Arduino and the EK-TM4C123GXL below. If someone could point out what I'm doing wrong, I would appreciate it. Just from using print statements, it looks like the EK-TM4C123GXL code doesn't execute past initiating SSI2.
//***************************************************************************** // // project0.c - Example to demonstrate minimal TivaWare setup // // Copyright (c) 2012-2020 Texas Instruments Incorporated. All rights reserved. // Software License Agreement // // Texas Instruments (TI) is supplying this software for use solely and // exclusively on TI's microcontroller products. The software is owned by // TI and/or its suppliers, and is protected under applicable copyright // laws. You may not combine this software with "viral" open-source // software in order to form a larger program. // // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL // DAMAGES, FOR ANY REASON WHATSOEVER. // // This is part of revision 2.2.0.295 of the EK-TM4C123GXL Firmware Package. // //***************************************************************************** #include <stdbool.h> #include <stdint.h> #include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "driverlib/debug.h" #include "driverlib/gpio.h" #include "driverlib/interrupt.h" #include "driverlib/pin_map.h" #include "driverlib/pwm.h" #include "driverlib/rom.h" #include "driverlib/rom_map.h" #include "driverlib/hw_memmap.h" #include "driverlib/qei.h" #include "driverlib/sysctl.h" #include "driverlib/uart.h" #include "utils/uartstdio.h" #include "driverlib/fpu.h" #include "inc/hw_types.h" #include "inc/hw_memmap.h" // The error routine that is called if the driver library encounters an error. #include "inc/hw_types.h" // Defines common types and macros #include "inc/hw_gpio.h" // Defines Macros for GPIO hardware #include "inc/hw_qei.h" #include "driverlib/ssi.h" #include "driverlib/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 1 //***************************************************************************** // // Global variables used in interrupt handler and the main loop. // //***************************************************************************** volatile unsigned long g_ulSSI2RXTO = 0; unsigned long g_ulDataRx2[NUM_SSI_DATA]; //***************************************************************************** // // Interrupt handler for SSI2 peripheral in slave mode. It reads the interrupt // status and if the interrupt is fired by a RX time out interrupt it reads the // SSI2 RX FIFO and increments a counter to tell the main loop that RX timeout // interrupt was fired. // //***************************************************************************** void SSI2IntHandler(void) { unsigned long ulStatus, ulIndex; // // Read interrupt status. // ulStatus = SSIIntStatus(SSI2_BASE, 1); // // Check the reason for the interrupt. // if(ulStatus) { // // Interrupt is because of RX time out. So increment counter to tell // main loop that RX timeout interrupt occurred. // g_ulSSI2RXTO++; // // Read NUM_SSI_DATA bytes of data from SSI2 RX FIFO. // for(ulIndex = 0; ulIndex < NUM_SSI_DATA; ulIndex++) { SSIDataGet(SSI2_BASE, &g_ulDataRx2[ulIndex]); } } // // Clear interrupts. // SSIIntClear(SSI2_BASE, ulStatus); } //***************************************************************************** // // 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); // // 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); } //***************************************************************************** // // This function sets up SPI2 to be used as slave in freescale mode. // //***************************************************************************** void InitSPI2(void) { // // The SSI0 peripheral must be enabled for use. // SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2); // // For this example SSI2 is used with PortH[7:4]. GPIO port H needs to be // enabled so these pins can be used. // SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOH); // // Configure the pin muxing for SSI2 functions on port H4, H5, H6 and H7. // This step is not necessary if your part does not support pin muxing. // GPIOPinConfigure(GPIO_PB4_SSI2CLK); GPIOPinConfigure(GPIO_PB5_SSI2FSS); GPIOPinConfigure(GPIO_PB6_SSI2RX); GPIOPinConfigure(GPIO_PB7_SSI2TX); // // 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: // PH7 - SSI2Tx // PH6 - SSI2Rx // PH5 - SSI2Fss // PH4 - SSI2CLK // GPIOPinTypeSSI(GPIO_PORTH_BASE, GPIO_PIN_7 | GPIO_PIN_6 | GPIO_PIN_5 | GPIO_PIN_4); // // Configure and enable the SSI2 port for SPI slave mode. // SSIConfigSetExpClk(SSI2_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_2, SSI_MODE_SLAVE, 660000, 8); // // Enable the SSI2 module. // SSIEnable(SSI2_BASE); } //***************************************************************************** // // This example will send out 3 bytes of data from master, then waits for slave // RX timeout interrupt to fire (where these 3 bytes are read). Then the sent // and returned data are compared to give out appropriate status messages on // UART0. // //***************************************************************************** int main(void) { unsigned long ulDataTx0[NUM_SSI_DATA]; unsigned long ulDataRx0[NUM_SSI_DATA]; unsigned long ulindex; // // Set the clocking to run directly from the external crystal/oscillator. // SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); // // 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: 16-bit\n\n"); // // Init SPI2 as slave. // UARTprintf("290\n\n"); InitSPI2(); UARTprintf("292\n\n"); // // Enable RX timeout interrupt. // SSIIntEnable(SSI2_BASE, SSI_RXTO); // // 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(SSI2_BASE, &g_ulDataRx2[0])) { } // // Clear any pending interrupt // SSIIntClear(SSI2_BASE, SSI_RXTO); // // IntEnable(INT_SSI2); // // Wait for the SSI2 RXTO interrupt to fire and data read from RXFIFO. // while(g_ulSSI2RXTO == 0) { UARTprintf("\waiting...\n "); } // // Display indication that salve has receiving data. // UARTprintf("\nReceived:\n "); // // Display the 3 bytes of data that were read from RX FIFO. // for(ulindex = 0; ulindex < NUM_SSI_DATA; ulindex++) { UARTprintf("'%c' ", g_ulDataRx2[ulindex]); } if(g_ulSSI2RXTO > 1) { // // Tell the user that the test failed and the reason. // UARTprintf("\n\nError: %d interrupt(s) fired when expecting only one." "\n", g_ulSSI2RXTO); } else { // // Tell the user that the test passed. // UARTprintf("\n\nTest Passed.\n\n"); } while(1) { } }
For whatever reason, TI's website will not let me place another code object, so for the arduino:
#include<SPI.h>
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
SPI.begin();
//SPI.setClockDivider(SPI_CLOCK_DIV8);
digitalWrite(SS,HIGH);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.println("Sending over SPI");
byte master_send, master_receive;
digitalWrite(SS, LOW);
master_send = 1;
master_receive = SPI.transfer(master_send);
if(master_receive == 1) //Logic for setting the LED output depending upon value received from slave
{
Serial.println("SPI working");
}
delay(1000);
}