Other Parts Discussed in Thread: EK-TM4C1294XL
Hi all,
I'm trying to set up SPI communication between an Arduino Mega 2560 and a TI microcontroller. I am trying to set up the Arduino Mega 2560 as master and the TI controller as the slave. I want the master to continously send 2 bytes in a single SPI transmission over and over again from the Arduino to the TI microcontroller.
Between the two boards, I have the following connections:
Arduino Mega 2560 EK-TM4C123GXL
PIN 50 => PA5
PIN 51 => PA4
PIN 52 => PA2
PIN 53 => PA3
It appears that the interrupt for SPI is called one time, and then does not get called again. It correctly transfers the first byte sent, but this first byte appears in both the 0 and 1 index of the storage array.
It does not appear that the interrupt gets called more than once. What's preventing the Arduino from correctly repeatedly transferring two bytes to the EK-TM4C123GXL?
Code for Arduino:
#include<SPI.h> byte direction_byte = 0b00001110; byte speed_byte = 0b01010101; //SPISettings ti_settings(SPI_CLOCK_DIV4,MSBFIRST,SPI_MODE2); bool flip = 0; void setup (void) { digitalWrite(SS, HIGH); // ensure SS stays high for now SPI.setDataMode(SPI_MODE2); // Put SCK, MOSI, SS pins into output mode // also put SCK, MOSI into LOW state, and SS into HIGH state. // Then put SPI hardware into Master mode and turn SPI on SPI.begin (); // Slow down the master a bit SPI.setClockDivider(SPI_CLOCK_DIV8); SPI.setDataMode(SPI_MODE2); } // end of setup void loop (void) { // enable Slave Select digitalWrite(SS, LOW); // SS is pin 10 // send test string SPI.transfer(direction_byte); SPI.transfer(speed_byte); // disable Slave Select digitalWrite(SS, HIGH); delay (1000); // 1 seconds delay } // end of loop
Code for EK-TM4C123GXL:
//***************************************************************************** // // 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 "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 "inc/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 "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 2 //***************************************************************************** // // Global variables used in interrupt handler and the main loop. // //***************************************************************************** //volatile unsigned long g_ulSSI2RXTO = 0; //unsigned long g_ulDataRx2[NUM_SSI_DATA]; volatile uint32_t g_ulSSI2RXTO = 0; volatile uint32_t 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 SSI0IntHandler(void) { unsigned long ulStatus, ulIndex; // // Read interrupt status. // ulStatus = SSIIntStatus(SSI0_BASE, 1); // // 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_ulSSI2RXTO++; // // Read NUM_SSI_DATA bytes of data from SSI2 RX FIFO. // for(ulIndex = 0; ulIndex < NUM_SSI_DATA; ulIndex++) { SSIDataGet(SSI0_BASE, &g_ulDataRx2[ulIndex]); } g_ulSSI2RXTO--; } // // 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. // //***************************************************************************** //***************************************************************************** // // 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); while (!SysCtlPeripheralReady(SYSCTL_PERIPH_SSI0)) { } // // 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_GPIOA); while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA)) { } // // 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_PA2_SSI0CLK); GPIOPinConfigure(GPIO_PA3_SSI0FSS); GPIOPinConfigure(GPIO_PA4_SSI0RX); GPIOPinConfigure(GPIO_PA5_SSI0TX); GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2); SSIDisable(SSI0_BASE); // // Configure and enable the SSI0 port for SPI master mode. // SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_2, SSI_MODE_SLAVE, 660000, 8); SSIDisable(SSI0_BASE); // // Enable the SSI2 module. // SSIEnable(SSI0_BASE); IntEnable(INT_SSI0); SSIIntEnable(SSI0_BASE, SSI_RXTO); SSIIntRegister(SSI0_BASE, SSI0IntHandler); } //***************************************************************************** // // This function sets up SPI2 to be used as slave in freescale mode. // //***************************************************************************** //************************************************************************* int main(void) { /* unsigned long ulDataTx0[NUM_SSI_DATA]; unsigned long ulDataRx0[NUM_SSI_DATA]; unsigned long ulindex; */ uint32_t ulDataTx0[NUM_SSI_DATA]; uint32_t ulDataRx0[NUM_SSI_DATA]; uint32_t 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); // // Init SPI0 as master. // InitSPI0(); // // 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. This might not be needed here. // while(SSIDataGetNonBlocking(SSI0_BASE, &ulDataRx0[0])) { } // // Clear any pending interrupt // SSIIntClear(SSI0_BASE, SSI_RXTO); while(1) { } }