CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

PIC24 with ex_stisr.c

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
jeremiah



Joined: 20 Jul 2010
Posts: 1358

View user's profile Send private message

PIC24 with ex_stisr.c
PostPosted: Thu May 15, 2014 11:38 am     Reply with quote

I found one old thread about this, but it had no responses. Other threads didn't seem to cover these particular issues that I could find.

Rev 5.025
PIC24FJ64GA004
24MHz crystal

ISSUE #1:
I grabbed the ex_stisr.c file to test out serial driven output, but out of the box it didn't work. It seemed like it would print the first character and then not print any others. I could force it back into action by manually calling putc() with some character and the interrupt would start firing again until the buffer was empty. Using LED's I was able to trace the code to being stuck in the while loop in bputc():

Code:
while(ni==t_next_out);


I had an LED flash while in the loop (which I could visually see), an LED set to update based on TRMT, and an LED set to update based on U1TXIE (interrupt enable bit). While stuck in the loop, TRMT was set to 1 and U1TXIE was also 1 indicating that the interrupt was still enabled but there were no TX data in the 4 byte TX buffer. This means that my code was filling up the TX buffer and waiting but not actually firing the interrupt.

The first fix I cam up with for this was to manually set the IF bit for the interrupt right after enabling the interrupt (I remember a recent thread about manually starting interrupts) and this seems to make the example run correctly.

Looking at the code after that, it wasn't even apparent how the original ex_stisr.c was initially firing the interrupt to begin with (does that happen when you enable the interrupt normally or something?).

This seems like odd behavior. Is there a better way specifically to get the TBE interrupt to fire for the first byte of the buffer?


ISSUE #2:
Now that I have it working I noticed another of my debug LED's acting oddly. Instead of toggling each time a character was put in the buffer, it toggled twice per character, going back to the original state. To make sure I wasn't seeing a "sampling to fast to see" measurement issue, I added a counter to the TBE interrupt and an LCD driver to print out the value of the counter (since I am using the UART already). Sure enough, I was getting around 42 interrupts for each "This is buffered data\r\n". This wasn't exactly 2x the number of characters sent, so based on a hunch from what I saw in issue #1, I moved the enable/disable logic from the code and placed a single enable in the main right before the call to enable global interrupts so that the TBE interrupt was always enabled.

After doing that I got 1 count from simply powering on and getting to the while loop, and then for every "This is buffered data\r\n", I got an additional 46 counts, which was 2x the number of chars.

Is it normal for there there to be two TBE interrupts for every char if they are placed in the buffer one after another (per the ISR)?

I checked the errata for the chip and there was a TBE item, but it was for when the interrupt select was not 0b00 (which is what mine is set for). That doesn't mean it isn't related, but it wasn't exactly the same issue.

