UART configuration with set_baud_rate()

Technical questions regarding the XTC tools and programming with XMOS.
psebastiani
Member++
Posts: 29
Joined: Wed Oct 02, 2013 4:20 pm

UART configuration with set_baud_rate()

Post by psebastiani »

Dear all,
I use an XL-216 processor with "lib-uart 3.1.0" to implement a single UART interface.
The default configuration of the UART is 115200 and the program work fine, transmit and receive without error.
During the execution program I want to change the speed of the UART to 56700, but after that I lost the communication with the host (host uart correctly changed at 57600 after the switch on xcore).
I need to change the speed in TX and RX.
I try to simplify and compact the code:

Code: Select all

...
int main (void) {
  ...
  interface uart_rx_if i_rx;
  interface uart_tx_if i_tx;
  input_gpio_if i_gpio_rx[1];
  output_gpio_if i_gpio_tx[1];
  uart_config_if i_UART_config;
  ...
  par {
     on tile[0]: output_gpio(i_gpio_tx, 1, p_uart_tx, null);
     on tile[0]: uart_tx(i_tx, i_UART_config, UARTBAUDRATE, UART_PARITY_NONE, 8, 1, i_gpio_tx[0]);
     on tile[0].core[0] : input_gpio_with_events(i_gpio_rx, 1, p_uart_rx, null);
     on tile[0].core[0] : uart_rx(i_rx, null, RX_BUFFER_SIZE, UARTBAUDRATE, UART_PARITY_NONE, 8, 1, i_gpio_rx[0]);
     on tile[0]: {
            Function1(); 
            MainUARTcomunication(i_tx, i_rx, i_UART_config);
     }
  }
}
...
void MainUARTcomunication(client uart_tx_if uartTX, client uart_rx_if uartRX, client uart_config_if uart_cfg) {
  ...
  while(1) {
    ...
    Function2();
    ...
    if (event) {
        uart_cfg.set_baud_rate(BaudRate); //Change the baud rate
      }
    ...
  }
}  
Any idea?
I also tried with the definition of another "uart_config_if" interface for the RX tread and call twice set_baud_rate, but it don't work:

Code: Select all

...
int main (void) {
  ...
  interface uart_rx_if i_rx;
  interface uart_tx_if i_tx;
  input_gpio_if i_gpio_rx[1];
  output_gpio_if i_gpio_tx[1];
  uart_config_if i_UART_config;
   uart_config_if i_UART_RX_config;
  ...
  par {
     on tile[0]: output_gpio(i_gpio_tx, 1, p_uart_tx, null);
     on tile[0]: uart_tx(i_tx, i_UART_config, UARTBAUDRATE, UART_PARITY_NONE, 8, 1, i_gpio_tx[0]);
     on tile[0].core[0] : input_gpio_with_events(i_gpio_rx, 1, p_uart_rx, null);
     on tile[0].core[0] : uart_rx(i_rx,i_UART_RX_config, RX_BUFFER_SIZE, UARTBAUDRATE, UART_PARITY_NONE, 8, 1, i_gpio_rx[0]);
     on tile[0]: {
            Function1(); 
            MainUARTcomunication(i_tx, i_rx, i_UART_config, i_UART_RX_config);
     }
  }
}
...
void MainUARTcomunication(client uart_tx_if uartTX, client uart_rx_if uartRX, client uart_config_if uart_cfg, client uart_config_if uart_RX_cfg) {
  ...
  while(1) {
    ...
    Function2();
    ...
    if (event) {
        uart_cfg.set_baud_rate(BaudRate); //Change the tx baud rate
        uart_RX_cfg.set_baud_rate(BaudRate); //Change the rx baud rate
      }
    ...
  }
}  
What's wrong?
Regards
Piero


User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

