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.
Tool/software:
Hello,
I am using the Launchpad F280049 board and I'm trying to understand how to use interrupts to implement SCI communication with the host computer. The example used and modified is the sci_ex2_interrupts.c located at (C:\ti\c2000\C2000Ware_5_01_00_00\driverlib\f28004x\examples\sci).
To get straight to the point, when I try to send a character array from the host computer, the SCIRX interrupt does it's job, receives the characters and sends them back. Even though the job of the ISR routine is finished, the RX interrupt is called again. But in this case, I'm not sending any characters to the RX so the readCharArray function just waits forever and thus ISR never returns.
SCIRX and SCITX ISR routines
__interrupt void sciaTxISR(void) { // // Disable the TXRDY interrupt. // SCI_disableInterrupt(SCIA_BASE, SCI_INT_TXRDY); msg = "\r\nEnter a character: \0"; SCI_writeCharArray(SCIA_BASE, (uint16_t*)msg, 22); // // Ackowledge the PIE interrupt. // Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9); } __interrupt void sciaRxISR(void) { // // Enable the TXRDY interrupt again. // SCI_enableInterrupt(SCIA_BASE, SCI_INT_TXRDY); // // Read a character from the RXBUF. // MSG_LENGTH = 10 characters SCI_readCharArray(SCIA_BASE, msgreceive, MSG_LENGTH); // HERE IS THE PROBLEM // // Echo back the character. // msg = "You sent: "; SCI_writeCharArray(SCIA_BASE, (uint16_t*)msg, 13); SCI_writeCharArray(SCIA_BASE, (uint16_t*)msgreceive, MSG_LENGTH); //recievemsg = (uint16_t)(HWREGH(SCIA_BASE + SCI_O_RXBUF) & SCI_RXBUF_SAR_M); // // Acknowledge the PIE interrupt. // Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9); counter++; }
When I try to disable the RX interrupt inside the ISR and enable it inside the TX ISR, the RX ISR never gets stuck calling itself and receives characters and exits properly.
__interrupt void sciaTxISR(void) { // // Disable the TXRDY interrupt. // SCI_disableInterrupt(SCIA_BASE, SCI_INT_TXRDY); SCI_enableInterrupt(SCIA_BASE, SCI_INT_RXRDY_BRKDT); //ENABLE RX INTERRUPT msg = "\r\nEnter a character: \0"; SCI_writeCharArray(SCIA_BASE, (uint16_t*)msg, 22); // // Ackowledge the PIE interrupt. // Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9); } // // sciaRxISR - Read the character from the RXBUF and echo it back. // __interrupt void sciaRxISR(void) { // // Enable the TXRDY interrupt again. // SCI_disableInterrupt(SCIA_BASE, SCI_INT_RXRDY_BRKDT); // DISABLE RX INTERRUPT SCI_enableInterrupt(SCIA_BASE, SCI_INT_TXRDY); // // Read a character from the RXBUF. // SCI_readCharArray(SCIA_BASE, msgreceive, MSG_LENGTH); // // Echo back the character. // msg = "You sent: "; SCI_writeCharArray(SCIA_BASE, (uint16_t*)msg, 13); SCI_writeCharArray(SCIA_BASE, (uint16_t*)msgreceive, MSG_LENGTH); //recievemsg = (uint16_t)(HWREGH(SCIA_BASE + SCI_O_RXBUF) & SCI_RXBUF_SAR_M); // // Acknowledge the PIE interrupt. // Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9); counter++; }
My question is: why does disabling and enabling an interrupt in this manner work? What is making the program call the ISR again in the first case even though there are no characters in the SCIRXBUF register?
I hope I covered everything clearly but if not, happy to provide more detail.
Thank you.
Hello,
Have you modified the SCI configurations? The interrupts will be called if they are triggered, so the registers to look at are the SCI RX registers - is this nonFIFO mode and dependent on the RX status bits? Are you already stepping through the code and watching the SCI registers to see how the behavior is and/or scoping SCI lines to ensure the signals are as expected?
By the way, if you were using FIFO mode, the RX and TX interrupts would be solely dependent on the level of characters in the FIFO and, for example, would trigger when your preconfigured amount of characters is received (e.g. if you have RXFFIL = 2, RX interrupt would be triggered when the RX FIFO is filled with 2 complete characters).
If you are disabling the RX interrupt in your RX ISR, you ensure that no RX interrupts can be called unless you first jump to your TX ISR. In this case, when you write to the buffer to transmit, that causes a jump to the TX ISR and enables the RX ISR to then occur upon receival.
Best Regards,
Allison
I am using this example from the C2000WARE library. "C:\ti\c2000\C2000Ware_5_01_00_00\driverlib\f28004x\examples\sci\sci_ex2_interrupts.c"
All I modified was these set of lines
// // Read a character from the RXBUF. // receivedChar = SCI_readCharBlockingNonFIFO(SCIA_BASE); // // Echo back the character. // msg = " You sent: \0"; SCI_writeCharArray(SCIA_BASE, (uint16_t*)msg, 13); SCI_writeCharBlockingNonFIFO(SCIA_BASE, receivedChar);
to these:
// // Read a character from the RXBUF. // SCI_readCharArray(SCIA_BASE, msgreceive, MSG_LENGTH); // // Echo back the character. // msg = " You sent: \0"; SCI_writeCharArray(SCIA_BASE, (uint16_t*)msg, 13); SCI_writeCharArray(SCIA_BASE, (uint16_t*)msgreceive, MSG_LENGTH);
inside the SCIRX ISR. The only difference is in the first one I'm just echo'ing back a character and in the second one, I'm trying to echo back MSG_LENGTH character array.
I am using non FIFO based communication here and the configuration is shown below:
// // Map the ISR to the wake interrupt. // Interrupt_register(INT_SCIA_TX, sciaTxISR); Interrupt_register(INT_SCIA_RX, sciaRxISR); SCI_performSoftwareReset(SCIA_BASE); SCI_disableModule(SCIA_BASE); HWREGH(SCIA_BASE + SCI_O_HBAUD) = 0; HWREGH(SCIA_BASE + SCI_O_LBAUD) = 0; HWREGH(SCIA_BASE + SCI_O_CCR) = ((HWREGH(SCIA_BASE + SCI_O_CCR) & ~(SCI_CONFIG_PAR_MASK | SCI_CONFIG_STOP_MASK | SCI_CONFIG_WLEN_MASK)) | (SCI_CONFIG_WLEN_8 | SCI_CONFIG_STOP_ONE | SCI_CONFIG_PAR_NONE)); SCI_resetChannels(SCIA_BASE); SCI_clearInterruptStatus(SCIA_BASE, SCI_INT_TXRDY | SCI_INT_RXRDY_BRKDT); SCI_enableModule(SCIA_BASE); SCI_performSoftwareReset(SCIA_BASE); // // Enable the TXRDY and RXRDY interrupts. // SCI_enableInterrupt(SCIA_BASE, SCI_INT_TXRDY | SCI_INT_RXRDY_BRKDT);
If you are disabling the RX interrupt in your RX ISR, you ensure that no RX interrupts can be called unless you first jump to your TX ISR. In this case, when you write to the buffer to transmit, that causes a jump to the TX ISR and enables the RX ISR to then occur upon receival.
This is what happens and disabling and enabling the interrupts like this works and I'm trying to understand the reason. Why should I disable and enable? Shouldn't the character array be empty once I received so that it never calls the ISR again (I'm referring to the second code snippet)?
Hi Shriram,
Allison is currently out of office until after the holidays. Please expect a delay in response. Thank you for your patience.
Best Regards,
Aishwarya
Hi Shiram,
Apologies for the extended delay. Are you still having confusion here?
Added below are the driverlib descriptions just for context, which are very similar between the two (in NonFIFO), aside for the amount of data.
SCI_readCharBlockingNonFIFO:
//***************************************************************************** // //! Waits for a character from the specified port when the FIFO enhancement //! is not enabled. //! //! \param base is the base address of the SCI port. //! //! Gets a character from the receive buffer for the specified port. If there //! is no characters available, this function waits until a character is //! received before returning. //! //! \return Returns the character read from the specified port as \e uint16_t. // //***************************************************************************** static inline uint16_t SCI_readCharBlockingNonFIFO(uint32_t base) { // // Check the arguments. // ASSERT(SCI_isBaseValid(base)); // // Wait until a character is available in the receive FIFO. // while(!SCI_isDataAvailableNonFIFO(base)) { } // // Return the character from the receive buffer. // return((uint16_t)(HWREGH(base + SCI_O_RXBUF) & SCI_RXBUF_SAR_M)); }
SCI_readCharArray:
//***************************************************************************** // // SCI_readCharArray // //***************************************************************************** void SCI_readCharArray(uint32_t base, uint16_t * const array, uint16_t length) { // // Check the arguments. // ASSERT(SCI_isBaseValid(base)); uint16_t i; // // Check if FIFO enhancement is enabled. // if(SCI_isFIFOEnabled(base)) { // // FIFO is enabled. // For loop to read (Blocking) 'length' number of characters // for(i = 0U; i < length; i++) { // // Wait until a character is available in the receive FIFO. // while(SCI_getRxFIFOStatus(base) == SCI_FIFO_RX0) { } // // Return the character from the receive buffer. // array[i] = (uint16_t) (HWREGH(base + SCI_O_RXBUF) & SCI_RXBUF_SAR_M); } } else { // // FIFO is not enabled. // For loop to read (Blocking) 'length' number of characters // for(i = 0U; i < length; i++) { // // Wait until a character is available in the receive buffer. // while(!SCI_isDataAvailableNonFIFO(base)) { } // // Return the character from the receive buffer. // array[i] = (uint16_t) (HWREGH(base + SCI_O_RXBUF) & SCI_RXBUF_SAR_M); } } }
In the original unmodified example: the device would first be triggered to enter TX ISR, disable the TX interrupt so it doesn't repeatedly send messages to the host PC. The device would idle until triggered by the user writing a character to be received by the device. Upon receival, the device would enter the RX ISR which would then write back the character to the host and allow another TX ISR to occur before idling again waiting for receival.
I would expect similar behavior for your case. Have you stepped through your code to observe/confirm the behavior line by line? Have you also reviewed the SCI waveforms to see if there is behavior on the RX line?
Best Regards,
Allison
Hello,
"disable the TX interrupt so it doesn't repeatedly send messages to the host PC. The device would idle until triggered by the user writing a character to be received by the device".
This was what I was looking for. Why do we need to disable the interrupt inside the interrupt? Unless we send a character, how can the interrupt be called again?
From the original example, the TX interrupt is disabled but not the RX interrupt. I modified the example to disable the RX interrupt for it to work. Why is this?
And yes, I did debug the code to see if I could capture an anomaly but everytime, it would just jump to the next call for the RX ISR after reading the character array.
Hi Shriram,
Let me address your first question:
Why do we need to disable the interrupt inside the interrupt?
This is because the example wants to send a single message to the user and then wait for a response from the user (wait to receive a character) before triggering the TX ISR again to (again) prompt the user to enter a character. Note that the SCI transmitter uses the SCICTL2 register flag bit TXRDY which indicates active interrupt conditions. So in essence, the TXRDY bit determines when a TX interrupt is triggered- which is why we want to enable/disable in this example.
If you review the register descriptions for TXRDY, you'll see that the TXRDY bit is set to '1' when the SCITXBUF buffer is empty (ready to be written to in order to transmit the next character). When set, this flag asserts a transmitter interrupt request as long as the interrupt-enable bit is set as well. So if the TXRDY interrupt remained enabled after you finished transmitting the first message, the TXBUF would be empty after sending out the message which would actually immediately trigger another TX interrupt (after the interrupt is acknowledged) while waiting for the user to send back a character.
Please note that there are several different ways to accomplish what this example is doing. This is simply one of them showcasing an application of SCI interrupts in nonFIFO mode.
everytime, it would just jump to the next call for the RX ISR after reading the character array
Regarding this, are you seeing the RXRDY flag get cleared to 0 correctly after reading from RXBUF? This bit is controlling the receiver interrupt line.
Best Regards,
Allison
Regarding this, are you seeing the RXRDY flag get cleared to 0 correctly after reading from RXBUF? This bit is controlling the receiver interrupt line.
When I'm in debug mode, the RXRDY flag is not set at all (always at 0).
"Data is shifted from RXSHF to the receiver buffer register (SCIRXBUF); an interrupt is requested. Flag bit
RXRDY (SCIRXST, bit 6) goes high to signal that a new character has been received."
The above is from the technical reference manual. So according to this, the program should only receive the interrupt when I send in the next character. If I'm sending 10 characters from the host PC and calling readCharArray on 10 characters, RXRDY after reading the last character should be 0 as expected. But the program gets stuck at this part here where it waits for the 11th character (which is not present at all):
// Wait until a character is available in the receive FIFO. // while(!SCI_isDataAvailableNonFIFO(base)) { }
which is inside the RX ISR. So unless the ISR is called a second time, there's no way for the program to bein this infinite loop waiting for the next character to be recieved.
When I'm in debug mode, the RXRDY flag is not set at all (always at 0).
Sometimes, I can see it being set but it depends upon where I set my breakpoints. When the ISR runs for the second time (which it shouldn't), it's always at 0.
Update:
So I was able to get RXRDY to be 1 on a different debug point, but I had to twiddle around to exactly get this signature. But when I'm sending 10 characters from PC and expecting 10 characters in the firmware (provided code in the first post), why does RXRDY always say 1?
Hi Shriram,
RXRDY is dependent on the status of RXBUF, so it should clear to 0 after every read (and before it receives the next character into RXBUF). Depending on how you are debugging, you may not see the RXRDY bit being cleared if there is back to back data constantly being received and CCS refresh can't capture it. A few notes:
I will try to see if I can run similar code to you and determine if I see similar behavior over the next ~day.
Best Regards,
Allison
Hi Shriram,
I am running a version of the SCI example 2 interrupts from C2000Ware and modified similar to how you have (transmitting 10 characters using same driverlib functions as you.
With this setup, when you write the first character, the CPU will immediately jump to the RX ISR since you are in nonFIFO mode and the RX interrupt flag will get set with a single character ready to be read. After this, however, the user needs to continue typing in characters (sending to the C2000) to fulfill the read_CharArray function MSG LENGTH requirement (message length being 10). As soon as you enter another character into the serial terminal, there is now another pending RX interrupt flag. Since we don't disable the RX interrupts or clear all flags along the interrupt path (from SCI --> PIE --> CPU level), then that causes the program to jump right back into the next RX ISR after. This is also because SCIRX interrupt is prioritized over SCITX, so even when the TX interrupt flag is set, the program will keep jumping into RX ISR which is what you are seeing.
I then modified the example by disabling RX interrupts at the start of the RX ISR (and re-enabling within the TX ISR). As you hinted at. In this way, the RX ISR is not called repeatedly. It will wait until the TX ISR is executed first before allowing the next RX ISR to occur.
To reiterate, there are other more concise methods of accomplishing this such as utilizing FIFO mode + interrupts, but hopefully this clears up any lasting confusion on why RX INT disable is needed for your case sending multiple characters using the array functions.
Attached is my modified example so you can compare:
Best Regards,
Allison