Forum Discussion
Altera_Forum
Honored Contributor
15 years agoDE4 simple socket server
Hello all,
I implemented a data acquisition system on the DE4. In general, I grab a fixed number of samples (called A-line), store them on a RAM and then my SOPC reads the RAM contents (through PIO's) and then Nios sends data through ethernet to the PC (Matlab, with pnet http://www.mathworks.com/matlabcentral/fileexchange/345-tcpudpip-toolbox-2-0-6) I modified the example provided by Terasic, having 2 transfer modes: 1. Slow transfer: I send a command (ASCII 65) to the socket server and it sends one A-line to PC. Works fine, but terribly slow (~4.85 lines/sec). 2. Continuous transfer: I send another command (ASCII 67) and the socket server continuously sends A-lines (~1093 lines/sec), but they overlap each other. See attached picture. I wonder if anyone has an idea how to avoid data from overlapping :confused: I basically modified the function sss_exec_command in the code simple_socket_server.c:
.
.
.
/*sss_exec_command()*/
void sss_exec_command(SSSConn* conn)
{
int bytes_to_process = conn->rx_wr_pos - conn->rx_rd_pos;
INT8U tx_buf;
INT8U *tx_wr_pos = tx_buf;
int pos_ini = tx_wr_pos;
INT8U error_code;
/*
* "SSSCommand" is declared static so that the data will reside
* in the BSS segment. This is done because a pointer to the data in
* SSSCommand
* will be passed via SSSLedCommandQ to the LEDManagementTask.
* Therefore SSSCommand cannot be placed on the stack of the
* SSSSimpleSocketServerTask, since the LEDManagementTask does not
* have access to the stack of the SSSSimpleSocketServerTask.
*/
static INT32U SSSCommand;
SSSCommand = CMD_LEDS_BIT_0_TOGGLE;
while(bytes_to_process--)
{
SSSCommand = toupper(*(conn->rx_rd_pos++));
if(SSSCommand >= ' ' && SSSCommand <= '~')
{
tx_wr_pos += sprintf(tx_wr_pos,
"--> Simple Socket Server Command %c.\n\r",
(char)SSSCommand);
if (SSSCommand == CMD_QUIT)
{
tx_wr_pos += sprintf(tx_wr_pos,"Terminating connection.\n\n\r");
conn->close = 1;
} // END if (SSSCommand == CMD_QUIT)
else
{
if (SSSCommand == 65)
{// Read command A (ASCII code = 65)
//printf("--> Acquiring single %c-line...\n",(char)SSSCommand);
// Wait to finish writing acquired data to the RAM
do
{
acq_busy_signal = IORD_ALTERA_AVALON_PIO_DATA(ACQ_BUSY_PIO_BASE);
// look definitions in ..software\simple_socket_server\simple_socket_server_syslib\Debug\system_description\system.h
}
while (acq_busy_signal == 1);
// Indicate that we are busy reading RAM contents
read_RAM_busy = 1;
IOWR_ALTERA_AVALON_PIO_DATA(READ_RAM_BUSY_PIO_BASE, read_RAM_busy);
// Do the transfer
buffer_position = 0;
*tx_wr_pos = 0;
tx_wr_pos = pos_ini;
if (acq_busy_signal == 0)//acq_busy_signal == 0
{
for (RAM_address = 1; RAM_address <= NSAMPLES; RAM_address++)
{
// Read data port (from RAM)
ADC_data = IORD_ALTERA_AVALON_PIO_DATA(ADC_DATA_PIO_BASE);
// Write address port (to RAM)
IOWR_ALTERA_AVALON_PIO_DATA(READ_RAM_ADDRESS_BASE, RAM_address + 1);
dataPointer = &ADC_data;
// Send 16-bit data
tx_buf = dataPointer;
tx_buf = dataPointer;
/* If ADC_data == 32bits
tx_buf = dataPointer;
tx_buf = dataPointer;
tx_buf = dataPointer;
tx_buf = dataPointer;
tx_wr_pos += 4; // 4 bytes*/
tx_wr_pos += 2; // 2 bytes increment
buffer_position += 2;
// Send data every 500*2 bytes
/* if (RAM_address % 500 == 0 && RAM_address != 0)
{
send(conn->fd, tx_buf, tx_wr_pos - tx_buf, 0);
buffer_position = 0;
*tx_wr_pos = 0;
tx_wr_pos = pos_ini;
}
else
{
buffer_position = (RAM_address % 500) * 2; //2 bytes
}*/
} // END for (RAM_address = 0; RAM_address <= NSAMPLES; RAM_address++)
send(conn->fd, tx_buf, tx_wr_pos - tx_buf, 0);
buffer_position = 0;
*tx_wr_pos = 0;
tx_wr_pos = pos_ini;
//printf("--> A-line sent!\n");
} // END if (acq_busy_signal == 0)
// Indicate that we are done reading RAM contents
read_RAM_busy = 0;
IOWR_ALTERA_AVALON_PIO_DATA(READ_RAM_BUSY_PIO_BASE, read_RAM_busy);
} // END if (SSSCommand == 65)
else
{
if (SSSCommand == 67)
{
printf("Continuous acquisition! \n");
while (SSSCommand != CMD_QUIT)
{
// Wait to finish writing acquired data to the RAM
do
{
acq_busy_signal = IORD_ALTERA_AVALON_PIO_DATA(ACQ_BUSY_PIO_BASE);
// look definitions in ..software\simple_socket_server\simple_socket_server_syslib\Debug\system_description\system.h
}
while (acq_busy_signal == 1);
// Indicate that we are busy reading RAM contents
read_RAM_busy = 1;
IOWR_ALTERA_AVALON_PIO_DATA(READ_RAM_BUSY_PIO_BASE, read_RAM_busy);
// Do the transfer
buffer_position = 0;
*tx_wr_pos = 0;
tx_wr_pos = pos_ini;
if (acq_busy_signal == 0)//acq_busy_signal == 0
{
for (RAM_address = 1; RAM_address <= NSAMPLES; RAM_address++)
{
// Read data port (from RAM)
ADC_data = IORD_ALTERA_AVALON_PIO_DATA(ADC_DATA_PIO_BASE);
// Write address port (to RAM)
IOWR_ALTERA_AVALON_PIO_DATA(READ_RAM_ADDRESS_BASE, RAM_address + 1);
dataPointer = &ADC_data;
// Send 16-bit data
tx_buf = dataPointer;
tx_buf = dataPointer;
tx_wr_pos += 2; // 2 bytes increment
buffer_position += 2;
} // END for (RAM_address = 0; RAM_address <= NSAMPLES; RAM_address++)
send(conn->fd, tx_buf, tx_wr_pos - tx_buf, 0);
buffer_position = 0;
*tx_wr_pos = 0;
tx_wr_pos = pos_ini;
} // END if (acq_busy_signal == 0)
// Indicate that we are done reading RAM contents
read_RAM_busy = 0;
IOWR_ALTERA_AVALON_PIO_DATA(READ_RAM_BUSY_PIO_BASE, read_RAM_busy);
} // END while (SSSCommand != CMD_QUIT)
} // END if (SSSCommand == 67)
else
{
error_code = OSQPost(SSSLEDCommandQ, (void *)SSSCommand);
alt_SSSErrorHandler(error_code, 0);
} // END else if (SSSCommand == 67)
} // END else if (SSSCommand == 65)
} // END else if(SSSCommand == CMD_QUIT)
} // END if(SSSCommand >= ' ' && SSSCommand <= '~')
} // END while(bytes_to_process--)
// ORIGINAL POSITION OF SEND COMMAND!!!
return;
} // END void sss_exec_command(SSSConn* conn)
.
.
.
p.s. change .zip extension to .rar3 Replies
- Altera_Forum
Honored Contributor
And this is the Matlab code:
%% PNET EXAMPLE clear; clc; % Server machine (FPGA) serverAddress = '192.168.1.234'; portNumber = 30; NSAMPLES = 1170; BUFFERSIZE = 9000; % Creates tcp/ip connection to the specified 'hostname' and port tcpConn = pnet('tcpconnect',serverAddress,portNumber ); pause(0.1); % specifies how long read and listen commands blocks before it timeouts. pnet(tcpConn,'setreadtimeout',0.25); pnet(tcpConn,'setwritetimeout',0.1); disp('Connection established') %% Read elements at the beginning of connection to flush buffer flush = pnet(tcpConn,'read',BUFFERSIZE,'uint8'); % Show flushed data disp(char(flush)) %% Write commands '0\n\r' to '6\n\r' % for iComm = 0:6, % pnet(tcpConn,'write',uint8()); % % Receive 35+2 characters from FPGA % textReceived = uint8(swapbytes(pnet(tcpConn,'read',,'uint8'))); % disp(char(textReceived')) % end %% Write command to send A-line 'A\n\r' tic nLinesPerFrame = 400; nFrames = 1; nAcqSamples = nLinesPerFrame*nFrames; rawData = zeros(,'int16'); for iFrames = 1:nFrames, for iLines = 1:nLinesPerFrame, pnet(tcpConn,'write',uint8()); % Reads an array of NSAMPLES elements from a connection rawData(:,iLines,iFrames) = pnet(tcpConn,'read',,'int16'); end end elapsedTime = toc; disp() fprintf('Estimated speed %.2f lines/sec\n',nAcqSamples/elapsedTime) % Reads an array of elements from a connection % reception = uint32(swapbytes(pnet(tcpConn,'read',,'uint32'))); %% Display previously acquired data figure ylim() for iFrames = 1:size(rawData,3), for iLines = 1:size(rawData,2), plot(squeeze(rawData(:,iLines,iFrames))) ylim() title(sprintf('Slow Transfer. Frame %d. Line %d',iFrames,iLines)) pause(0.01); end end %% Continuous acquisition 'C\n\r' % DOES NOT WORK WELL!!!! CORRUPTED DATA!!! nLinesPerFrame = 400; nFrames = 25; nAcqSamples = nLinesPerFrame*nFrames; rawDataCont = zeros(,'int16'); pnet(tcpConn,'write',uint8()); tic for iFrames = 1:nFrames, for iLines = 1:nLinesPerFrame, % Reads an array of NSAMPLES elements from a connection % dataReceived = pnet(tcpConn,'read',,'int16'); rawDataCont(:,iLines,iFrames) = pnet(tcpConn,'read',,'int16'); end end elapsedTime = toc; disp() fprintf('Estimated speed: %.2f lines/sec\n',nAcqSamples/elapsedTime) %% Display data acquired continuously figure ylim() for iFrames = 1:size(rawDataCont,3), for iLines = 1:nLinesPerFrame, plot(squeeze(rawDataCont(:,iLines,iFrames))) title(sprintf('Continuous Transfer. Frame %d. Line %d',iFrames,iLines)) end end %% Closes a tcpconnection (send first a 'Q\n\r') pnet(tcpConn,'write',); % Receive 35+2 characters from FPGA textReceived = uint8(swapbytes(pnet(tcpConn,'read',,'uint8'))); disp(char(textReceived')) % pause(0.1); pnet(tcpConn,'close') disp('Connection closed') - Altera_Forum
Honored Contributor
You need to be able to read the 'write pointer' of the capture hardware.
Then you can loop until there is enough data to fill a frame. Probably means a capture/memory buffer that is a few 'A-line' buffers long. - Altera_Forum
Honored Contributor
Thanks for the advice dsl, I changed my transmission buffer to 2340 bytes (just enough for a single buffer of 1170 samples). Had to add a small delay after the send command to make it work (~17 Mbits/sec), but it seems that my PC is not keeping up to the speed :cry:
Any ideas how to know if the packet was received in the PC?case 67: printf("Continuous acquisition! \n"); ////////////////////////////////////////////////////////// // Continuous acquisition loop (ASCII code = 67) ////////////////////////////////////////////////////////// //for (iLines = 1; iLines <= nLines; iLines++) while(1) { ////////////////////////////////////////////////////////// // Send single A-line ////////////////////////////////////////////////////////// // Wait to finish writing acquired data to the RAM do { acq_busy_signal = IORD_ALTERA_AVALON_PIO_DATA(ACQ_BUSY_PIO_BASE); // look definitions in ..software\simple_socket_server\simple_socket_server_syslib\Debug\system_description\system.h } while (acq_busy_signal == 1); // Indicate that we are busy reading RAM contents read_RAM_busy = 1; IOWR_ALTERA_AVALON_PIO_DATA(READ_RAM_BUSY_PIO_BASE, read_RAM_busy); // Begin the transfer tx_wr_pos = tx_buf; for (RAM_address = 1; RAM_address <= NSAMPLES; RAM_address++) { // Read data port (from RAM) ADC_data = IORD_ALTERA_AVALON_PIO_DATA(ADC_DATA_PIO_BASE); // Write address port (to RAM) IOWR_ALTERA_AVALON_PIO_DATA(READ_RAM_ADDRESS_BASE, RAM_address + 1); dataPointer = (unsigned char*)&ADC_data; // Send 16-bit data (swapped upper and lower bytes) *tx_wr_pos++ = dataPointer; *tx_wr_pos++ = dataPointer; } // END for (RAM_address = 0; RAM_address <= NSAMPLES; RAM_address++) bytes_sent = send(conn->fd, tx_buf, tx_wr_pos - tx_buf, 0); //printf("L:%d BS: %d\n",iLines,bytes_sent); // Indicate that we are done reading RAM contents read_RAM_busy = 0; IOWR_ALTERA_AVALON_PIO_DATA(READ_RAM_BUSY_PIO_BASE, read_RAM_busy); ////////////////////////////////////////////////////////// // single A-line transfer done! ////////////////////////////////////////////////////////// // Wait a little... Should know why... for (RAM_address = 1; RAM_address <= NSAMPLES; RAM_address++); } // END of continuous acquisition loop break;