Hi Piero. Does your code work if you start the XMOS IP @ 57600 (instead of 115200)? If no, then share details on the UART clock value for this IP. We recall that for best UART framing, you are required to feed the XMOS IP an external clock of 1.8432 Mhz (3v3 swing) or suitable multiple of this clock value into a free single bit port. Then allow for your UART IP to make use of this external clock source for accurate framing of the UART traffic (send / receive). With this clock value, you should be able to frame all of the PC standard baud rates (115200...9600, etc.). So the issue could be the UART reference clock which is not accurate for 57600 bps framing or there is an issue with the XMOS code during your runtime switching. You could measure the bit width of the traffic @ 57600 bps on the XMOS device and compare to the PC UART.
psebastiani
Member++
Posts: 29
Joined: Wed Oct 02, 2013 4:20 pm

Post by psebastiani »

Hi mon,
I'll be very luky to use 115200 baud rate for first!
You are right, if I start the program with default baud rate set to 57600 or other speed and UART communication don't work. I measure the bit width of the XMOS Tx traffic and it is about 110kHz always! If I set another baud rate the bit frequency don't change.
It's very strange that the that bit frequency don't change. If I set any speed, the UART comunicate with the PC-host at 115200. Why? I haven't possibilities to change the frequency in single UART comunication?
I use a single UART (No multi-UART) and I have no idea how "lib_uart" calculate the physical uart clock(and then the bit frequency). The only clock I supplied to XMOS is the system clock.
I use 25.0MHz external clock generation for the XL216 and I set the opration frequency to the ".xn" file:

Code: Select all

...
<Nodes>
	<Node Id="0" InPackageId="0" Type="XS2-L16A-512" Oscillator="25MHz" SystemFrequency="500MHz">
		<Boot>
...
If I change this clock I can solve the problem?
I should use a 14.7456MHz clock wich is multiply of 1.8432MHz and included in the frequency range that the XCORE PLL accept (4-25MHz). It's right?
In this case, I also set the system frequency to 500MHz?
My goal is to use all the standard baud rate (from 9600 to 115200) changed dynamically by software command. It's not necessary but if works, I also want to use 230400 and 460800 baud.
Regards
Piero
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

Hi Piero.

1) The UART external clock is independent to the CPU clock. That is, you are free to use any external clock (3v3 swing) and within the limits of the XMOS datasheet but this external clock will be used solely to clock your UART IP. Based on the XMOS rules, you MUST use a free single bit port to feed this external clock source into your XMOS IP.

2) Yes, agree that you could use 14.7456 Mhz for up to 921k support.

3) I recall coding some XMOS IP that would bit bang out even the PC baud rates using the 100 Mhz CPU clock but since you are using the XMOS supplied IP, consider to apply an external clock oscillator. They are fairly low cost and practical.

Perhaps lacking in the documentation but the single UART IP does not appear to list the requirement of this external clock oscillator but the multi-uart IP does. Do apply this external clock source and test away. First idea is to make use of this external clock -> select 115200 and check the bit width. Does it frame ok? Then proceed to configure for 57600 bps, etc.

To boost your confidence, see here:

https://www.xmos.com/support/boards?product=15828

This slice board is fitted with an external clock oscillator @ 1.8432 Mhz but as noted, you are free to consider multiples of this value for even higher data rates. We have used 14.7456 Mhz for the past 15+ years of our designs of PC adapters.

Image

Please do post your results so others can benefit from this review.
psebastiani
Member++
Posts: 29
Joined: Wed Oct 02, 2013 4:20 pm

Post by psebastiani »

Hi Mon,
Thanks for your answer.
At the moment I have some problem to add an external clock, because I'm working in own custom board. I can try it but it's difficult for me to add definitely on the board.
Also I have some questions:

a) The clock that I shoud apply externally(14.7456MHz for 921.2kbaud, 1.8432 for 115.2kbaud), must be 16x greather than the maximum baud rate used? Why?

b) In the single UART transmit/receive function there isn't a "clock" parameter like in the multi-uart (4th parameter):

Code: Select all

