This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Help with SPI protocol on TIVA C Series

Other Parts Discussed in Thread: TM4C123GH6PM

EDIT: My apologies. I haven't copy-pasted the code properly, so this may be causing some confusion. It was very late at night when I originally posted this thread, so I will post it again in a short time.


Hey there. I am trying to get a basic SPI protocol going. My end goal is to make my device a slave device that sends information to an mBed master on request. However, I am experimenting with the SPI settings and I am struggling to get anything working, at all.

I first tried to get my to receive data from the mBed master (who someone else is in charge of) but it didn't work, so I changed my immediate objective to try and get at least something, anything, working. So I took it away and configured it as a master device so that it would output its own clock signal and so that it would continuously output data. I even configured the clock polarity such that at idle the clock pin should just output high, but it didn't even do that. I just get nothing on any pin and I am really stumped as to why this is. The code did however successfully run without any fault handlers or anything like that. I have always been under the impression that all you have to do after the initialisation is write to the SSI data register in order for it to transmit. Then wait for it to become empty by checking the flag, then transmitting again.

I was hoping one of you could read my code and help me find out what is wrong with it. I will be working on this all day tomorrow as well. I should also add that the PLL has been set so the system clock is at 80 MHz. If I am leavign out any vital information please don't hesitate to tell me.

I am using Keil uVision5. I am using the TIVA C Series development board with  TM4C123GH6PM.


#define GPIO_PORTA_DATA_R (*((volatile unsigned long *)0x400043FC))
#define GPIO_PORTA_DIR_R (*((volatile unsigned long *)0x40004400))
#define GPIO_PORTA_AFSEL_R (*((volatile unsigned long *)0x40004420))
#define GPIO_PORTA_PUR_R (*((volatile unsigned long *)0x40004510))
#define GPIO_PORTA_DEN_R (*((volatile unsigned long *)0x4000451C))
#define GPIO_PORTA_CR_R (*((volatile unsigned long *)0x40004524))
#define GPIO_PORTA_AMSEL_R (*((volatile unsigned long *)0x40004528))
#define GPIO_PORTA_PCTL_R (*((volatile unsigned long *)0x4000452C))

#define GPIO_PORTF_DATA_R (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_AFSEL_R (*((volatile unsigned long *)0x40025420))
#define GPIO_PORTF_PUR_R (*((volatile unsigned long *)0x40025510))
#define GPIO_PORTF_DEN_R (*((volatile unsigned long *)0x4002551C))
#define GPIO_PORTF_CR_R (*((volatile unsigned long *)0x40025524))
#define GPIO_PORTF_AMSEL_R (*((volatile unsigned long *)0x40025528))
#define GPIO_PORTF_PCTL_R (*((volatile unsigned long *)0x4002552C))
#define GPIO_PORTF_LOCK_R (*((volatile unsigned long *)0x40025520))

#define SYSCTL_RCGC2_R (*((volatile unsigned long *)0x400FE108))
#define SYSCTL_RCGC1_R (*((volatile unsigned long *)0x400FE104))
#define SYSCTL_RCGC0_R (*((volatile unsigned long *)0x400FE100))

#define SSI_CR0_R (*((volatile unsigned long *)0x40008000))
#define SSI_CR1_R (*((volatile unsigned long *)0x40008004))
#define SSI_CC_R (*((volatile unsigned long *)0x40008FC8))
#define SSI_CPSR_R (*((volatile unsigned long *)0x40008010))
#define SSI_DATA_R (*((volatile unsigned long *)0x40008008))
#define SSI_SR_R (*((volatile unsigned long *)0x4000800C))

unsigned long RxData = 0;
unsigned long TxData = 0;

