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

CN Interrupt problem

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



Joined: 15 Jun 2016
Posts: 33

View user's profile Send private message

CN Interrupt problem
PostPosted: Wed Jan 25, 2017 9:53 am     Reply with quote

Hi,

I have two PIC's dsPIC33fj256MC710A's talking to each other over rs232

Compiler version: V4.078

What I'm trying to do is:
PIC1:
When encoder reaches predetermined positions:-
* Send read pulse from PIC1 to PIC2 & Send encoder position

PIC2:
* When CN interrupt triggered, read adc straight away to get closest reading to required encoder position
* Decode position
* Send encoder position and adc reading to PC

Much of the day has been trying to solve what was another bug, I think which was a stack overflow problem and it was receiving the encoder value, sending first few chars out then just noise like wrong baud rate. When I debugged it, the PC was at line one each time I tried to receive and send.
I had several nested functions with the final having a printf with a float in it. I am now using a flag to perform the function in main and not in the ISR.
So after much reading of this forum, I've resolved that thanks!

Initially I was doing this just fine by polling in the main loop, but thought I would try using interrupt for my first time, which isn't going so well..

If I have the SAMPLE_SYNC if section un-commented then I can receive encoder position just fine and send out adc value, hardcoded currently to reduce code size. If I swap over and use the cn interrupt instead of the main if(SAMPLE_SYNC) I get an overrun error.
I have included the ERRORS keyword in #use rs232, to try and automatically clear them, but this has not helped.

Code:
setup()
{
   set_tris_c(0xFFFF);      // all inputs
   CNPU2=0x0020;            // Enable weak pull-up on CN21 as connected with U2RX   
   //enable_interrupts(INTR_CN_PIN | PIN_C13);
  // enable_interrupts(INTR_GLOBAL);


}

#int_CNI
void CCNI_Interrupt()   // motion board sends pulse to read adc
{
   if(SAMPLE_SYNC == 1)   // make sure it was rising edge on CN1
   {
      interruptFlag = true;
   }
   CNIF = 0; // Clear CN interrupt flag
}

void main()
{
   setup();

   printf("\r\n\Running...\r\n");

     while(true)
       {
      if(SAMPLE_SYNC == 1)   // make sure it was rising edge on CN1
      {
         interruptFlag = true;
      }

      if(interruptFlag == true)
      {
         //readAdc();
         decode_enc_rs232();
         interruptFlag = false;
      }

   }
}

I've been looking at this for a day and a half and can't see the wood for the trees!
Can anyone point me in the right direction please?
Thanks in anticipation! Very Happy Crying or Very sad
temtronic



Joined: 01 Jul 2010
Posts: 9229
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Jan 25, 2017 10:38 am     Reply with quote

this...
decode_enc_rs232();

could be the killer...
I don't know what's inside it !

ISR mantra...
short and fast !!

ONLY set flags within all ISRs....

Do NOT use delays of any kind
Do NOT use prints of any kind
Do NOT use ANY maths,especially FP
Do NOT use any 'functions'...

if decode_enc_rs232(); is more than 3 lines long, it'll kill the ISR.
also some(most) interrupts automatically clear their own interrupt,though you may have to read a port( check the datasheet !)

Jay
ccsfred



Joined: 15 Jun 2016
Posts: 33

View user's profile Send private message

PostPosted: Wed Jan 25, 2017 10:52 am     Reply with quote

Hi Jay,

Thanks for comments, I've included decode_enc_rs232(); below for reference, I was trying to keep post short.

I am using the ISR to set the interruptFlag, then handling the rest in the main loop... is not right?

