View previous topic :: View next topic |
Author |
Message |
Swys
Joined: 24 Feb 2010 Posts: 22
|
PCD putc() help |
Posted: Tue May 11, 2010 9:12 am |
|
|
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
|
|
Posted: Tue May 11, 2010 10:35 am |
|
|
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
|
|
Posted: Wed May 12, 2010 12:18 am |
|
|
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
|
|
Posted: Wed May 12, 2010 12:41 am |
|
|
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
|
|
Posted: Wed May 12, 2010 12:48 am |
|
|
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
|
|
Posted: Wed May 12, 2010 1:13 am |
|
|
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
|
Same problem |
Posted: Mon Nov 22, 2010 11:47 pm |
|
|
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
|
|
Posted: Tue Nov 23, 2010 4:04 am |
|
|
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
|
|
Posted: Tue Nov 23, 2010 4:54 am |
|
|
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
|
|
Posted: Tue Nov 23, 2010 5:43 am |
|
|
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
|
|
Posted: Tue Nov 23, 2010 6:22 am |
|
|
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
|
|
Posted: Tue Nov 23, 2010 2:39 pm |
|
|
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
|
Thank you |
Posted: Wed Nov 24, 2010 12:21 am |
|
|
Thanks FvM
This has been a great help! |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Wed Nov 24, 2010 10:13 am |
|
|
CCS has said, that the problem has been fixed and the next compiler release will contain the correction. |
|
|
|