|
|
View previous topic :: View next topic |
Author |
Message |
apakSeO
Joined: 07 Dec 2016 Posts: 60 Location: Northeast USA
|
UART sending last byte first? |
Posted: Fri Mar 31, 2017 1:53 pm |
|
|
MPLAB X 3.4
PIC24FJ256GB210
CCS v. 5.070
The goal: send an arbitrary length array of bytes, stored in contiguous memory in the PIC, out the UART TX pin.
In this example code, I have a pre-defined 9-byte word and put it into a char array. When a button is pressed, I want to send this out the UART's TX pin. I read almost everything I could find on this forum with 'rs232' to get an example of interrupt-driven UART, and used code examples from forum user Ttelmah; this helped a lot but I am still unable to send usable data.
The code:
Code: |
#include <24FJ256GB210.h>
#fuses NOWDT,NOWRT,NOPROTECT
#device PIC24FJ256GB210 ICD=TRUE
#use delay(INTERNAL=8MHz, CLOCK=32MHz) // Checked clock output on REFO; 32MHz observed
// Maps hardware UART to PPS pins
#pin_select U1TX=PIN_F2
#pin_select U1RX=PIN_F3
// Unfortunately below line returns errors if MAX_ERROR < 9
#use rs232(BAUD=921600, BRGH1OK, MAX_ERROR=9, UART1, XMIT=PIN_F2, RCV=PIN_F3, PARITY=N, BITS=8, STOP=1, TXISR, TRANSMIT_BUFFER=32, STREAM=uart1, ERRORS)
unsigned char testBuff1[] = {0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD, 0xEF, 0xA1, 0xB2};
unsigned char testBuff1_L = 9;
void main(void)
{
enable_interrupts(GLOBAL);
// First tested with normal I/O, PIC24 running on 3.3V. Works. Scope is clean.
// Set rs232 UART pins on port F to be open-drain. Pull to 1.8V. Works. Scope is clean.
set_open_drain_f(0b0000000000001100);
/* In the 'real' code version, testBuff1[] is assembled & ready, as is testBuff_L */
while(1){
if(!input(PIN_B7)){ // Quick n dirty debounce for send testBuff1
delay_ms(10);
if(!input(PIN_B7)){
enable_interrupts(INT_TBE);
delay_ms(10);
}
}
}//while(1)
}//main()
#INT_TBE
void serial_isr(void)
{
static int8 bcnt = 0;
putc(testBuff1[bcnt++]);
if( bcnt == testBuff1_L )
{
disable_interrupts(INT_TBE);
bcnt = 0;
}
}
|
This results in the following output on the UART1 TX pin:
>> Why is the last byte in testBuff1[] being sent first? It isn't an endian-ness thing, as all other bytes are in correct order.
>> If I increase the number of elements in testBuffer1[] to 13, then I get mostly garbage followed by some real data from testBuffer1. In that case, my data is set to
Code: |
unsigned char testBuff1[] = {0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD, 0xEF, 0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6};
unsigned char testBuff1_L = 13;
|
and generates:
I realize that the reason for the initial garbage bytes out of the UART is **probably** due to the fact that I neglect to 'wait' for the hardware buffer, but I am not sure how or where to put this 'wait' functionality. I also have tried to figure out how ex_stisr.c works but it doesn't appear to me there is a 'wait' functionality implemented there, either. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Fri Mar 31, 2017 2:12 pm |
|
|
You are mixing two ways of working.
You are enabling the compiler TX buffering _and_ your own. The compiler TX buffering is turned on by the TX_ISR flag in the #USE RS232. This code is executed in front of your own code.
You don't need to specify pins in the #use rs232.
Your #use just needs:
Code: |
#use rs232(BAUD=921600, BRGH1OK, MAX_ERROR=9, UART1, PARITY=N, BITS=8, STOP=1, STREAM=uart1, ERRORS)
|
This then will use _your_ buffer code.
Alternatively, get rid of your buffer code, and just printf directly. The compiler will then automatically buffer for you.
Also you should be using the stream name and fputc, otherwise if you use a second UART things will go wrong. |
|
|
apakSeO
Joined: 07 Dec 2016 Posts: 60 Location: Northeast USA
|
|
Posted: Fri Mar 31, 2017 3:25 pm |
|
|
Ttelmah wrote: | You are mixing two ways of working.
You are enabling the compiler TX buffering _and_ your own. The compiler TX buffering is turned on by the TX_ISR flag in the #USE RS232. This code is executed in front of your own code.
You don't need to specify pins in the #use rs232.
Your #use just needs:
Code: |
#use rs232(BAUD=921600, BRGH1OK, MAX_ERROR=9, UART1, PARITY=N, BITS=8, STOP=1, STREAM=uart1, ERRORS)
|
This then will use _your_ buffer code.
Alternatively, get rid of your buffer code, and just printf directly. The compiler will then automatically buffer for you.
Also you should be using the stream name and fputc, otherwise if you use a second UART things will go wrong. |
Ah yes, OK, that worked for eliminating the last-byte-first issue. Thanks again, Ttelmah. I'll move on to experimenting more with this code, because for buffer lengths <= 13 my bytes are decoded correctly, but when the buffer > 14 or so I'm getting a strange off-time pulse or missing stop bit. For example,
Code: |
unsigned char testBuff1[] = {0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD, 0xEF, 0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, 0x93};
unsigned char testBuff1_L = 20;
|
generates what appears to be a bad pulse after byte 0xF6, as if the stop bit is missing
Zoomed out a little:
I traced this behavior to UART baud rate. Scope is set to 921600 baud, but the UART is transmitting at 1Mbps, so when enough bytes are written, eventually the offsets are causing misreads. Calculations for U1BRG come out to 3.340 but the compiler must set this to 3 ( must be an int ) To achieve this bit rate, BRGH must be set to 1. I check this in the generated *.lst and see this:
BRGH lives at address 0x0220, bit3
If I'm reading this right, BRGH is set to 0 instead of 1 in the *.lst output. So that's confusing because I'm nearly achieving the baud rate I desire but not quite sure how it could be (nearly) working |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Fri Mar 31, 2017 3:40 pm |
|
|
OK, with 'RS-232' aka serial communications you MUST have less than 3% difference in the baud rates between the two devices. 921600 and 1000000 is too far apart! That does explain why you 'lose' after a few bytes.
One easy way to get accurate baudrates is to use a clock xtal like 2.457600. Check the datasheet section on UART and there should be a chart of baud rates/xtals/ error rates. Find a xtal that gives you 0% error.
Jay |
|
|
apakSeO
Joined: 07 Dec 2016 Posts: 60 Location: Northeast USA
|
|
Posted: Fri Mar 31, 2017 3:50 pm |
|
|
temtronic wrote: | OK, with 'RS-232' aka serial communications you MUST have less than 3% difference in the baud rates between the two devices. 921600 and 1000000 is too far apart! That does explain why you 'lose' after a few bytes.
One easy way to get accurate baudrates is to use a clock xtal like 2.457600. Check the datasheet section on UART and there should be a chart of baud rates/xtals/ error rates. Find a xtal that gives you 0% error.
Jay |
Makes sense.
If I use a 14.7456MHz crystal with the PIC24's 2x PLL, I get 29.4912MHz which 921600 goes into exactly 32 times. So should, in theory, get almost zero baud rate error.
I've only used the PIC's PLL for USB clock generation and also only have ever used the PLL at 4x. I will experiment with using external crystal source and PLL x2 soon.
Thanks for your help, greatly appreciated. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Fri Mar 31, 2017 6:42 pm |
|
|
Interesting tidbit your 14.7456 xtal is 6x my 2.4576 xtal! I used the 2.4576 30 years ago to get a stable 24Hz clock needed to send data serially 15 miles through copper wires. The RC clock wasn't stable (accurate), would vary over temperature..so the 'end units' lost communications. |
|
|
apakSeO
Joined: 07 Dec 2016 Posts: 60 Location: Northeast USA
|
|
Posted: Sat Apr 01, 2017 10:26 am |
|
|
temtronic wrote: | Interesting tidbit your 14.7456 xtal is 6x my 2.4576 xtal! I used the 2.4576 30 years ago to get a stable 24Hz clock needed to send data serially 15 miles through copper wires. The RC clock wasn't stable (accurate), would vary over temperature..so the 'end units' lost communications. |
Awesome! 24Hz and 15 MILES of copper?! What were the driver's characteristics for this scheme? I can't imagine the capacitive load this must have presented. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Sat Apr 01, 2017 11:26 am |
|
|
I'd have expected the compiler to warn if the error was that large. Must be right on the borderline of warning.
Increasing the master oscillator frequency should reduce the error.
Even with BRGH set to 1, the oscillator to feed the UART is 1/4 Fcy.
I used to use 3.84MHz on one of my first PIC boards for exactly the same reason.
Normally it's worth being aware that the very flexible PLL on the PIC24 may allow a frequency to be selected that may help, even from the internal oscillator. However the clock is much more restricted on this chip because of the USB. This forces certain selections onto the PLL, and because of this the chip doesn't give as many selections as many other chips.
If you want to run USB, you can't use a crystal like 14.756MHz. |
|
|
|
|
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
|