Standard UART Library - How to get more than one char ?

New to XMOS and XCore? Get started here.
Post Reply
User avatar
uc69
Member
Posts: 13
Joined: Thu Jan 04, 2018 8:34 pm

Standard UART Library - How to get more than one char ?

Post by uc69 »

Hello,
I'm trying to use the standard UART lib. but I have a problem while receiving data: it only receives the first char from the string emitted from the remote terminal (I can receive the full string I'm sending to the xmos only if I set the inter char delay at, at least, 70 ms in the terminal settings - which is very long !)

Taken from the example, I'm using:
void app(client uart_tx_if uart_tx, client uart_rx_if uart_rx)
{
while(1)
{
select
{
case uart_rx.data_ready():
uint8_t data = uart_rx.read();
printf("Data received %d\n", data);
break;
}
}
}
Strangely, there is a 'RX_BUFFER_SIZE', but how to access this buffer?

Why it is not possible the use this lib. with 0 ms inter char delay from the remote terminal/emitter like with any UART block of a "normal" microcontroller ?
I will need to send different parameter values to the xmos, like 'PAR1=100,PAR2=30', etc. So only being able to receive only 1 char. is not very usefull
I tried the streaming example but I only get garbage, I cannot find a transmission speed which fits it...
Is there somewhere a more complete UART RX example ?
Thank you,
J.


User avatar
infiniteimprobability
XCore Legend
Posts: 1126
Joined: Thu May 27, 2010 10:08 am
Contact:

Post by infiniteimprobability »

Code looks OK. How are you printing? JTAG or XSCOPE?

http://www.xcore.com/viewtopic.php?t=4088


RX_BUFFER_SIZE is a define so either set in the Makefile -DRX_BUFFER_SIZE=xxx or in your source in the relevant include
User avatar
uc69
Member
Posts: 13
Joined: Thu Jan 04, 2018 8:34 pm

Post by uc69 »

Hello, I use JTAG printing (I suppose, I have just the startkit connected with the usb cable)
I found the solution, I was confused with the 'clear notification' in read()...
The following code builds and prints the received string since a newline is received and,Ok, printf is is very bad there, will be commented in production code but
where is the best location do to the received string processing/parsing ? In another core ? But how to notify the other thread that data is available ? Using a global variable breaks the 'par', so using an interface is the recommented way I suppose ?
//[[combinable]]
void app(client uart_tx_if uart_tx, client uart_rx_if uart_rx)
{
while(1)
{
select
{
case uart_rx.data_ready():
uint8_t data = uart_rx.read();
cmd[cmd_index] = data;
cmd_index++;
if ( data == 10 )
{
cmd[cmd_index] = 0;
cmd_index = 0;
printf("Data received %s\n", cmd);
// flag_cmd_received = 1; // ! breaks 'par'
}
break;
}
}
}
User avatar
uc69
Member
Posts: 13
Joined: Thu Jan 04, 2018 8:34 pm

Post by uc69 »

Thanks for the info, i finaly have this code running but now I'm facing the problem of how to dispatch the received char of char to the other tasks...
I tried the chanelend master-slave-transaction without success, it seems we cannot use the ':>' and '<:' operators inside a 'select-case' ? (makes my code crash)
Pointers are not welcomed - I use a dirty solution with unsafe to go ahead...
What is the best solution to broadcast array data (more "complex" data structure like strings, struct, etc..) across tasks - Should I use FIFO with a tier task ? (but still the problem is "how to get the data out of the task ?")

#include <xs1.h>
#include <platform.h>
#include <timer.h>
#include <stdio.h>
#include <uart.h>
#include <gpio.h>

typedef interface my_interface
{
[[clears_notification]] int clear_notification(void);
[[notification]] slave void ready_for_parsing(void);
} my_interface;

transaction parse_cmd(chanend ce, client my_interface my_face);

