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 support@ccsinfo.com

PCD putc() help

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



Joined: 24 Feb 2010
Posts: 22

View user's profile Send private message

PCD putc() help
PostPosted: Tue May 11, 2010 9:12 am     Reply with quote

Hi all,

I want to start writing a bootloader for myself so that I will be able to program my PIC over RS485, but I can't get past this simple problem. When I call putc('H'), the PIC doesn't send the character. But, when I call putc('H') twice, it actually sends the character...twice...

I thought that the program doesn't reach the putc command, but the LED connected to AUX_CS actually gets toggled.

Any help with this problem will be appreciated a lot.

I am using version 4.107 of the PCD compiler, with a PIC24HJ64GP504.

Below is my code:

Code:
#define AUX_CS PIN_B6

//===RS485 definitions===\\
#define RS485_TX PIN_C8         //RS485 TX pin
#define RS485_RX PIN_C9         //RS485 RX pin
#define RS485_EN PIN_C7         //RS485_EN = 1 --> RS485 TX Enabled
#define RS485_BAUD 9600         //The RS485 baud rate

#include "main.h"

#define LOADER_END getenv("PROGRAM_MEMORY") - 1
#define LOADER_SIZE 0x7FF   //2kB
#define LOADER_START_ADDR LOADER_END - LOADER_SIZE

#ORG LOADER_START_ADDR,LOADER_END auto=0 default

#pin_select U1TX=RS485_TX
#pin_select U1RX=RS485_RX
#use rs232(UART1,baud=RS485_BAUD,parity=N,bits=8,enable=RS485_EN)

void main()
{
   putc('c');
   output_high(AUX_CS);
}
Gary Smithson



Joined: 13 Feb 2004
Posts: 22

View user's profile Send private message Visit poster's website

PostPosted: Tue May 11, 2010 10:35 am     Reply with quote

The way you have main() written, the PIC is going to sleep before the character is shifted out the shift register. Remember that CCS places a sleep instruction just after main() and if you allow it to end, it will hit the sleep.

Try this:
Code:
void main()
{
   while (TRUE) {
      putc('c');
      output_toggle(AUX_CS);
      delay_ms (1000);
   }
}


Gary
Swys



Joined: 24 Feb 2010
Posts: 22

View user's profile Send private message

PostPosted: Wed May 12, 2010 12:18 am     Reply with quote

Thanks for the answer Gary. I did exactly as you suggested, but it unfortunately did not work. It makes sense what you say about the sleep after main(), but why does the command after the putc('c') (toggling the LED) work? This is quite strange...

It now seems that if I use putc('c') an odd amount of times, it only executes an even amount of times. For example:

Code:
void main()
{
      putc('a');
      putc('b');

      output_toggle(AUX_CS);
}


will execute perfectly, sending both bytes to the PC. However, whenever I do this:

Code:
void main()
{
      putc('a');
      putc('b');
      putc('c');

      output_toggle(AUX_CS);
}


only 'a' and 'b' gets sent to the PC. The same happens even though I put it into a while() loop. Any ideas of how to fix this?
Gary Smithson



Joined: 13 Feb 2004
Posts: 22

View user's profile Send private message Visit poster's website

PostPosted: Wed May 12, 2010 12:41 am     Reply with quote

CCS probably has a bug. If possible I would first try the test as RS232 instead of RS485. In other words remove the enable parameter from #use rs232.

If the PC really does have an RS485 connection you can still remove the enable parameter and just drive the enable signal static active for the duration of the test.

I now remember from years past that a common mistake is to deassert the enable pin before the last character is shifted out the UART. If that happens the character will not be driven on the bus. That may very well be what is happening here depending on how CCS is managing the enable pin.

If that doesn't work I would remove the #org statements and let the program compile in a more natural state.

Hope that helps.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed May 12, 2010 12:48 am     Reply with quote

There is a hidden Sleep instruction at the end of main(). It's placed there
by CCS. Any RS232 (that uses the hardware UART) that is "in progress"
will be shut down when it hits that Sleep instruction. Prevent this by
putting a while(1); statement at the end of main(). Example:
Quote:

void main()
{
putc('a');
putc('b');

output_toggle(AUX_CS);

while(1); // Prevent PIC from going to Sleep.
}
Swys



Joined: 24 Feb 2010
Posts: 22

View user's profile Send private message

PostPosted: Wed May 12, 2010 1:13 am     Reply with quote

Thanks for your suggestions guys. Just before I came to check on the forum again, I tried writing to the UTXREG directly. At first this didn't work, when I thought (as Gary said) that maybe the enable pin doesn't stay high long enough for the byte to get pushed through the MAX3485. And sure enough that was the problem. So, I will be writing my own putc() function for this, toggling the enable pin myself...

Thanks a lot for your help!
Jakesvanzyl



Joined: 12 Nov 2010
Posts: 5

View user's profile Send private message

Same problem
PostPosted: Mon Nov 22, 2010 11:47 pm     Reply with quote

I'm struggling with exactly the same problem. The problem can be fixed in 1 of 2 ways.

