Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

dsPIC33FJ64GS606 uart receive interrupt not working properly

Status
Not open for further replies.

raja_rajan

Newbie level 6
Joined
Jul 25, 2016
Messages
12
Helped
1
Reputation
2
Reaction score
1
Trophy points
3
Activity points
129
Hi,
I am using dsPIC33FJ64GS606. UART receive interrupt not working prorperly. while sending data from real term terminal two or three times.

i have get a response message or the specified operation are working after sending the data two or three times.

Here is the code for uart receive.



Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
void __attribute__((interrupt, no_auto_psv)) _U1RXInterrupt( void ) 
{
 
   
   /* Check for receive errors */
    if(U1STAbits.FERR == 1)
    {
    
        buf=U1RXREG;;
        buf=U1STAbits.FERR;
    }
    /* Must clear the overrun error to keep UART receiving */
    if(U1STAbits.OERR == 1)
    {
        U1STAbits.OERR = 0;
        
    }
   
    /* get the data */
  // if(U1STAbits.URXDA ==1)
    {
      rx[count++] = U1RXREG;
    }
    
     R_flag=1;
     
    IFS0bits.U1RXIF = 0; // clear TX interrupt flag  
   
}
 
 
Here is the check receive function.
 
void check_receive(void)
{
     
 
          /* if(U1STAbits.TRMT==1);
           U1TXREG = 'A'; // Transmit one character
           __delay_ms(30);
          */
 
          if((rx[0]=='1')&&(rx[1]=='p')&&(rx[2]=='1')) 
          {
                uart1_send('1');
                uart1_send('p');
             
              
         }
        if((rx[0]=='1')&&(rx[1]=='s'))      //start pwm
         {
 
            PTCONbits.PTEN       = 1;               /* Enable the PWM Module */  
 
            if(rx[2]=='f')
            {  
              forward=1;
              reverse=0;
              //  while(rx[2]=='f')
              //  motor_forward();
            }
            else if(rx[2]=='r')
            {
              reverse=1;
              forward=0;
                //while(rx[2]=='r')
                // motor_reverse();
            }
          
         }
 
        if((rx[0]=='1')&&(rx[1]=='d'))       //stop pwm
         {
            
            PTCONbits.PTEN = 0;                 /* Disable the PWM Module */  
         }
         
       if((rx[0]=='s')&&(rx[1]=='p'))      // speed count
         {
            if(rx[2]=='4')
            speed=0.004;
            if(rx[2]=='5')
            speed=0.005;
            if(rx[2]=='6')
            speed=0.006;
            if(rx[2]=='7')
            speed=0.007;
             if(rx[2]=='8')
            speed=0.008;
            if(rx[2]=='9')
            speed=0.009;
            if((rx[2]=='1')&&(rx[3]=='0'))
            speed=0.010;
         }
 
          
           count=0; 
           rx[0]=0;
           rx[1]=0;
           rx[2]=0;
           R_flag=0;
         
      
     // }
     
}
 
 
Here is the main function
 
 
int main()
{
 
 
/* Configure Oscillator to operate the device at 40Mhz
       Fosc= Fin*M/(N1*N2), Fcy=Fosc/2
       Fosc= 7.37*(43)/(2*2)=80Mhz for Fosc, Fcy = 40Mhz */
 
    /* Configure PLL prescaler, PLL postscaler, PLL divisor */
    PLLFBD=41;              /* M = PLLFBD + 2 */
    CLKDIVbits.PLLPOST=0;   /* N1 = 2 */
    CLKDIVbits.PLLPRE=0;    /* N2 = 2 */
 
 
    __builtin_write_OSCCONH(0x01);          /* New Oscillator FRC w/ PLL */
    __builtin_write_OSCCONL(0x01);          /* Enable Switch */
      
    while(OSCCONbits.COSC != 0b001);        /* Wait for new Oscillator to become FRC w/ PLL */  
    while(OSCCONbits.LOCK != 1);            /* Wait for Pll to Lock */
 
    
 
   //TRISB=0x0000;
    TRISFbits.TRISF2=1;
    TRISFbits.TRISF3=0;
    TRISBbits.TRISB9=1;
    TRISBbits.TRISB10=1;
 //  TRISD=0x00ff;
  // PORTB=0x00ff;
    uart1_init();
  __delay_ms(1000)
    adc_init();
    init_PWM();  
    External_interrupt_init();
  
 //   INTCON1bits.NSTDIS=1;
   
 
 
    uart1_send('p');
    uart1_send('w');
    uart1_send('m');
    
    while(1)                                /* Infinite Loop */
    {
        __delay_us(300)
     
          if(R_flag==1)
          {
           check_receive();
          }
 
          if(forward==1)
          {
            if(C_pwm3<18000)
            motor_forward();
            else{
            PTCONbits.PTEN= 0;   
            C_pwm3=0;
           }
        
          }  
 
          if(reverse==1)
          {
            if(C_pwm3<18000)
            motor_reverse();
            else{
            PTCONbits.PTEN= 0;   
            C_pwm3=0;
           }
          } 
 
  /*        if((flag3==1)||(flag4==1))
          {
             if(flag3==1)
             uart1_send(C_pwm3);
             else
             uart1_send(C_pwm1);
             flag3=flag4=0;
          }
    */
 
  
    }
}

 
Last edited by a moderator:

Part 1: Get the interrupts working.
For a start I'd strip out all of the code other than the parts that set up the oscillator and the UART. Get the Rx ISR begin called reliably every time to begin with.
Unfortunately you do not show us enough code to really help you there. How is the UART initialised? I take it from your comments that the ISR is being called but can you please confirm that.
Also ensure that the variables used in the ISR are all marked as 'volatile'.

Part 2: Using the correct approach.
I think the way you are receiving the characters is flawed. You set the 'R_flag' in the ISR whenever a single character is received. Also the ISR will save the received character int the 'rx' buffer at an offset determined by the 'count' variable.
In the main loop you call the 'check_receive' function whenever the 'R_flag' is set. Regardless of what occurs within the 'check_receive' function, you set the 'count' variable to zero.
Looking at you code, you seem to be looking for a command such as '1p1' or '1s' or 'sp4'.
Now consider what will happen when the 's' (of the 'sp4' command) is received. The ISR will be called and the character saved in 'rx[0]' and the R_flag' set. The main loop will then see the 'R-flag' being set and call the 'check_receive' function.
As the 'check_receive' function goes through the various checks for a command, it will not match any as 'rx[0]' contains 's' but 'rx[1]' will not have received anything yet. Therefore it will set 'count' back to zero and clear the 'rx' array.
Now the 'p' character is received through the ISR and is also saved in 'rx[0]' and the 'R-flag' set. Again this will cause 'check_receive' to be called but again none of the command checks will match and again 'count' will be reset to 0.
Now, you DO have a delay of 300uSec in the main loop. Therefore, if the characters just happen to ALL be received while the main loop is delayed, then your program will work. This explains why it is so unreliable and also why this is totally the wrong approach.
Further, if you are sending characters from some other device (you mention RealTerm presumably on a PC) then it is possible that the characters will not be sent until a line terminator is entered. If that is the case then you need to handle the '\r' (perhaps) and the '\n' characters - and these are the characters that may save you!
If the other device sends characters as they are typed then they MUST all be send within 300uSec and must just happen to have the timing exactly right (as explained above) - my guess is that this would almost never work.

The better approach is to use a ring buffer and always have the ISR add characters to the end of the ring. The main program can then see how many characters are in the ring and perform the command checks.
I would also recommend that you use the '\n' character (assuming it is sent) as a synchronising character. When you see it in the ISR, you can set a flag to show that a complete command has been received. When the main loop sees that flag it can then look to interpret the command from the ring buffer. Whether or not a valid command has been received, you can then clear out the ring buffer knowing that the next character to be received is supposed to be the start of a new command - you are then back in sync with the sending device.
There are many variations on this that you can use.
Susan
 

    V

    Points: 2
    Helpful Answer Positive Rating
