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.
Hi folks,
Im working withe the SPI-A on the F28027 to communicate between two of these devices. I though I had everything set up correctly, and still cant see any issue but as soon as the master F28027 starts sending data (8-bit ASCII) to the slave F28027, the slave traps the SPIRXINTA in the ISR_ILLEGAL isr.
PIECTRL.PIEVECT shows that it is the SPIRXINTA vector (0x0D91) that is being fetched when this happens, even though I have assigned my own ISR to this vector that should handle the SPI Rx. Am at a bit of a loss as to what is wrong to cause this :\
Thanks for any help figuring it out!
Below is my current code. With it when the master wishes to communicate with the slave it does so in a synchronous manner by calling spiMasterComm() which simply pushes the bytes sequentially into the TX buffer, blocking while the transmission takes place (i.e. while SPISTS.BUFFULL_FLAG is true). If the master knows a response is required from the slave it waits for a service request signal (external interrupt) then begins to feed dummy data into the TX buffer and remove the received data from the RX buffer.
the slave side operates a little more asynchronously, using interrupts, when data is received the spiSlaveRx_isr() *should* be vectored and remove the byte from the RX buffer push it to a queue, before acknowledging the interrupt and returning. If transmitting a response to the master, the slave simply calls spiSlaveTx() which pops a char off of a queue, asserts the GPIO to raise the master's external interrupt service request signal and puts the data in the TX buffer. spiSlaveTx_isr then only needs to acknowledge the TX interrupt.
static void interrupt spiSlaveRx_isr (void) { /* Receives data on a slave unit from a master unit. */ uint16_t err = 0; char buf[2] = {0}; /* pushIBuff requires a string input */ /* Read the data from the SPI receive buffer and push the lower byte to the SCPI input buffer */ buf[0] = (char) SpiaRegs.SPIRXBUF; if (GpioDataRegs.GPADAT.bit.GPIO6) {/* Check SRQ is not asserted as otherwise the received data is just dummy data */ err = pushIBuff(buf); /* Push the char to the iBuff. */ if (err) /* Ensure the push completed OK. */ pushError(err); } PieCtrlRegs.PIEACK.bit.ACK6 = 1;/* Acknowledge the interrupt in PIE */ } int16_t spiSlaveTx (void) { /* Starts transmitting data-byte from a slave unit to a master unit. */ uint16_t err; char buf = 0; while (SpiaRegs.SPISTS.bit.BUFFULL_FLAG) {} /* Wait for the transmit buffer to be ready. */ msgs.flag.brq = true; /* Set brq message. */ err = popOQueue(&buf); /* Pop a byte from the output queue. */ if (err) { /* Check the pop occurred correctly. */ pushError(err); return 1; } assertSRQ(); /* Make sure SRQ is asserted. */ buf = SpiaRegs.SPIRXBUF;/* Read any dummy data from receive buffer to clear interrupt flag. */ /* Move the byte to the transmit buffer (left justified). */ SpiaRegs.SPITXBUF = buf << 8; return 0; } static void interrupt spiSlaveTx_isr (void) { /* SPI transmission interrupt, indicating the SPI is ready for more data. */ PieCtrlRegs.PIEACK.bit.ACK6 = 1; /* Acknowledge the interrupt in PIE. */ } int16_t spiInit(spiMode mode, uint32_t baud, spiLpbk loopback, transPol cPol, spiCPha cPha, uint16_t to) { float spiBrr = (float)baud; uint16_t temp = 7; /* Init the config control reg (SPICCR) value. Reset on, 8-bit char length. */ temp |= ((uint16_t) cPol) << 6; /* Add the clock polarity setting to the SPICCR value. */ temp |= ((uint16_t) loopback) << 4;/* Add the loop-back setting to the SPICCR value. */ SpiaRegs.SPICCR.all = temp; /* Save the SPICCR value to the register. */ temp = 0x02; /* Init the operation control reg (SPICTL) value. Enable TALK. */ if (mode == spiSlave) /* Enable the interrupts if this is the slave. */ temp |= 1; temp |= ((uint16_t) cPha) << 3; /* Add the clock phase setting to the SPICTL value. */ temp |= ((uint16_t) mode) << 2; /* Add the mode setting to the SPICTL value. */ SpiaRegs.SPICTL.all = temp; /* Save the SPICTL value to the register. */ /* Use the requested baud rate and LSPCLK frequency to calculate the * SPI bit rate control value. * Baud rate = (LSPCLK / [SPIBRR + 1]). */ spiBrr = (LOSPCLK_FREQ_SET / spiBrr) - 1; if ((spiBrr < 4) || (spiBrr > 127)) /* Ensure SPIBRR value is within bounds */ return VALUE_OOB; SpiaRegs.SPIBRR = (uint16_t) spiBrr;/* Save the |SPIBRR| value to the register. */ SpiaRegs.SPIPRI.all = 0x00; /* Set free-run and 4-wire mode. */ if (mode == spiSlave) { releaseSRQ(); /* Make sure outgoing SRQ output is LOW. */ PieVectTable.SPIRXINTA = &spiSlaveRx_isr; /* Set ISR for SPI receive interrupt. */ PieVectTable.SPITXINTA = &spiSlaveTx_isr; /* Set ISR for SPI transmit interrupt. */ PieCtrlRegs.PIECTRL.bit.ENPIE = 1; /* Ensure the PIE block is enabled. */ PieCtrlRegs.PIEIER6.bit.INTx1 = 1; /* Enable PIE group 6, INT 1, SPIRXINTA. */ PieCtrlRegs.PIEIER6.bit.INTx2 = 1; /* Enable PIE group 6, INT 2, SPITXINTA. */ IER |= M_INT6; /* Enable group 6 in IER */ } rxTimeout = to; /* Save the receive timeout setting. */ resetVirtualTimer(&vTimer0); /* Setup the timer for the SRQ assertion timeout. */ setVirtualTimerThld(&vTimer0, rxTimeout); SpiaRegs.SPICCR.bit.SPISWRESET = 1; /* Relinquish SPI from reset. */ return 0; } int16_t spiMasterComm (uint16_t * length, char * txMessage, char * rxMessage) { if ((!*txMessage || !*length) && !rxMessage) /* Check parameters are valid. */ return 1; /* Parameters incorrect. */ uint16_t i = 0, dump; char buf = 0; if (*txMessage && *length) { /* Check if a transmission is required. */ /* Count the number of bytes sent so we know when the full message has been sent. */ for (i = 0; i < *length; i++) { while (SpiaRegs.SPISTS.bit.BUFFULL_FLAG) {} /* Wait until the transmit buffer is ready. */ /* Move the next byte to be transmitted into the transmit buffer (left justified). */ SpiaRegs.SPITXBUF = ((uint16_t) (*txMessage++)) << 8; } i = 0; /* Clear the counter. */ } if (*rxMessage) { /* Check if a receive is required. */ /* Set so the ISR doesn't regard the SRQ as a report of an error on the slave. */ expectingSRQ = true; startVirtualTimer(&vTimer0); /* Start the timer for the receive timeout. */ /* Wait for the SRQ assertion to be reported by the ISR. */ while (!isSRQ) {} ackSRQ(); /* Acknowledge the SRQ. */ /* Receive the expected data while the destination remains valid. */ while (*rxMessage) { /* Transmit dummy data to run the clock for receive data from the slave. */ SpiaRegs.SPITXBUF = 0; while (!SpiaRegs.SPISTS.bit.INT_FLAG) {} /* Wait for a data byte to be received. */ buf = (char) SpiaRegs.SPIRXBUF; if ((buf != UNIT_SEP) && (buf != NL_MSG_TERM) && (buf != END_MSG_TERM)) { *rxMessage++ = buf; i++; } else { *rxMessage++ = 0; /* Replace any <PMUT>s or <PMT>s with string termination. */ } } *length = i; } dump = dump; /* Prevent unused variable warning. */ return 0; }
Toby,
The ILLEGAL ISR corresponds to a illegal trap. This occurs most often when a buffer overflows, the stack is corrupted or a function with a load location in flash is not copied to a run location in RAM. Some of the causes and ideas of how to track it down are documented here:
http://processors.wiki.ti.com/index.php/Interrupt_FAQ_for_C2000#Q:_How_can_I_debug_an_ITRAP.3F
Regards
Lori
Oeh,
if
(mode == spiSlave) {
releaseSRQ();
/* Make sure outgoing SRQ output is LOW. */
PieVectTable.SPIRXINTA = &spiSlaveRx_isr;
/* Set ISR for SPI receive interrupt. */
PieVectTable.SPITXINTA = &spiSlaveTx_isr;
/* Set ISR for SPI transmit interrupt. */
If "mode!=spiSlave" then by the previous line lines "if (mode == spiSlave) temp |= 1;" then interrupts should be disabled... Checking the register at run time shows this is correct... Thanks for the suggestion though.
Uhm,
I never see you using EALLOW; ... EDIS;
Aren't you changing protected registers?
And please correct me if I'm wrong, but aren't ISRs clearing the "EALLOW" permission?
Tjarco
Gosh darn it you're correct Tjarco! Damn EALLOW protection is always catching me out!!
Thanks a bunch, I could have been looking at this for days and not cottoned on to that, LOL
I think I remember there being a list of all EALLOW protected registers somewhere, but I cant remember where... any notion where that might be?
Just for anyone who might stumble on this with similar issues; The PieVectTable registers I wrote to in my spiInit() function are EALLOW protected. So my code should have been as follows:
if (mode == spiSlave) { releaseSRQ(); /* Make sure outgoing SRQ output is LOW. */ EALLOW; PieVectTable.SPIRXINTA = &spiSlaveRx_isr; /* Set ISR for SPI receive interrupt. */ PieVectTable.SPITXINTA = &spiSlaveTx_isr; /* Set ISR for SPI transmit interrupt. */ EDIS; //... }
Hi,
Good to hear. If I'm correct you can find the register overview in the "System Control and Interrupts" Reference Guide of the Microcontroller page 102.
And if I'm correct you should take in account that if an Interrupt occurs between the "EALLOW" and the "EDIS" line, your EALLOW will be cleared. So you should use something like an intrinsic to keep your permission:
var = __disable_interrupts(); //Disable global interrupts EALLOW; ... EDIS; if(var) __enable_interrupts(); //Enable global interrupts
Could someone confirm this, just to be sure?
Hi Tjarco,
Great, I will check that out and print out and pin-up the page with that on!
As regards EALLOW clearing via interrupt, however I was always told that its good practice to do all such system initialization near the start of a program and before globally enabling interrupts which would avoid this problem:
void main (void) { pwmInit(); spiInit(); sciInit(); i2cInit(); adcInit(); EINT; /* Enable Global interrupt INTM */ ERTM; /* Enable Global real-time interrupt DBGM */ while (1) { //... } }
Though I am not sure you are correct in sying tht interrupts clear the EALLOW condition. They do clear the EALLOW bit in ST1 after a context switch, i.e. ST1 is pushed to the stack before it is cleared, meaning that when the interrupt returns EALLOW should be restored. See page 2-35 of http://www.ti.com/lit/ug/spru430e/spru430e.pdf
Though this does mean that EALLOW is disabled for the purposes of the ISR code execution unless explicitly reset by the ISR code itself.
Hi Toby,
Yes I think you're right about the context restore of EALLOW. I've some code in which I've to EALLOW inside an interrupt. Therefore I usually add the _disable_interrupt when changing protected registers.
Best regards,
Tjarco