int main(void)
{
PLL_Init();
SysTick_Init();

SYSCTL_RCGC2_R |= 0x00000020;//Enable and provide clock for port F
delay = SYSCTL_RCGC2_R; //wait for clock to stabilise
GPIO_PORTF_LOCK_R = 0x4C4F434B; //unlock port F
GPIO_PORTF_CR_R = 0x1F; // allow changes to port F
GPIO_PORTF_AMSEL_R = 0x00; //No analogue 
GPIO_PORTF_PCTL_R = 0x00000000; //No alternative function select
GPIO_PORTF_DIR_R = 0x0E; //configure pins 1, 2 and 3 as output (for LED on board)
GPIO_PORTF_AFSEL_R = 0x00;//No alternative function enabled
GPIO_PORTF_DEN_R = 0x1F; //Digital I/O Enabled
GPIO_PORTF_DATA_R = 0x00;//initial clear data register

//CONFIGURE GPIO PINS
SYSCTL_RCGC1_R |= 0x00000010; //1. EN and provide clock to SSI module 0
SYSCTL_RCGC2_R |= 0x00000001; //2. EN and provide clock to GPIO module on portA
// SSIOClk is PA2, SSIOFss is PA3, SSIORx is PA4 and SSIOTx is PA5
GPIO_PORTA_AFSEL_R |= 0x3C; //3. EN alternative functions on PA 2-5
GPIO_PORTA_PCTL_R |= 0x00222200;//4. Configure PMCn fieldsin the PCTL register to assign SSi signals to pins

//CONFIGURE SSI MODULE
SSI_CR1_R &= ~(1<<1);//1. Disable SSI module by clearing SSE bit in SSICR1
SSI_CR1_R = 0x00000000;//2. Select master mode
SSI_CC_R = 0x00;//3. Configure SSI clock source as system clock
SSI_CPSR_R = 0x0A;//4. Configure clock prescale divisor
//BIT RATE = SysClk / (CPSDVSR * (1+SCR))
//1*10^6 = 80*10^6 / (CPSDVSR * (1+SCR))
//Therefore CPSDVSR * (1+SCR) = 80. I chose CPSDVSR=10=0xA and SCR=7=0x7 to make 10 * (1+7) = 80
//5.Write the SSICR0 register witht he following:
SSI_CR0_R = (0x7<<8);//- Serial clock rate (SCR)
SSI_CR0_R &= ~(0x3<<6);//- Desired clock phase/polarity, if using Freescale SPI mode (SPH and SPO)
SSI_CR0_R &= ~(0x3<<4);//- The protocol mode i.e: Freescae SPI, TISSF, MICROWIRE (FRF) [SPI]
SSI_CR0_R |= 0x0007;//- The data size [8 bits]
SSI_CR0_R |= (0x01<<6);
SSI_CR1_R |= (1<<1); //6. EN SSI module by setting SSE bit in SSICR1

while(1)
{
SSI_DATA_R = 0x3E; //write data to Data register for it to be outputted to FIFO
while((SSI_SR_R&(1<<0))==0){}//wait for FIFO to become empty
GPIO_PORTF_DATA_R=0x02; //Turn on LED as a quick visual verification that code is running

}

}

  • Why are you not using the TivaWare API?
  • I wasn't aware of the TivaWare API until now. Is it vital for getting SPI to work? Having discovered this I still prefer not to use it because this is for a project for university and I want to maximize my 'technical content' and I think the best way to do this is to do all the low-level register manipulation without using any functions that I haven't written myself. The trouble is that I am hardly an expert, as I am sure you can tell from this question. :P I was under the impression that following the initialization instruction in the datasheet on p.961 and reading from and writing to the SSI data register was enough to get something working and that the clock and slave select pins would 'take care' of themselves.
  • No, it is not vital - it's just a wrapper to the necessary register calls.

    If you want to (or your professor wants you to) reinvent the wheel, then who am I to say no. Just don't expect much help from here if you decide to do so - the TivaWare API exists exactly to ease the hurdles of getting all the registers right. You can always check the source code for the TivaWare functions and see if you have missed something.

    But my very frank opinion: you would be stupid not to use the API just because you want more "technical content" in your work, and if I were to grade your work I'd deduct points for not using a proven framework when there's no technical reason not to.

  • Ok. Thank you very much for your reply and help. I will use the Tivaware API.