I also made sure that when I manually set the IF flag, I only do it when the "reset" condition is met in bputc(). I did make sure to use {} (which ex_stisr.c doesn't) on the if statement.

Any thoughts?

I can post my entire code, but it is really close to ex_stisr.c, so I am not sure if that is allowed or not.
newguy



Joined: 24 Jun 2004
Posts: 1911

View user's profile Send private message

PostPosted: Thu May 15, 2014 12:11 pm     Reply with quote

I had similar problems with the stock CCS drivers (it's been many years since I first played with them, so my memory is a bit fuzzy). Here's tried & true transmit code that is more-or-less the basis of all my interrupt driven serial transmit code.

Code:
#int_TBE
void TBE_isr(void) {
   if (tx_counter != 0) {
      putc(tx_buffer[tx_rd_index]);
      if (++tx_rd_index > TX_BUFFER_SIZE) {
         tx_rd_index = 0;
      }
      tx_counter--;
      if (tx_counter == 0) {
         disable_interrupts(INT_TBE);
         transmit_enabled = FALSE;
      }
   }
}

void bputc(int c) {
   int1 restart = FALSE;

   while (tx_counter > (TX_BUFFER_SIZE - 1)) {
      restart_wdt();
   }
   disable_interrupts(INT_TBE);
   if (tx_counter == 0) {
      restart = TRUE;
   }
   tx_buffer[tx_wr_index++] = c;
   if (tx_wr_index > TX_BUFFER_SIZE) {
      tx_wr_index = 0;
   }
   tx_counter++;
   if (restart) {
      transmit_enabled = TRUE;
   }
   if (transmit_enabled) {
      enable_interrupts(INT_TBE);
   }
}
jeremiah



Joined: 20 Jul 2010
Posts: 1358

View user's profile Send private message

PostPosted: Thu May 15, 2014 5:45 pm     Reply with quote

Thanks! I'll try that out tomorrow. Though at first glance it still looks like it might suffer from the interrupt not firing (like I saw in issue #1). I'll test it out and see though.


I did figure out that issue #2 is directly related to what I tried to do to fix issue #1.
newguy



Joined: 24 Jun 2004
Posts: 1911

View user's profile Send private message

PostPosted: Thu May 15, 2014 8:08 pm     Reply with quote

The TBE interrupt is, by far, the most dangerous interrupt. What I mean by that is that it's very very easy to make a mistake that bricks the PIC.

- Keep in mind that the TBE "fires" if the transmit buffer is empty and will keep firing, over & over, if you don't "feed" the UART a character to transmit.
- Thou shalt only enable the TBE interrupt if you actually have characters to feed to the UART.
- Thou shalt disable the TBE interrupt after you've fed it the last character to send.
- ANY variables or flags used to either load the transmit buffer or test for its state (empty or not) shall only be tested when the TBE interrupt has been disabled, then re-enabled after that (if necessary).
jeremiah



Joined: 20 Jul 2010
Posts: 1358

View user's profile Send private message

PostPosted: Thu May 15, 2014 9:13 pm     Reply with quote

newguy wrote:

- Keep in mind that the TBE "fires" if the transmit buffer is empty and will keep firing, over & over, if you don't "feed" the UART a character to transmit.


That's what I mean. It isn't doing that on my chip. It only fires when a character is transferred out or it goes empty, but after that it no longer fires. In my case, I actually have to force the first interrupt by setting the IF flag for TBE to get it going and if it stops, I have to force the interrupt again. I don't know if that is typical of PIC24 chips vs others or not, but it only seems to fire on "transitions". It's not continuously firing if the buffer is empty.
newguy



Joined: 24 Jun 2004
Posts: 1911

View user's profile Send private message

PostPosted: Thu May 15, 2014 9:42 pm     Reply with quote

Check that chip's errata. Bet you'll find the reason why it's doing that in there.
jeremiah



Joined: 20 Jul 2010
Posts: 1358

View user's profile Send private message

PostPosted: Fri May 16, 2014 11:41 am     Reply with quote

Yeah, I mentioned the errata earlier in my first post. Unless I am missing one, I only see the one for TBE near the end where it returns too fast when saying the buffer is empty. I'm not sure how to equate that to not receiving the interrupt at all (maybe it is so quick, I don't service the first ISR fast enough?), especially since my interrupt selection bits are 00 rather than the 01 the errata specifies.

Thanks for the insight. I did try your code. The disable/enable of the interrupt seems to get past the issue of not starting at all, but it fills the entire buffer before printing to the screen, causing lost chars. Sometimes it replaces chars with other ascii values that are not in the print statement as well. I am guessing it is related to the issues we have been discussing though (the possible errata related, etc.).

I did take notes on your implementation though. Gating the code with a flag value cut down a lot of my spurious interrupts. Changing how I managed the buffer itself also helped. Now instead of 2x interrupts per char sent, I get 1x + C, where C=1 for one char and C=2 for more than one char. That is a lot more acceptable.

Maybe in the future I will try and pair it down more.
Ttelmah



Joined: 11 Mar 2010
Posts: 19588

View user's profile Send private message

PostPosted: Fri May 16, 2014 12:13 pm     Reply with quote

The killer one for transmit on this chip is no 52.

When you enter the ISR, you have to poll the buffer empty flag, and verify it is true before you load the character.
Do a #bit define for TRMT, and when you enter the ISR, loop waiting for this to go high before you load the byte.
It interrupts before it can take the byte....

Best Wishes
newguy



Joined: 24 Jun 2004
Posts: 1911

View user's profile Send private message

PostPosted: Fri May 16, 2014 12:26 pm     Reply with quote

TTelmah wrote:
The killer one for transmit on this chip is no 52.


jeremiah wrote:
...my interrupt selection bits are 00 rather than the 01 the errata specifies.


Even though the errata claims that a different transmit mode is suspect, err on the side of caution and add the workaround anyway. I've encountered chips where the errata documentation was similarly "exclusive" in nature, but I've found that in practice it wasn't.

It's a very simple fix - worth trying just to see what happens if nothing else.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group