//[[combinable]] // alors faire: on tile[0].core[1] (rajouter '.core[x]')
transaction app(chanend ce, client uart_tx_if uart_tx, client uart_rx_if uart_rx, server my_interface brol);
//void app(client uart_tx_if uart_tx, client uart_rx_if my_uart_rx);

// Port declarations
port p_uart_rx = on tile[0] : XS1_PORT_1F; // for StartKit //XS1_PORT_1A;
port p_uart_tx = on tile[0] : XS1_PORT_1H; // for StartKit
#define RX_BUFFER_SIZE 512
char cmd[128];
uint8_t cmd_index = 0;
char * unsafe new_cmd; // pointer to cmd[] when complete command received
int main()
{
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];
my_interface i_flag;
chan ce;
par
{
on tile[0]: output_gpio(i_gpio_tx, 1, p_uart_tx, null);
on tile[0]: uart_tx(i_tx, null, 115200, 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, 115200, UART_PARITY_NONE, 8, 1, i_gpio_rx[0]);
on tile[0] : master app(ce, i_tx, i_rx, i_flag); //on tile[0] : app(i_tx, i_rx);
on tile[0] : slave parse_cmd(ce, i_flag);
on tile[0] : printf("tile[0] Waiting UART Commands...\n");
}
return 0;
}

//[[combinable]]
transaction app(chanend ce, client uart_tx_if uart_tx, client uart_rx_if uart_rx, server my_interface my_face)
{
while(1)
{
select
{
case uart_rx.data_ready():
uint8_t data = uart_rx.read();
cmd[cmd_index++] = data;
if ( data == 10 )
{
cmd[cmd_index] = 0;
cmd_index = 0;
my_face.ready_for_parsing();
printf("Data received [%s]\n", cmd);
// CRASH ! ce <: cmd_len;
}
break;
case my_face.clear_notification() -> int return_value: // https://www.xmos.com/published/how-use- ... interfaces
printf("Clearing notification.\n");
unsafe { new_cmd = cmd; }
return_value = 1;
break;
}
// CRASH ce <: cmd_len;
}
}
transaction parse_cmd(chanend ce, client my_interface my_if)
{
while(1)
{
// CRASH ce :> valeur;
select
{
case my_if.ready_for_parsing():
int val = my_if.clear_notification();
printf("Parsing [%s] %d\n", new_cmd, val);
break;
}
}
}
User avatar
CousinItt
Respected Member
Posts: 360
Joined: Wed May 31, 2017 6:55 pm

Post by CousinItt »

The "best" way to pass arrays between tasks depends on whether the tasks are executing on the same tile. If they are, since the cores on a tile share memory, you can use pointers. I usually use movable pointers as they are safer. If the tasks are running on different tiles (or you need to make your code more portable) then the data can be passed over the processor links using an interface or channel.

There are a plenty of examples in the xmos literature and in this forum. Here are a few...

https://www.xmos.com/published/how-pass ... face-calls

https://www.xmos.com/published/how-use-movable-pointers

https://xcore.com/viewtopic.php?t=3301

http://www.xcore.com/viewtopic.php?t=5585
User avatar
uc69
Member
Posts: 13
Joined: Thu Jan 04, 2018 8:34 pm

Post by uc69 »

Thanks, I will investigate moveable pointers - I managed to make it working with interface but it requires to copy the data (in 'command[]')- ok for small arrays but for bigger things, it is cpu time & energy wasted.