1 - Send the last byte twice for example

Code:
      for (I=0;I<Length;I++)  //Data
      {
         fputc (ReturnData[I],RS485);
      }
     
      fputc (15,RS485);      //XOR
      fputc (22,RS485);      //XOR     
      fputc (22,RS485);      //XOR  send the last byte twice

2 - Handle the enable line manually

Code:
     Output_High (Data_Enable_Line);
     for (I=0;I<Length;I++)  //Data
      {
         fputc (ReturnData[I],RS485);
      }
     
      fputc (15,RS485);      //XOR
      fputc (22,RS485);      //XOR     
      delay_ms(1);
      Output_Low(Data_Enable_Line);

The problem with solution 1 is that the protocol gets messed with and devices can get confused because every now and again there is an extra "garbage" byte on the line. The problem with solution 2 is that when the PIC needs to do intensive work sitting around for a ms can cause problems.

Can somebody please help with a solution to this problem?

Regards

Jakes
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Tue Nov 23, 2010 4:04 am     Reply with quote

I'm not yet sure about the nature of the originally reported problem. With the #use rs232 enable option, the send routine is waiting for UxSTA.TRMT to go high before deasserting the enable output. This should be normally sufficient for regular RS485 direction control. It shouldn't be affected by the implicite sleep() at main end.

To understand, what's actually happening, one should inspect the TxD and Enable output lines with an oscilloscope.

I'm using the PIC24 hardware simplex control option instead of the CCS enable feature, because the delay involved with enable is inacceptable for an interrupt driven buffered send routine. The hardware simplex feature apparently works without any problems, but it isn't supported by the PCD built-in functions, it has to be enabled in special function registers. And it needs an additional inverter, because it's active low.
Jakesvanzyl



Joined: 12 Nov 2010
Posts: 5

View user's profile Send private message

PostPosted: Tue Nov 23, 2010 4:54 am     Reply with quote

Thanks for the reply

I have monitored the enable line on the RS485 and it definitely goes low before all the data is out. What is strange about this problem is that it only happens when you have an uneven amount of bytes that you are sending. For example.

putc('c'); - will send no bytes

and
putc('c');
putc('c'); - will send "cc"

and
putc('c');
putc('d');
putc('e'); - will send "cd"

I have tried to manage the enable line in various ways manually. For example I have tried to use the #INT_TBE to pull the enable line down when the TX buffer is empty what is interesting about this is the fact that you have exactly the same problem as before the interrupt happens before all the byte are out which makes me think this might be a Microchip problem and not necessarily a CCS problem.

The implicite sleep() definitely has no effect since my controller does some serious communication work and it is in a constant do while loop.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Tue Nov 23, 2010 5:43 am     Reply with quote

I checked the PCD code with V4.107 and V4.112 and it's apparently evaluating the TRMT bit correctly. So I agree, that it's most likely a PIC24 silicon bug, respectively the operation of TRMT is different from what's said in in the family reference manual. Interestingly, there's apparently no problem when using the UART hardware simplex control option.

It's just a guess, but it may be the case, that TRMT can not be tested in the next instruction after loading the transmit buffer, one could try a short (a few instruction cycles) delay.

The issue may be also device dependant. What's your exact chip and hardware revision?
Jakesvanzyl



Joined: 12 Nov 2010
Posts: 5

View user's profile Send private message

PostPosted: Tue Nov 23, 2010 6:22 am     Reply with quote

My device is a PIC24FJ48GA002 but we have seen the problem on a PIC24HJ64GP504 as well. I'm not sure how to check the hardware revision of the PIC but here is the full code of the PIC as displayed on the device.

PIC24FJ48GA002
-I/SO
101896M

I have tried a delay after the last character is loaded in the TX buffer the problem is the delay required is not "short" anything below 1ms does not work.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Tue Nov 23, 2010 2:39 pm     Reply with quote

I could reproduce your even/odd number of characters observation. But I also found, that a delay before
checking TRMT actually matters.

The original PCD putc() code is equivalent to the below C-code. It shows the same behaviour as described above.
Code:
output_high(ENABLE);
while(U1TXBF);
U1TXREG='c';
while(!U1TRMT);
output_low(ENABLE);

But inserting a single nop delay makes it work correctly.
Code:
output_high(ENABLE);
while(U1TXBF);
U1TXREG='c';
#asm  nop #endasm
while(!U1TRMT);
output_low(ENABLE);


I guess, the delay is necessary, because the character isn't immediately transferred to TSR when loading TXREG.
The existence of a delay is also suggested in Figure 21-4 in the PIC24 family reference manual. So it's not
actually a silicon bug rather than a case of not exactly considering the documented chip behaviour.
Jakesvanzyl



Joined: 12 Nov 2010
Posts: 5

View user's profile Send private message

Thank you
PostPosted: Wed Nov 24, 2010 12:21 am     Reply with quote

Thanks FvM

This has been a great help!
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Wed Nov 24, 2010 10:13 am     Reply with quote

CCS has said, that the problem has been fixed and the next compiler release will contain the correction.
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