Code:
void decode_enc_rs232()
{
   uint8_t i = 1;
   
   long timeout =0;

   fprintf(USB,"d");
   
   // Check for receive errors
   if(U2FERR == 1)
   {
      fprintf(USB,"Receive errors\n\r");
      continue;
   }

   // Must clear the overrun error to keep UART receiving
   if(U2OERR == 1)
   {
      U2OERR = 0;
      fprintf(USB,"Overrun error\n\r");
      continue;
   }

   if(U2RXDA)   // data available
   {
      RxBufEnc[0] = U2RXREG;      // read initial char
      if(RxBufEnc[0] == 0x64)      // if encoder message
      {
         while ((RxBufEnc[i-1] != 0x0D) && (timeout<50000))   // continue to read until "\r"
         {            
            if(U2RXDA)      // data available
            {   
               RxBufEnc[i] = U2RXREG;   
               i++;
            }
            else
            {
               delay_us(2);   
               timeout++;      
            }
         }
         j=0;
         // take "d" off
         for(i=1; i<8; i++)
         {
            if((RxBufEnc[i] != 0x0A) || (RxBufEnc[i] != 0x0D))   // ignore LF & CR
            {
               value[j] = RxBufEnc[i];
               j++;
            }
         }
         encoder = atoi(value);

         fprintf(USB, "e%d  B%1.4f \n\r", encoder, adcVoltage[chToRead]);

      }
      else
      {
         return;
      }
   }
}


Note: I changed over to using the registers to rule out any compiler issues...
I was finding the fprintf with the float was attributing to the stackoverflow error I previously had.
And I'll look into the interrupt clearing, thanks.
newguy



Joined: 24 Jun 2004
Posts: 1908

View user's profile Send private message

PostPosted: Wed Jan 25, 2017 11:02 am     Reply with quote

I've been using a very similar chip, the dsPIC33FJ256GP710A, for ~5 years now. I had real trouble with v4.099 which forced me to migrate to v4.141 at the time. I've stuck with v4.141 since then. I have to say that even v4.141 doesn't properly support the processor but I've written so many different "low level" drivers that I'm reluctant to upgrade to v5.

With that said, I have grave reservations about v4.078. What I'm wondering is what % of strange things you're fighting is the compiler, your code, or compiler support for chip peripherals not being what you think it is.

I'd recommend upgrading your compiler if you have the funds for it.
ccsfred



Joined: 15 Jun 2016
Posts: 33

View user's profile Send private message

PostPosted: Wed Jan 25, 2017 11:12 am     Reply with quote

Thanks for your comments newguy, I have suggested we upgrade, the device header I have isn't even for the 'A' version of the chip, you could be onto something.. I have had numerious funny goings on and as you say have written my own "low level" drivers.
Thanks! Smile
temtronic



Joined: 01 Jul 2010
Posts: 9229
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Jan 25, 2017 11:15 am     Reply with quote

sigh, guess I need TRIfocals now..I have to remove my glasses when at keyboard, put them on to do board work/read real books, on to driver see across the room. This getting old ain't fun....it looked to me that the decode_enc_rs232(); was in the ISR, my mistake.
Ttelmah



Joined: 11 Mar 2010
Posts: 19520

View user's profile Send private message

PostPosted: Wed Jan 25, 2017 12:56 pm     Reply with quote

The obvious thing is the interrupt enables are both remarked out....

Also you always need to read the pin in the interrupt or the flag cannot be cleared (you don''t need to do this yourself, the compiler automatically does this, unless you tell it not to), but neither will work if the pin has not been read.

As another comment added later, you almost certainly need to enlarge the stack. Printf's in particular use a lot of stack. #build stack=512
ccsfred



Joined: 15 Jun 2016
Posts: 33

View user's profile Send private message

PostPosted: Thu Jan 26, 2017 2:32 am     Reply with quote

Thanks Ttelmah for your reply!

I've been swapping over between using the interrupt, unremarking the:

Code:
//enable_interrupts(INTR_CN_PIN | PIN_C13);
// enable_interrupts(INTR_GLOBAL);


thus enabling the interrupt & remarking:

Code:
      if(SAMPLE_SYNC == 1)   // make sure it was rising edge on CN1
      {
         interruptFlag = true;
      }


to test that it's still receiving ok from the other PIC and it is only the interrupt that is causing the issue.

I'm reading the pin in the interrupt, SAMPLE_SYNC is defined as:

Code:
#define SAMPLE_SYNC input(PIN_C13)


so I don't need to clear the interrupt flag myself then?:

Code:
CNIF = 0; // Clear CN interrupt flag


I've now increased the stack size to 1024, with my version I had to use brackets around:

Code:
#BUILD (STACK=1024)


and I can see the size changing in the sym file, something else I've learnt!

Unfortunately the problem still exists, when the pin is checked in the main it reads the other PIC just fine everytime, comment that out, uncomment the enable interrupt lines and doesn't work. It is going into the ISR ok and into my decode_enc_rs232 function, I'm trying to debug further, but can't see the data available but changing U2RXDA low (U2STA bit 0 is low) in the watch window (with a PICkit3) when its working or not... When using the interrupt, after the first interrupt it does have overrun error U2OERR high. It does seem that the interrupt is messing with the UART somehow.
ccsfred



Joined: 15 Jun 2016
Posts: 33

View user's profile Send private message

PostPosted: Thu Jan 26, 2017 2:39 am     Reply with quote

If I comment out the overrun check and clear section:

Code:

/*   // Must clear the overrun error to keep UART receiving
   if(U2OERR == 1)
   {
      U2OERR = 0;
      fprintf(USB,"Overrun error\n\r");
      continue;
   }
*/


I do get a successful read the second time, and the second time only!
ccsfred



Joined: 15 Jun 2016
Posts: 33

View user's profile Send private message

PostPosted: Thu Jan 26, 2017 4:10 am     Reply with quote

Well... I've got it working now, haven't solved why the CN interrupt was breaking the serial.
I've now used a serial interrupt, and in the ISR I get the chars and put into a software buffer (based on example EX_SISR.C), sets a flag for the CN interrupt handler in the main, which then sends out the encoder value and adc value.

Code:
#include "CD91493.h"
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#define SAMPLE_SYNC input(PIN_C13)
#define BUFFER_SIZE 32

bool interruptFlag = false;
bool readyToSendOut = false;
uint8_t j = 0;
int32_t encoder =0;
char value [10];
float adcVoltage[10] ={0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00};
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;


void getEncoderReading()
{
   int i;
   j=0;

   if(buffer[0] == 0x64)      // if encoder message
   {
      // take "d" off
      for(i=1; i<8; i++)
      {
         if((buffer[i] != 0x0A) || (buffer[i] != 0x0D))   // ignore LF & CR
         {
            value[j] = buffer[i];
            j++;
         }
      }
   
      encoder = atoi(value);
      readyToSendOut = true;
   }
   else
   {
      fprintf(USB,"Encoder recieve error\n\r");
   }
}

#int_rda2
void serial_isr()
{
   int t, i, j;
   next_in = 0;

   for(i=0; i<BUFFER_SIZE; i++)               // clear buffer out
   {
      buffer[i] = 0x00;
   }

   while(buffer[next_in-1] != 0x0D)            // while not CR
   {
      buffer[next_in]=fgetc(ENC);            // get char and put in buffer
      t=next_in;                              // t = 0
      next_in=(next_in+1) % BUFFER_SIZE;      // when next_in = 31, the modulus of BUFFER_SIZE wil be 0
      if(next_in==next_out)                  // so here 0 = 0
        next_in=t;                             // Buffer full
   }
   getEncoderReading();
}


setup()
{
   set_tris_c(0xFFFF);      // all inputs
   CNPU2=0x0020;            // Enable weak pull-up on CN21 as connected with U2RX   

   enable_interrupts(INTR_CN_PIN | PIN_C13);
   enable_interrupts(int_rda2);               // UART2
   enable_interrupts(INTR_GLOBAL);
}

#int_CNI
void CCNI_Interrupt()   // motion board sends pulse to read adc
{
   if(SAMPLE_SYNC == 1)   // make sure it was rising edge on CN1
   {
      interruptFlag = true;
   }
}

void main()
{
   char string[30];
   setup();

   printf("\r\n\Running...\r\n");

     while(true)
   {
      if(interruptFlag == true)
      {
         //readAdc();
         
         while(!readyToSendOut);   // wait until string recieved from the motion board

         fprintf(USB, "e%d  B%1.4f \n\r", encoder, adcVoltage[0]);
         
         interruptFlag = false;
      }
   }
}


Any comments to improve my code greatly appreciated!
Thanks for your help!
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