typedef interface my_interface
{
[[clears_notification]] int clear_notification(void);
[[notification]] slave void ready_for_parsing(void);
void get_command(char command[]);
} my_interface;
...
void app(client uart_tx_if uart_tx, client uart_rx_if uart_rx, server my_interface my_face)
{
int cmd_len;
while(1)
{
select
{
case uart_rx.data_ready():
uint8_t data = uart_rx.read();
cmd[cmd_index++] = data;
if ( data == 10 )
{
cmd[cmd_index] = 0;
cmd_len = cmd_index;
cmd_index = 0;
my_face.ready_for_parsing();
//printf("Data received [%s]\n", cmd);
}
break;
case my_face.clear_notification() -> int return_value:
//unsafe { new_cmd = cmd; }
return_value = cmd_len;
//printf("Clearing notification.\n");
break;
case my_face.get_command(char command[]):
for(int i=0; i <= cmd_len; i++)
{
command = cmd; // copy
}
break;
}
}
}
...
void parse_cmd(client my_interface my_if)
{
char cmd_by_if[COMMAND_SIZE];
while(1)
{
select
{
case my_if.ready_for_parsing():
int val = my_if.clear_notification();
//printf("UNSAFE Parsing [%s] %d\n", new_cmd, val); // unsafe
my_if.get_command(cmd_by_if); // interface way
printf("Parsing [%s] %d\n", cmd_by_if, val);
break;
}
}
}
User avatar
uc69
Member
Posts: 13
Joined: Thu Jan 04, 2018 8:34 pm

Post by uc69 »

I'm living a nightmare, the above code worked fine during one day (=I was able to receive more than 1 char in 'cmd[]' and then parse them in 'parse_cmd(...)' but since today, the *exact same code* is only able to receive 1 char, I'm sure at 100% I'm running the same code - I did a zipped backup of the working project, the backup behaves wrongly also, the code never sees anymore the following chars sent by the remote terminal (check & rechecked the term. settings, speed & co => all OK)
Tried on 2 different workstations, Windows (10) & Linux (Ubuntu 17.10), same problem everywhere !
Then I tried the streaming version, also only ONE char (always the 1st one of the stream) is received ! (see full code below)
I also swapped the port pins in case the 'rx' orignal one was damaged, but no change..., re-load the original xmos libs (uart, etc.) in the composer, no change

Could this 2 issues be linked ? https://www.xcore.com/viewtopic.php?f=44&t=2820 Something damaged in the chip ??
It possible to update the firmware of chip ? How ?

#include <xs1.h>
#include <platform.h>
#include <timer.h>
#include <uart.h>
#include <gpio.h>
#include <print.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// Port declarations
//port p_uart_rx = on tile[0] : XS1_PORT_1F; // StarterKit 1-bit port J7-1 (X0D13)
//port p_uart_tx = on tile[0] : XS1_PORT_1H; // StarterKit 1-bit port J7-2 (X0D23)
port p_uart_tx = on tile[0] : XS1_PORT_1F; // StarterKit 1-bit port J7-1 (X0D13)
port p_uart_rx = on tile[0] : XS1_PORT_1H; // StarterKit 1-bit port J7-2 (X0D23)

void app(streaming chanend c_tx, streaming chanend c_rx)
{
uint8_t byte;
printstrln("Test started");
byte = 0;
while(1) // scan incoming byte steam
{
//uart_tx_streaming_write_byte(c_tx, 0xff);
//uint8_t byte;
uart_rx_streaming_read_byte(c_rx, byte);
printf("BYTE=%d\n",byte); // ONLY THE 1ST BYTE IS RECEIVED FROM STREAM !
}
}

#define TICKS_PER_BIT 868 // (868 = 100,000,000 MHz / 115,200 bauds)

int main() {
streaming chan c_rx;
streaming chan c_tx;
par {
on tile[0]: uart_tx_streaming(p_uart_tx, c_tx, TICKS_PER_BIT);
on tile[0]: uart_rx_streaming(p_uart_rx, c_rx, TICKS_PER_BIT);
on tile[0]: app(c_tx, c_rx);
}
return 0;
}
User avatar
CousinItt
Respected Member
Posts: 360
Joined: Wed May 31, 2017 6:55 pm

Post by CousinItt »

I'd confirm your power supply is good first. If you have access to a decent Raspberry Pi power supply, give it a try. They've worked well for me.
Post Reply