void uart_rx(server interface uart_rx_if i_data, server interface uart_config_if ?i_config, const static unsigned buffer_size, unsigned baud, enum uart_parity_t parity, unsigned bits_per_byte, unsigned stop_bits, client input_gpio_if p_rxd)

void multi_uart_rx(streaming chanend c, server interface multi_uart_rx_if i, in buffered port:32 p, clock clk, size_t num_uarts, unsigned clock_rate_hz, unsigned baud, enum uart_parity_t arity, unsigned bits_per_byte, unsigned stop_bits)
I should declare multi-uart and use only one?

c) Can I use a dedicate thread to generate this clock? Output from one free pin and input to another. Obviosly the frequency is not exact, but it's in the tolerance; I think. With 100MHz frequency core: 1.8518MHz instead of 1.8432MHz with an error of about 1%.

d) I also have another choise: come back to "sc_uart" inline library(module_uart_rx module_uart_tx), I used them with older XMOS processor and I never had this kind of problem. This modules works on XL216 core?

Regards
Piero
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

@Piero,

apply the following line to replace the similar line in your code:

Code: Select all

// Configure the UART to 9600 BAUD
uart_tx_cfg.set_baud_rate(9600);
Your code has:

Code: Select all

uart_cfg.set_baud_rate(BaudRate); //Change the tx baud rate
For now, do not bother to switch to the multi-uart IP nor the use of the external clock. This single UART IP should work from the 100 Mhz CPU clock (without external clock reference for the UART IP).

The reason for the 16x clock is to allow for the internal UART state machine to sample up to 16x of the bit level on the UART line to be sure the logic level is "1" or "0". Some modern UARTs now only perform 4 samples per clock bit for the same task.
psebastiani
Member++
Posts: 29
Joined: Wed Oct 02, 2013 4:20 pm

Post by psebastiani »

Hi Mon
I have explicited 9600 in the "set_baud_rate()" function, but it don't work well.
Now if I change the baudrate at the start of the XMOS IP, it work fine for any speed frequencies. The error explain in the previous post was that to effective change the baudrate at the start of XMOS IP I must first "clean" the project and then "build".
But if I change the baudrate during the execution (for example change from 115200 to 9600), I receive correct data @9600 but if I send anything the XMOS IP don't receive correct data, and after any sends saturate the receive buffer. I see that: I send 6 byte @9600 and the XCORE IP receive about 30 incorrect byte!
I suppose that it's receiving at a different speed. Why? The PC host send data @9600; I verified that with the oscilloscope.
I have also a question:
When I change the speed with "set_baud_rate()" function, I must set only for RX or TX clients, or for together? I set all three options (TX, RX, TX+RX) but the behavior is the same explained before.
Regards
Piero
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

@Piero,

1) based on your comments, believe you are breaking the supplied UART IP with the modifications

2) start with the original XMOS UART IP and see if the hard coded UART @ 9600 bps can sustain the streaming data from the host PC. If yes, then reverse the data flow and allow for the XMOS IP to send out streamed data @ 9600 bps to the host PC. If again working, then test bidirectional flow @ 9600 bps. This data rate is quite slow and therefore the XMOS IP should be fine to support this speed without data loss.

3) Keep in mind that the UART IP is without data flow control. Often hardware flow control lines (such as RTS & CTS on the PC UART model) are used to inform the other party that the buffer is about to be over flowed so stop sending me data while I digest the received data. Using this mechanism, both parties on the UART interface can prevent data loss. However, do not believe this UART IP from XMOS offers hardware flow control support. Another version we recall did have this so check around if this is desirable. Right now, you have only TX & RX pins and it is expected that the host will not saturate the XMOS buffers and vice versa.

4) Given that this IP is advertised to support upto 10 Mbps, believe the XMOS IP can sustain high data rates without issues. Keep in mind that, when properly coded, the XMOS IP is the next best thing to using FPGA technology. Respectively, only as strong or as weak as the coded UART IP. For this reason, what is the host PC UART ? Perhaps a USB to UART dongle @ 3v3 swing? Maybe FTDI or Silicon labs based? Either way, start your testing @ 9600 bps and then shift to 115200 (still using hard coded baud rate values) and see if both sides can keep up without data loss and without hardware flow controls.

