I'm working on a piece of code that performs hardware-level SPI back and forth with an ADC. After numerous attempts, I set the interrupt-driven code aside and wrote a software-level bit bang and tested that it does work. I'd really like to get the built-in SPI mechanism working though. Once that's done, I'll rewrite it to work in SYS/BIOS.
The problem I'm experiencing is, while I don't even know if the first transfer is getting through, the hardware IRQ keeps triggering, and I'm struggling to understand why.
Here is the main.c file. It's a derivation of the Example_2833xSpi_FFDLB_int from the TI Control Suite. However, I've hacked it to pieces since and rearranged things to an near unrecognizable state.
#include "DSP28x_Project.h" // Device Headerfile and Examples Include File
#include "BitBangSPI.h"
#include "HardwareSPI.h"
#include "PSU.h"
Uint16 sdata[7]; // Send data buffer
Uint16 rdata[7][2]; // Receive data buffer
void main(void)
{
Uint16 i;
InitSysCtrl();
SetupPSU();
DINT;
IER = 0x0000;
IFR = 0x0000;
InitPieCtrl();
InitPieVectTable();
spiSetup();
//Setup data to be sent
for(i=0;i<7;i++){
sdata[i]=
(1<<7)|
((i & 0x0007)<<4)|
((0 & 0x0001)<<3)|
((1 & 0x0001)<<2)|
((3 & 0x0003));
}
//Clear data reception buffer
for(i=0;i<7;i++){
rdata[i][0]=0;
rdata[i][1]=0;
}
//Loop and send forever
i=0;
for(;;){
if(i>=7){i=0;}
spiSendAndReceive(sdata+i,1,rdata[i],2,8);
i++;
}
}
Here is my HardwareSPI.c library. There are a few missing functions, but I promise they're just GPIO inits. The two functions called from main.c are spiSetup and spiSendAndReceive.
#include "HardwareSPI.h"
#ifndef USE_SOFTWARE_SPI
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
static Uint16 spiDataIndex=0;
static Uint16 spiDataSize=0;
static Uint16 *spiTXBuffer;
static Uint16 *spiRXBuffer;
static Uint16 spiSemRXFF;
static Uint16 spiSemTXFF;
static void spiHoldInReset();
static void spiRegisterISR();
static void spiFIFOInit();
static void spiReleaseFromReset();
static void spiEnableInterrupts();
void spiSetup(){
spiHoldInReset();
spiInitGPIOPins();
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
spiRegisterISR();
// Initialize all the Device Peripherals:
// This function is found in DSP2833x_InitPeripherals.c
// InitPeripherals(); // Not required for this example
spiFIFOInit(); // Initialize the SPI only
spiReleaseFromReset();
spiEnableInterrupts();
}
static void spiHoldInReset(){
EALLOW;
PieCtrlRegs.PIEIFR6.bit.INTx1=0; //Disable FIFO Interrupt flags
PieCtrlRegs.PIEIFR6.bit.INTx2=0; //Disable FIFO Interrupt flags
SpiaRegs.SPIFFTX.bit.SPIRST=0; // Hold both FIFOs in reset
SpiaRegs.SPIFFTX.bit.TXFIFO=0; // Hold TX FIFO in reset
SpiaRegs.SPIFFRX.bit.RXFIFORESET=0; // Hold RX FIFO in reset
SpiaRegs.SPICCR.bit.SPISWRESET=0; // Software Reset SPI
SpiaRegs.SPIFFTX.bit.TXFFINTCLR=1; //Clear TX FIFO
SpiaRegs.SPIFFRX.bit.RXFFINTCLR=1; //Clear RX FIFO
EDIS;
}
void spiInitGPIOPins(){
spiCommonInitGPIOPinsStart();
/* Configure SPI-A pins using GPIO regs*/
// This specifies which of the possible GPIO pins will be SPI functional pins.
GpioCtrlRegs.GPBMUX2.bit.GPIO54 = 1; // Configure GPIO54 as SPISIMOA
GpioCtrlRegs.GPBMUX2.bit.GPIO55 = 1; // Configure GPIO55 as SPISOMIA
GpioCtrlRegs.GPBMUX2.bit.GPIO56 = 1; // Configure GPIO56 as SPICLKA
spiCommonInitGPIOPinsEnd();
}
static void spiRegisterISR(){
EALLOW; // This is needed to write to EALLOW protected registers
PieVectTable.SPIRXINTA = &spiRxFifoIsr;
PieVectTable.SPITXINTA = &spiTxFifoIsr;
EDIS; // This is needed to disable write to EALLOW protected registers
}
static void spiFIFOInit()
{
EALLOW;
// Initialize SPI FIFO registers
SpiaRegs.SPIFFCT.bit.TXDLY=0;
SpiaRegs.SPICCR.bit.CLKPOLARITY=0;
SpiaRegs.SPICCR.bit.SPILBK=0;
SpiaRegs.SPICCR.bit.SPICHAR=7; //Bit width of characters
SpiaRegs.SPICTL.bit.OVERRUNINTENA=1;//Enable Overrun Interrupt
SpiaRegs.SPICTL.bit.CLK_PHASE=1; //Delay by 1/2 cycle
SpiaRegs.SPICTL.bit.MASTER_SLAVE=1; //TI is Master
SpiaRegs.SPICTL.bit.TALK=1; //Communication is permitted
SpiaRegs.SPICTL.bit.SPIINTENA=0; //Disable Interrupt
SpiaRegs.SPISTS.all=0x0000;
SpiaRegs.SPIBRR=0x007; // Baud rate=LSPCLK/(7+1)
SpiaRegs.SPIFFTX.bit.SPIFFENA=1; //TX FIFO Enable
SpiaRegs.SPIFFTX.bit.TXFFINTCLR=1; //Clear TX Int flag
SpiaRegs.SPIFFTX.bit.TXFFIL=4; //Set Level to 1 character
SpiaRegs.SPIFFTX.bit.TXFFST=0; //Set FIFO Status to 0 characters
SpiaRegs.SPIFFRX.bit.RXFFOVFCLR=1; //Clear RX FIFO Overflow flag
SpiaRegs.SPIFFRX.bit.RXFFINTCLR=1; //Clear RX FIFO Interrupt flag
SpiaRegs.SPIFFRX.bit.RXFFIENA=0; //Disable RX FIFO Interrupt
SpiaRegs.SPIFFRX.bit.RXFFIL=4; //Set flag after 4 bytes received
SpiaRegs.SPIFFRX.bit.RXFFST=0; //Set RX FIFO status to 0
SpiaRegs.SPIPRI.bit.FREE=1; //Don't let debug interrupt SPI transfer
SpiaRegs.SPIPRI.bit.SOFT=0; //Makes no difference
EDIS;
}
static void spiReleaseFromReset(){
EALLOW;
SpiaRegs.SPIFFRX.bit.RXFIFORESET=1; //Release from reset
SpiaRegs.SPIFFTX.bit.TXFIFO=1; //Release from reset
SpiaRegs.SPIFFTX.bit.SPIRST=1; //Release from reset
SpiaRegs.SPICCR.bit.SPISWRESET=1; //Release SPI from reset
EDIS;
}
static void spiEnableInterrupts(){
EALLOW;
// Enable interrupts required for this example
PieCtrlRegs.PIECTRL.bit.ENPIE = 1; // Enable the PIE block
PieCtrlRegs.PIEIER6.bit.INTx1=1; // Enable PIE Group 6, INT 1
PieCtrlRegs.PIEIER6.bit.INTx2=1; // Enable PIE Group 6, INT 2
IER=0x20; // Enable CPU INT6
EINT; // Enable Global Interrupts
EDIS;
}
void spiSendAndReceive(Uint16 *outBuffer, Uint16 outBytes, Uint16 *inBuffer, Uint16 inBytes, Uint16 byteSize){
if(byteSize==0||byteSize>16){return;} //If bad byte size return
if(outBuffer==0&&inBuffer==0){return;} //If both buffers are null return
if(outBuffer==0&&outBytes!=0){return;} //If TX buffer is null, but TX buffer size is non zero return
if(inBuffer==0&&inBytes!=0){return;} //If RX buffer is null, but RX buffer size is non zero return
spiSetByteSize(byteSize);
spiSend(outBuffer, outBytes);
spiReceive(inBuffer, inBytes);
EALLOW;
SpiaRegs.SPIFFTX.bit.TXFFIENA=0; //TX FIFO Int Enable
SpiaRegs.SPIFFRX.bit.RXFFIENA=0; //RX FIFO Int Enable
EDIS;
}
void spiSetByteSize(Uint16 byteSize){
SpiaRegs.SPICCR.bit.SPICHAR=(byteSize-1) & (0x000F);
}
void spiSend(Uint16 *outBuffer,Uint16 outBytes){
spiSemTXFF=1; //Pseudo Semaphore for TX ISR
spiTXBuffer=outBuffer; //Set data buffer
spiDataSize=outBytes; //Set data size
EALLOW;
SpiaRegs.SPIFFTX.bit.TXFFIL=outBytes; //Set level to number of characters
SpiaRegs.SPIFFTX.bit.TXFFST=outBytes; //Set status reg to number of characters
SpiaRegs.SPIFFTX.bit.TXFFIENA=1; // Enable TX FIFO interrupt
EDIS;
while(spiSemTXFF==1){} //Wait until ISR returns
EALLOW;
SpiaRegs.SPIFFTX.bit.TXFFIENA=0; // Disable TX FIFO interrupt
EDIS;
}
void spiReceive(Uint16 *inBuffer,Uint16 inBytes){
spiSemRXFF=1; //Pseudo Semaphore for RX ISR
spiRXBuffer=inBuffer; //Set data buffer
spiDataSize=inBytes; //Set data size
EALLOW;
SpiaRegs.SPIFFRX.bit.RXFFIL=inBytes; //Set level to number of characters
SpiaRegs.SPIFFRX.bit.RXFFST=inBytes; //Set status reg to number of characters
SpiaRegs.SPIFFRX.bit.RXFFIENA=1; //Enable RX FIFO interrupt
EDIS;
while(spiSemRXFF==1){} //Wait until ISR returns
EALLOW;
SpiaRegs.SPIFFRX.bit.RXFFIENA=0; //Disable RX FIFO interrupt
EDIS;
}
interrupt void spiTxFifoIsr(void)
{
//For every character,
for(spiDataIndex=0;spiDataIndex<spiDataSize;spiDataIndex++){
SpiaRegs.SPITXBUF=
(spiTXBuffer[spiDataIndex]<<(15-SpiaRegs.SPICCR.bit.SPICHAR));// Left align data, then send
}
SpiaRegs.SPIFFTX.bit.TXFFINTCLR=1; //Clear Interrupt flag
//PieCtrlRegs.PIEACK.all|=0x20; //Issue PIE ACK
PieCtrlRegs.PIEACK.bit.ACK6=1; //Acknowledge interrupt to PIE
spiSemTXFF=0; //Reset Semaphore
}
interrupt void spiRxFifoIsr(void)
{
for(spiDataIndex=0;spiDataIndex<spiDataSize;spiDataIndex++){
spiRXBuffer[spiDataIndex]=SpiaRegs.SPIRXBUF; // Read data
}
SpiaRegs.SPIFFRX.bit.RXFFOVFCLR=1; // Clear Overflow flag
SpiaRegs.SPIFFRX.bit.RXFFINTCLR=1; // Clear Interrupt flag
//PieCtrlRegs.PIEACK.all|=0x20; // Issue PIE ack
PieCtrlRegs.PIEACK.bit.ACK6=1; //Acknowledge interrupt to PIE
spiSemRXFF=0; //Reset Semaphore
}
#endif
Any help would be greatly appreciated.