Good day,
I am configuring a Tiva Launchpad EK-TM4C123GXL with a Tiva series TM4C123GH6PM with CCSv6. I am programming it to aggregate some analog sensor data, and send it via SPI slave mode to another TI MCU, which is the master. Also, I need to implement some software addressing, because there is another SPI slave on the bus and I can't get a separate chip select.
But my immediate issue is the ISR that is configured to be called when the SSI RX FIFO is half full or more. The master is sending out 4 8-bit frames in a row. Since the FIFO is 8 elements deep, every time I get a poll (4 8-bit frames) from the master, it should trip the ISR. In the ISR, I loop through and get all the elements from the FIFO. And before, in the main loop, I have the slave output data already in the TX FIFO. Why is the interrupt only being called every 4 times I poll the slave with the master? Also, the first byte out of 4 is ending up in every element of the recieveData array. The last 3 bytes from the transmit aren't making it through. I have the 4 SPI lines on a scope, and can see the interrupt because I have a GPIO pin toggled high while in the ISR. The master data is correct on the scope. The frame format matches the master, CLK =0 and CPHA = 0.
I attached the main.c file, thanks if you can help explain this.
And right now the data is arbitrary for testing, but soon I am going try and detect the address in the first byte, and if it matches mine, I'll respond, otherwise not. Also, I plan on using:
SSI0_CR1_R &= ~SSI_CR1_SOD //disable the slave output disable //transmit and other ISR code SSI0_CR1_R |= SSI_CR1_SOD; //enable the slave output disable
Is this a valid plan of attack? I can't have the slave driving the output line when another slave is transmitting.
/* * main.c */ #include <stdint.h> #include <stdbool.h> #include "driverlib/sysctl.h" //#include "inc/tm4c123gh6pm.h" #include "driverlib/gpio.h" #include "driverlib/pin_map.h" #include "inc/hw_memmap.h" #include "driverlib/ssi.h" #include "driverlib/adc.h" #include "driverlib/interrupt.h" #include "driverlib/pin_map.h" #include "driverlib/uart.h" #include "inc/hw_ints.h" #include "utils/uartstdio.h" #include "driverlib/systick.h" #define SSI0_CR1_R (*((volatile uint32_t *)0x40008004)) #define SSI_CR1_SOD 0x00000008 #define NVIC_ST_CURRENT_R (*((volatile uint32_t *)0xE000E018)) #define NVIC_ST_CTRL_R (*((volatile unsigned long *)0xE000E010)) #define dataLength 4 uint32_t returnData[dataLength] = {0}; uint32_t receiveData[dataLength] = {0}; uint32_t dataSent = 1; //returns current system frequency which may not match requested frequency void Clock_Init(){ uint32_t ui32Config; //provides divisor of one the fixed PLL VCO settings //PLL is 400MHz: (400MHz/2)/4 = 50MHz ui32Config = (SYSCTL_SYSDIV_4 | SYSCTL_XTAL_16MHZ | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN); SysCtlClockSet(ui32Config); } void SysTick_Init(){ //15e6/50e6 = 300ms period SysTickDisable(); SysTickPeriodSet(15000000); SysTickEnable(); NVIC_ST_CURRENT_R = 0; } //configure GPIO to use SSI0 on Port A, SSI1 on Port D //and AIN0 from slide pot on pin PE3 //Nokia5110 DC void GPIO_Init(){ //SSI0 is for slave, SSI1 is for LCD SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); //for slave SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); //for LCD SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); //for ADC channels SysCtlDelay(100); SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0); SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1); SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); SysCtlDelay(3); GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); //PA2-5: GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5); //PD0-3: GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3); /* * x axis: PE0 AIN3 * z axis: PE1 AIN2 * offloader force: PE2 AIN1 * temperature: PE3 AIN0 */ GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3); GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_7);//for Data/Command to LCD GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_6); //for reset to LCD GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_6); //for SSI0 ISR signaling GPIOPinConfigure(GPIO_PA0_U0RX); GPIOPinConfigure(GPIO_PA1_U0TX); GPIOPinConfigure(GPIO_PA2_SSI0CLK); GPIOPinConfigure(GPIO_PA3_SSI0FSS); GPIOPinConfigure(GPIO_PA4_SSI0RX); GPIOPinConfigure(GPIO_PA5_SSI0TX); GPIOPinConfigure(GPIO_PD0_SSI1CLK); GPIOPinConfigure(GPIO_PD1_SSI1FSS); GPIOPinConfigure(GPIO_PD2_SSI1RX);//not used because LCD doesn't transmit back GPIOPinConfigure(GPIO_PD3_SSI1TX); } void UART_Init(){ UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC); UARTStdioConfig(0, 9600, 16000000); } void SSI0_Handler() { GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_6, GPIO_PIN_6); //SSI0_CR1_R &= ~SSI_CR1_SOD; //0 in slave output disable bit in order to drive line SSIIntClear(SSI0_BASE, SSI_RXFF); //UARTprintf(""); int i = 0; for(i = 0; i < dataLength; i++){ //wait until a value is in the RX FIFO if there isn't one. SSIDataGet(SSI0_BASE, &receiveData[i]); } for(i = 0; i < dataLength; i++){ UARTprintf("receiveData[%1d] = %08x\n", i, receiveData[i]); } dataSent = 1; UARTprintf("\n"); //disable slave output //SSI0_CR1_R |= SSI_CR1_SOD; GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_6, 0x00); } //configure and enable the SSI peripheral. Slave mode requires CLK < 12 x system clock (master uC runs SPI at 1.17MHz) //Using the same polarity and phase as F28M335x: Polarity 0, Phase 1 // means clock idle state is zero, sample takes place on 2nd clock edge void SSI_Init(){ SSIClockSourceSet(SSI1_BASE, SSI_CLOCK_SYSTEM); //Nokia5110 max f_sclk(ext) is 4.0MHz SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_SLAVE, 3330000, 8); //Nokia5110 samples SDIN at positive edge of clock: phase bit should be 1, set idle clock high SSIConfigSetExpClk(SSI1_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 3330000, 8); SSIIntEnable(SSI0_BASE, SSI_RXFF); //SSI0_Handler() will be called when RXFF is half full or more //For SLAVE SSIEnable(SSI0_BASE); //For Nokia5110 SSIEnable(SSI1_BASE); } //Configure Interrupts void NVIC_Init(){ IntEnable(INT_SSI0_TM4C123); IntPrioritySet(INT_SSI0_TM4C123, 0); IntMasterEnable(); } void SysTick_Wait3sec(){ int i; for (i = 0; i < 10; i++){ while((NVIC_ST_CTRL_R & 0x00010000)==0){ } } } int main(void) { Clock_Init(); GPIO_Init(); UART_Init(); SSI_Init(); SysTick_Init(); int i; for (i = 0; i < 4; i++){ returnData[i]=i; } NVIC_Init(); while(1){ //get data ready for master initiation //only put data in return FIFO if the last packet was sent if (dataSent){ UARTprintf("loading return data\n"); for (i = 0; i < dataLength; i++){ SSIDataPut(SSI0_BASE, returnData[i]); UARTprintf("returnData[%d]: %08x\n", i, returnData[i]); } dataSent = 0; } //clear recieveData for (i = 0; i < dataLength; i++){ receiveData[i] = 0; } UARTprintf("Main loop\n"); SysTick_Wait3sec(); } return 0; }