Hi,
Here is uart init code.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#define FCY 40000000
#define BAUDRATE 115200
#define BRGVAL ((FCY/BAUDRATE)/4)-1
 
 
unsigned short val=0;
 
void uart1_init()
{
    // configure U1MODE
    U1MODEbits.UARTEN = 0;  // Bit15 TX, RX DISABLED, ENABLE at end of func
    //U1MODEbits.notimplemented;    // Bit14
    U1MODEbits.USIDL = 0;   // Bit13 Continue in Idle
    U1MODEbits.IREN = 0;    // Bit12 No IR translation
    U1MODEbits.RTSMD = 0;   // Bit11 Simplex Mode
    //U1MODEbits.notimplemented;    // Bit10
    U1MODEbits.UEN = 0;     // Bits8,9 TX,RX enabled, CTS,RTS not
    U1MODEbits.WAKE = 0;    // Bit7 No Wake up (since we don't sleep here)
    U1MODEbits.LPBACK = 0;  // Bit6 No Loop Back
    U1MODEbits.ABAUD = 0;   // Bit5 No Autobaud (would require sending '55')
    U1MODEbits.URXINV = 0;  // Bit4 IdleState = 1  (for dsPIC)
    U1MODEbits.BRGH = 1;    // Bit3 16 clocks per bit period
    U1MODEbits.PDSEL = 0;   // Bits1,2 8bit, No Parity
    U1MODEbits.STSEL = 0;   // Bit0 One Stop Bit
 
    U1BRG = BRGVAL; 
    // Load all values in for U1STA SFR
    U1STAbits.UTXISEL1 = 0; //Bit15 Int when Char is transferred (1/2 config!)
    U1STAbits.UTXINV = 0;   //Bit14 N/A, IRDA config
    U1STAbits.UTXISEL0 = 0; //Bit13 Other half of Bit15
    //U1STAbits.notimplemented = 0; //Bit12
    U1STAbits.UTXBRK = 0;   //Bit11 Disabled
    U1STAbits.UTXEN = 0;    //Bit10 TX pins controlled by periph
    U1STAbits.URXISEL = 0;  //Bits6,7 Int. on character recieved
    U1STAbits.ADDEN = 0;    //Bit5 Address Detect Disabled
 
    IFS0bits.U1RXIF = 0;  
    IEC0bits.U1RXIE=1;          // Enable UART RX Interrupt
    IPC2bits.U1RXIP=6;
    U1MODEbits.UARTEN = 1;      // Enable UART
    U1STAbits.UTXEN = 1;        // Enable UART TX
 
}
 
void uart1_send(unsigned char Tx_data)
{
 
    /* wait at least 8.6usec (1/115200) before sending first char 
    
    if(val==0)
    {
        for(i = 0; i < 350; i++)
        {
          Nop();
        }
      val=5;
    } 
*/
    if(U1STAbits.TRMT==1);
    U1TXREG = Tx_data; // Transmit one character
  /*  if(U1STAbits.TRMT==1);
    U1TXREG = Tx_data; // Transmit one character
    if(U1STAbits.TRMT==1);
    U1TXREG = Tx_data; // Transmit one character
*/
}

 
Last edited by a moderator:

As Aussie Susan already mentioned, the problem of your code seems to be not an incorrect UART initialization. It's the bad coordination between receive interrupt function and processing of buffered data in the main loop. It can e.g. happen that the first character triggers the R_flag semaphore, then check_receive fails, deletes the buffer and resets R_flag.
 

The only thing I'd say about that UART initialisation code is I have only once ever seen a good reason to alter the priority of the interrupt away from the default value of 4.
The receive ISR is quite short (which is a good thing) and so even if there are other interrupts occurring there should be very little timing interactions between then that would justify preemptive ISRs (unless they were really badly written with delays and bloking code in them).
Susan
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top