Only after you are confident that the IP is working, then proceed to tweak the code to allow for dynamic baud rate changes. We have not yet experimented with this code but it should be possible to modify for your requirement. Our guess is that the other routines inside the par construct needs to be inspected. Keep in mind that each line inside the par construct will launch another thread of execution. Think of this as a single and dedicated microcontroller running each line of code shown inside the par construct. So from what we see, you have altered a single microcontroller's operation. You will need to review each line of the parallel (par) construct to see if the baud rates are truly changing to your desired values.

So you have assorted issues to review. Start with the initial and original XMOS code and be sure the IP can sustain send / receive of 9600 bps rates. Fairly confident that this speed is not an issue. Next test perhaps 19200 bps and repeat the testing. Then attempt to tweak the code for 9600 bps -> 19200 dynamic speed switching and vice versa. That is the approach we would take. Many USB UARTs cannot frame correctly at non-standard baud rates so do not attempt 10 Mbps, etc. at this time unless your USB UART engine offers this support. Also, at such data rates, the 3v3 interface lines must be kept short and sweet.

Another idea is to select a high data like 10 Mbps -> validate with your scope of logic analyzer that you are indeed @ 10 Mbps with the XMOS IP. Then attach the TX & RX (cmos port pins on the XMOS device) together. Now send out data strings @ 10 Mbps. Does the XMOS receiver IP receive the sent data without loss? Assuming it will be ok but worth testing to validate the XMOS IP without the involving the host PC. Using this local loopback idea, no external transceivers are required due to the short wire length. Also will be interesting to see if the coded XMOS IP can sustain the data rate(s) without using hardware flow control lines.
psebastiani
Member++
Posts: 29
Joined: Wed Oct 02, 2013 4:20 pm

Post by psebastiani »

Hi Mon
I made all you suggested
2) Done, it works fine.
3) The UART has physically connected only with TX and RX signal(No signal control) and come out the XMOS IP with MAX232 IC. The PC-host is a windows personal computer with an USB to RS232 adapter. This adapter have a FDTI chip.
4) 10Mbps at the moment is not important for me, I'll try later.
If I set the speed at the beginning of the XMOS IP core, WITHOUT change dinamically the baudrate with "set_baud_rate()" function, all works fine without loss. The XMOS IP program works at 9.6k, 19.2k, 57.6k and 115.2k baud. If I set statically the baud rate I have a bidirectional serial flow with no error, no bit losts and all works fine.
The problem is when I want to change dinamically the serial speed after a proper command send by the PC-host. It's seems that XMOS IP Tx change but XMOS IP Rx not.
I'll try all you suggested, and also the old "sc_uart" module, it worked fine on my old project.
Regards
Piero
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

In your RS232 to RS232 testing, be aware of the limits of your RS232 transceiver on each side of the cable. For example, the MAX232 is relatively a slow part. Best to keep your testing to 115.2k and slower else you may exceed the spec of the transceiver. We use SP3243EUCA which is a 1 Mbps rated part and no issue to even operate at +10% of the rated value. While this is not an issue at this time, just keep this variable out of your debugging exercise :)

If you do wish to test 10 Mbps, then the USB to serial dongle should feature a properly rated RS422 transceiver. RS422/RS485 can support such high data rates over copper wiring. Then also confirm the USB UART can allow for this higher data rate and test against the XMOS IP (also fitted with a local RS422 transceiver).

Immediately, it is the IP that needs the review to support the dynamic baud rate switching for your project. Consider to also review the Ethernet to Serial XMOS IP which allows for baud rate changes using a webserver. Perhaps that code will be applicable for your project.


https://www.xmos.com/published/serial-t ... mentation)
Post Reply