Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
11 years ago

Access serial port for data sent from Nios II's uart for real time plotting graph in

Hi all,

I am able to read data from FPGA to Nios processor, then transmit this data to Uart component created in Qsys using direct register method (IORD_ALTERA_AVALON_UART_STATUS (UART_BASE);

IOWR_ALTERA_AVALON_UART_TXDATA(UART_BASE, txdata);etc).

Then, I was trying to access serial port data sent from uart in Altera Nios II to plot graph real time in Matlab. I was using this code from Matlab central (http://uk.mathworks.com/matlabcentral/fileexchange/28941-real-time-data-plot-from-serial-port) with minor modification as pasted below:

When I run this code I keep getting the following error. What should I do ?

??? In an assignment A(I) = B, the number of elements in B and

I must be the same.

Error in ==> real_time_data_serial at 80

voltage(count) = fscanf(s,'%f');

I found a few solutions on the web, what I have tried:

1. add pause in .m file so that it has enough time to read the data before the next cycle of data

2. add enough delay at C code where I transmit data to uart

3. make sure the uart has the same setting as comport such as comport number, baud rate, parity, flow control

%%real time data plot from a serial port

% This matlab script is for ploting a graph by accessing serial port data in

% real time. Change the com values and all variable values accroding to

% your requirements. Dont forget to add terminator in to your serial device program.

% This script can be modified to be used on any platform by changing the

% serialPort variable.

% Author: Moidu thavot.

%%Clear all variables

clear all;

%%Variables (Edit yourself)

SerialPort='com8'; %serial port

MaxDeviation = 3;%Maximum Allowable Change from one value to next

TimeInterval=0.2;%time interval between each input.0.2

loop=120;%count values

%%Set up the serial port object

s=serial('com8');

set(s,'BaudRate',9600,'DataBits', 8, 'Parity', 'none','StopBits', 1, 'FlowControl', 'none','Terminator','LF');

set(s, 'terminator', 'LF');

set(s, 'timeout', 10);

%%s = serial(SerialPort)

fopen(s);

time =now;

voltage = 0;

%% Set up the figure

figureHandle = figure('NumberTitle','off',...

'Name','Voltage Characteristics',...

'Color',[0 0 0],'Visible','off');

% Set axes

axesHandle = axes('Parent',figureHandle,...

'YGrid','on',...

'YColor',[0.9725 0.9725 0.9725],...

'XGrid','on',...

'XColor',[0.9725 0.9725 0.9725],...

'Color',[0 0 0]);

hold on;

plotHandle = plot(axesHandle,time,voltage,'Marker','.','LineWidth',1,'Color',[0 1 0]);

xlim(axesHandle,[min(time) max(time+0.001)]);

% Create xlabel

xlabel('Time','FontWeight','bold','FontSize',14,'Color',[1 1 0]);

% Create ylabel

ylabel('Voltage in V','FontWeight','bold','FontSize',14,'Color',[1 1 0]);

% Create title

title('Real Time Data','FontSize',15,'Color',[1 1 0]);

%% Initializing variables

voltage(1)=0;

time(1)=0;

count = 2;

k=1;

while ~isequal(count,loop)

%%Re creating Serial port before timeout

k=k+1;

if k==25

fclose(s);

delete(s);

clear s;

s = serial('com8');

fopen(s)

k=0;

end

%%Serial data accessing

pause(2);

fprintf('here');

voltage(count) = fscanf(s,'%f');

%%For reducing Error Use your own costant

voltage(1)=0;

if (voltage(count)-voltage(count-1)>MaxDeviation)

voltage(count)=voltage(count-1);

end

time(count) = count;

set(plotHandle,'YData',voltage,'XData',time);

set(figureHandle,'Visible','on');

datetick('x','mm/DD HH:MM');

pause(5);

count = count +1;

end

%% Clean up the serial port

fclose(s);

delete(s);

clear s;

When I check the serial port status, I got the following:

Communication Settings

Port: COM8

BaudRate: 9600

Terminator: 'LF'

Communication State

Status: open

RecordStatus: off

Read/Write State

TransferStatus: idle

BytesAvailable: 0

ValuesReceived: 0

ValuesSent: 0

I noticed the serial port is ready (since it is open) but no data is sent or receive. Could you please tell me what is wrong so I could try?

Please , thank you

17 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    1) If you aren't limited by onchip memory, I don't see a reason for you to take out code from the InterruptHandlerforUart files. Even if you never call out GetUart, it won't hurt to have it in your code - for the future...

    I can't see why your code (.txt,.stack,.heap, etc) would take up a lot of memory. Normally I allocate at least 26000 bytes to onchip memory in qsys. That is more than enough for the complete Uart code.

    EmptyUart function is there to check if the data buffers are empty. You can use it if you want. You don't need it to transmit data. But again, even if you don't use it, don't remove it from the code if you have ample memory space.

    2) "The way interrupts work is that when the main thread is interrupted, the state of that main thread is temporarily stored the variable - context_uart - until the interrupt service routine (Isr_Uart1) is completed. Then the main thread will resume where it left off." <-- this is from my last reply

    So in IsrUart, context and id are the what you pass context_uart into. Although it's not used directly in that function, i think its needed for the ic_isr_register function, so don't modify.

    3) once again, if you aren't limited by on chip memory, don't delete this code. You might need it in the future.

    4) rxhead/tail, txhead/tail are just position markers in the Rxbuffer and Txbuffer. Basically, when the head = tails then the buffer is empty. The code is using these location values to parse through the data buffers. This is needed because Uart data maybe coming in at one rate, but you are reading it in at a different rate (as you need it).

    5) See answer 2 and middle section of previous reply. It is just a holder of the main thread's state, while the Uart Interrupt service routine is being processed.

    Here is a wiki on context switching / interrupt handling: http://en.wikipedia.org/wiki/context_switch#interrupt_handling

    So in summary, don't fiddle around with the interrupthandlerforuart code. It is more work then it's worth and you might damage the functionality.

    --- Quote End ---

    Hi Krasner, thank you so much again and again...

    I understand your point about not deleting those code about rx although i dont need them now.

    My question is, where should I put the data that I want to transmit to Uart ? I dont read data from serial port, I have the data with me (the data is stored at txdata1)

    I put the txdata1 in the main, but failed to display the character (2, 8,5,6, I did add 48 for ascii), I cant tell what is wrong now, need some time, sorry.

    Can I just put it in the main()?

    int main()

    {

    unsigned char ch;

    printf("\n\nHello NiosII!!!!!\n");

    InitUart();

    while(1) {

    if(!EmptyUart1()) {

    unsigned char txdata1 [4]={2, 8, 5,6};

    PutUart1(&txdata1);

    }

    } //while

    return 0;

    }

    2. as you can see in the next post, I just modified the code in the main(), and add printf in the interrupthandlerforuart code just for checking. When I run the code, it keeps giving the in_char=i, no matter what value I change in the txdata1

    3. Will it do any harm to include this function even though I am not doing anything with rrdy_msk and the rx buffer etc?

    void InitUart1(){

    IOWR_ALTERA_AVALON_UART_CONTROL(UART1_BASE, ALTERA_AVALON_UART_CONTROL_RRDY_MSK);

    }
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    This is difficult to read through....

    I suggest make yourself a main.c and main.h files.

    In main.c include main.h

    In main.h include your drivers (system.h, sys/alt_irq.h, altera_avalon_uart_regs.h, whatever else you wany, AND InterruptHandlerforUart.h)

    In InterruptHandlerforUart.h also include system.h and altera_avalon_uart_regs.h for safety...

    In main.c:

    first put in the void InitUart(){ .... } routine you have

    then (as in the last thing you do) put in the int main() {....} routine

    in int main() you want to include:

    call out InitUart

    and your PutUart

    you basically do this already just make sure the int main() is you last routine

    So for transmitting data you have this:

    while(1) {

    unsigned char txdata [4]={2, 8, 5,6};

    PutUart1(&txdata); <==================== this line right here isn't going to work since PutUart is expecting a character not an array

    }

    What I would do would be:

    unsigned char txdata[4]={0}; //initialize with zeros

    int i = 0; // array position

    while(1){

    txdata[0]=2;

    txdata[1]=8;

    txdata[2]=5;

    txdata[3]=6; // you can also initialize with {2,8,5,6}

    //Then in a for loop spit out each character from the array

    for(i=0;i<4;i++){

    PutUart(txdata[i]);

    }

    }

    So try that. Hopefully you didn't modify the InterruptHandlerforUart apart from InitUart1.... (I keep harping on this because at this point you just want to see if it'll work, you can modify once you verify functionality).

    Note:

    1. You don't need to add this line "#define UART1_BASE 0x00002000" to the code because it is already defined in system.h! This is why we include it in the first place. It contains all the address and other parameters of peripheral that you placed in qsys.

    2. I said this in the beginning, but separate you main program to another c file (main.c). It will make the code much cleaner.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    This is difficult to read through....

    I suggest make yourself a main.c and main.h files.

    In main.c include main.h

    In main.h include your drivers (system.h, sys/alt_irq.h, altera_avalon_uart_regs.h, whatever else you wany, AND InterruptHandlerforUart.h)

    In InterruptHandlerforUart.h also include system.h and altera_avalon_uart_regs.h for safety...

    In main.c:

    first put in the void InitUart(){ .... } routine you have

    then (as in the last thing you do) put in the int main() {....} routine

    in int main() you want to include:

    call out InitUart

    and your PutUart

    you basically do this already just make sure the int main() is you last routine

    So for transmitting data you have this:

    while(1) {

    unsigned char txdata [4]={2, 8, 5,6};

    PutUart1(&txdata); <==================== this line right here isn't going to work since PutUart is expecting a character not an array

    }

    What I would do would be:

    unsigned char txdata[4]={0}; //initialize with zeros

    int i = 0; // array position

    while(1){

    txdata[0]=2;

    txdata[1]=8;

    txdata[2]=5;

    txdata[3]=6; // you can also initialize with {2,8,5,6}

    //Then in a for loop spit out each character from the array

    for(i=0;i<4;i++){

    PutUart(txdata[i]);

    }

    }

    So try that. Hopefully you didn't modify the InterruptHandlerforUart apart from InitUart1.... (I keep harping on this because at this point you just want to see if it'll work, you can modify once you verify functionality).

    Note:

    1. You don't need to add this line "#define UART1_BASE 0x00002000" to the code because it is already defined in system.h! This is why we include it in the first place. It contains all the address and other parameters of peripheral that you placed in qsys.

    2. I said this in the beginning, but separate you main program to another c file (main.c). It will make the code much cleaner.

    --- Quote End ---

    Thank you very much Krasner, with your help, I am able to use the codes provided and modified main.c to transmit data to serial port. However, I am still facing the same problem as before, previously, as mentioned earlier, I do not implement uart interrupts, I was using polling previously, although I was able to plot the graph but data was not updated as often as it should be (as I posted in this thread http://www.alteraforum.com/forum/showthread.php?t=48165). Now, I have implemented interrupt, the same issue persists, I have no idea what perspective I should look into to troubleshoot this problem, I can send you the code, I am having the issue where the data is not updated as frequent as desired.

    In my C code, I want the parameter say parameter A to be updated every 0.2 seconds, so I expect to see 30 sets of data being updated within 6 seconds, however, it is only updated 3 sets within 6 seconds, I can see that the sequence/order it updates is correct, just that it is updated slower that it is supposed to be.

    I suspect two reasons and so I tried:

    1.Interval timer core, so I change the timer from 0.2 seconds to 0.1 seconds, it makes no difference to the results though

    2. Matlab code, timeout parameter, I set it to be 7 seconds, if I set it less than this, I will get an error saying the serial: data not returned within the timeout period.

    What I currently have are as follows:int main(void)

    { // open main

    printf("\n\nHello NiosII!!!!!\n");

    InitUart();

    // do other processing, read adc, interval timer etc

    //then call for PutUart1 int z = 0;

    for(z=0;z<12;z++)

    {

    unsigned char bb;

    bb= (char) txdata1[z] + 48;

    PutUart1(bb);

    }

    void InitUart()

    {

    int context_uart1;

    InitUart1();

    &#12288;

    alt_ic_isr_register(UART1_IRQ_INTERRUPT_CONTROLLER_ID, UART1_IRQ,IsrUart1,&context_uart1,0x0);

    &#12288;

    alt_ic_irq_enable(UART1_IRQ_INTERRUPT_CONTROLLER_ID, UART1_IRQ);

    }

    I have no idea what perspective I should look into to troubleshoot this problem, just need some idea from you, appreciate your help....My first question, how do I know/check if interrupts has been enabled? my second question is, I don't see the difference between the polling and interrupt implemented in my system, the only difference is, in the Matlab code timeout parameter, previously it worked with 5 seconds, now I can only set it to 7 seconds otherwise I will get an error saying the

    serial: data not returned within the timeout period. My third question, I didn't make any changes to the InterruptHandlerforUart.c (except printf), I want to know, what changes should I make to the InitUart1() function below since I am not doing anything with rrdy_mask and rx buffer, I only transmit but not receive. void InitUart1()

    {

    IOWR_ALTERA_AVALON_UART_CONTROL(UART1_BASE, ALTERA_AVALON_UART_CONTROL_RRDY_MSK);

    }

    &#12288;

    My fourth question, could it be the problem with the sequence/order? the sequence the program will call is InitUart, then adc read/sorting/timer etc, PutUart, is there anything wrong with this order?

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    You say you are using the interval timer. How are you using it? Because the interval timer can also be used with interrupts.

    The way I would imagine your system should work is:

    1) Initialize timer to 0.2 seconds

    2) once the timer runs out (if interrupts for the timer are enabled) it will trigger an interrupt

    3) In the ISR for the timer you would a) read ADC, b) put ADC value into PutUart

    4) Reset timer interrupt bit, reset timer to 0.2 seconds

    I don't see how the timer is used in your case.

    To check if interrupts are enabled all you have to do is read the value outputted from irq_enable and ic_isr_register. If both output 0 then the interrupts are enabled. If they output -1 then there was an error. I don't think you'll have errors.

    To set up interrupts for the timer, you would connect the irq in qsys, then use the same irq_enable and ic_isr_register command, but instead of UART IDs and IsrUart and context_uart

    you would use TIMER IDs, IsrTimer (which you would have to create) and context_timer.

    In IsrTimer you will do steps 2 - 4. Timers count down from your set value to 0. Read timer documentation on how to reset the timer interrupt.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    You say you are using the interval timer. How are you using it? Because the interval timer can also be used with interrupts.

    The way I would imagine your system should work is:

    1) Initialize timer to 0.2 seconds

    2) once the timer runs out (if interrupts for the timer are enabled) it will trigger an interrupt

    3) In the ISR for the timer you would a) read ADC, b) put ADC value into PutUart

    4) Reset timer interrupt bit, reset timer to 0.2 seconds

    I don't see how the timer is used in your case.

    To check if interrupts are enabled all you have to do is read the value outputted from irq_enable and ic_isr_register. If both output 0 then the interrupts are enabled. If they output -1 then there was an error. I don't think you'll have errors.

    To set up interrupts for the timer, you would connect the irq in qsys, then use the same irq_enable and ic_isr_register command, but instead of UART IDs and IsrUart and context_uart

    you would use TIMER IDs, IsrTimer (which you would have to create) and context_timer.

    In IsrTimer you will do steps 2 - 4. Timers count down from your set value to 0. Read timer documentation on how to reset the timer interrupt.

    --- Quote End ---

    Thank you very much for your kind reply, currently I am not using interrupt for timer, i have the preset value and when bit TO is one, I know time is up. still need some time to implement timer interrupt, will keep it posted. Thank u again for your explanation.