Hi, I face challenges in transferring data from one Bela to another Bela via UART. Could you please have a look and let me know if there is anything to fix it?
Sometimes the communication works fine, and sometimes I get wrong data on the receiver Bela. Below I describe my setup. What I've understood so far is that the uart communication which runs on a different thread than the audio one, it is interrupted by it. But I am not sure about this.
Setup:
I am using two Bela CTAG Face which are connected as in the attached picture.
To enable the UART port, I copy paste the following two lines in uEnv.txt file in the BELABOOT partition.
uboot_overlay_addr4=/lib/firmware/BB-BELA-B2.dtbo
uboot_overlay_addr5=/lib/firmware/BB-UART4-00A0.dtbo
And I add a few lines of code in the Serial.h to be able to use higher baud rates.
Code:
The 2 Belas are running different algorithms with different blocksize, and once every 24 msec I need to transfer 80 float numbers from Bela #1 to Bela #2.
The code of sender Bela #1 looks something like this:
#define DATA_LENGTH 80
#define UART_BUFFER_LENGTH 4 // number of bytes per float
#define UART_RATE 2000000
// Objects/structs
AuxiliaryTask uartTask;
Serial serial;
// State variables
float dataVector[DATA_LENGTH];
char *uartBuffer = (char *) dataVector;
const int uart_comm_rate = 6; // send data every x'th block
int counts = uart_comm_rate - 1;
char pedt[4] = {'X','X','X','X'}; // flag to finish data transfer
// Function declarations
void sendBuffer(char *buffer);
void callFuntion(void*)
{
sendBuffer(uartBuffer);
}
bool setup(BelaContext *context, void *userData)
{
// Initialise uart
serial.setup("/dev/ttyS4", UART_RATE);
// Initialise auxiliary tasks
if((uartTask = Bela_createAuxiliaryTask(&callFuntion, 90, "send-data")) == 0) {
return false;
}
return true;
}
void render(BelaContext *context, void *userData)
{
// Send data every uart_comm_rate blocks
counts += 1;
if (counts == uart_comm_rate)
{
Bela_scheduleAuxiliaryTask(uartTask);
counts = 0;
}
}
void cleanup(BelaContext *context, void *userData) {
}
void sendBuffer(char *buffer)
{
for (unsigned int ii = 0; ii < DATA_LENGTH-1; ii++) {
// write data
int bytesWrite = serial.write(&buffer[ii*UART_BUFFER_LENGTH], UART_BUFFER_LENGTH);
// check for errors
if (bytesWrite < 0)
printf("An error occurred in data transfer.\n");
else if (bytesWrite != UART_BUFFER_LENGTH)
printf("Error: The number of transfered bytes is %d\n", bytesWrite);
usleep(40);
}
// send flag and stop transfer
serial.write(pedt, UART_BUFFER_LENGTH);
usleep(40);
}
The code of receiver Bela #2 looks something like this:
#define DATA_LENGTH 80
#define UART_BUFFER_LENGTH 4 // number of bytes per float
#define UART_RATE 2000000
// Objects/structs
AuxiliaryTask auxTask;
Serial serial;
// State variables for UART
char uartBuffer[UART_BUFFER_LENGTH];
char tempBuffer[DATA_LENGTH];
float *uartFloatPtr = (float *) tempBuffer;
bool flag_new_data = false; // true when receive new data
// Function declarations
void readBuffer(void);
void loop(void* arg);
bool setup(BelaContext *context, void *userData)
{
// Zero vectors
std::memset(uartBuffer, 0, sizeof(uartBuffer));
std::memset(tempBuffer, 0, sizeof(tempBuffer));
// Initializion uart port
serial.setup("/dev/ttyS4", UART_RATE);
// Schedule auxiliary task
if((auxTask = Bela_createAuxiliaryTask(&loop, 90, "read-uart")) == 0) {
return false;
}
Bela_scheduleAuxiliaryTask(auxTask);
return true;
}
void render(BelaContext *context, void *userData)
{
// Processing
// ...
// Do processing if new data arrived
if (flag_new_data) {
// Processing
// ...
flag_new_data = false;
}
}
void cleanup(BelaContext *context, void *userData)
{
serial.cleanup();
}
void readBuffer(void)
{
bool receivingData = true;
int idx = 0;
// read 4 bytes (= 1 float) at a time
while (receivingData) { // this loop stops when DATA_LENGTH float numbers received
int bytesToRead = UART_BUFFER_LENGTH; // 4 bytes
int bytesRead;
while (bytesToRead > 0) { // this loop stops when 4 bytes are received
bytesRead = serial.read(uartBuffer, UART_BUFFER_LENGTH, -1);
// if uartBuffer equals XXXX then stop the outer loop
if (uartBuffer[0] == 'X' && uartBuffer[1] == 'X' && uartBuffer[2] == 'X' && uartBuffer[3] == 'X') {
receivingData = false;
bytesToRead = 0;
// else copy data to tempBuffer
} else {
std::memcpy(&tempBuffer[(idx+1)*UART_BUFFER_LENGTH - bytesToRead], uartBuffer, bytesRead);
bytesToRead -= bytesRead;
idx += 1;
}
}
// Check for errors
if (bytesRead <= 0) {
printf("An error occurred in data transfer.\n");
}
usleep(20);
}
flag_new_data = true;
}
void loop(void* arg)
{
while(!Bela_stopRequested())
{
if (!flag_new_data)
{
readBuffer();
}
}
}