Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Altera_Forum
Honored Contributor I
2,551 Views

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
0 Kudos
17 Replies
Altera_Forum
Honored Contributor I
407 Views

How are you transmitting uart from the fpga? Are you polling or using interrupts? 

 

Here is a thread about using UART with interrupts: http://www.alteraforum.com/forum/showthread.php?t=17224 

The code bluegem1 provides (uart interrupt handler) works very well. I've used it to communicate with nios and a Visual c++ program on the pc. 

Make sure your baud rates match up (i use 115200). 

 

The matlab code looks correct.
Altera_Forum
Honored Contributor I
407 Views

 

--- Quote Start ---  

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 

--- Quote End ---  

 

 

anyone please even a clue for me to try please?
Altera_Forum
Honored Contributor I
407 Views

How are you UART? are you polling or using interrupts?  

 

I recommend using interrupts: look at the following thread - the code provided in this thread works well... http://www.alteraforum.com/forum/showthread.php?t=17224 

I've used this code to communicate with a visual c++ program on the pc. 

 

I think the matlab code for accessing the serial port is correct, so the problem is probably on the FPGA side.
Altera_Forum
Honored Contributor I
407 Views

 

--- Quote Start ---  

How are you UART? are you polling or using interrupts?  

 

I recommend using interrupts: look at the following thread - the code provided in this thread works well... http://www.alteraforum.com/forum/showthread.php?t=17224 

I've used this code to communicate with a visual c++ program on the pc. 

 

I think the matlab code for accessing the serial port is correct, so the problem is probably on the FPGA side. 

--- Quote End ---  

 

 

Hi Krasner, 

 

Thanks for your reply. I dont understand why it is not working, must it be done with interrupts? Couldn't it be done by using iowr on the uart? 

 

 

I used the following code to access the UART (rs232 serial port) component I created in Qsys, I connected the txdata pin to the oscilloscope and it shows nothing, i am wondering why couldn't I use IOWR_ALTERA_AVALON_UART_TXDATA(UART_BASE, txdata); to transmit data to UART? 

What I want to do is Nios processor reads data from FPGA, Nios transmits the data to serial port and plot graph real time using Maltab,using de0 nano. I do not need to read data from serial port. 

 

#include "altera_avalon_uart_regs.h" 

 

#define UART_BASE 0x00002000 

 

 

int main (void) 

{alt_u16 status, rxdata=0,aa=0, txdata=0; 

while (! (status & 0x0040)) // Wait for transmission completion  

status = IORD_ALTERA_AVALON_UART_STATUS (UART_BASE);  

printf("status= %.2f V \r\n", (float) status); 

rxdata = 5; // assuming I get this data by accessing sdram in Nios 

txdata = rxdata; 

 

IOWR_ALTERA_AVALON_UART_TXDATA(UART_BASE, txdata); 

printf("txdata= %.2f V \r\n", (float) txdata); 

 

return 0;} 

 

 

Could you please give me some hints? Thanks
Altera_Forum
Honored Contributor I
407 Views

Yes you have to use interrupts for accurate transmission.  

 

I had the same issue you have when using polling (the while loop in your code). This is because the while loop prevents the nios from doing other tasks. In other words, you are bottlenecking yourself. Interrupts allow you to receive and transmit messages exaclty when you want to, by temporarily pausing the nios to perform the uart task. 

 

To do interrupts, you must connect the interrupt (IRQ) column in qsys (that is a hardware enable). Then you must do a software enable (alt_ic_isr_register and alt_ic_irq_enable) --> this is slightly different than in the code provided. He uses alt_irq_register and alt_irq_enable which are outdated... 

 

Here is what I suggest: 

 

The code i linked to is using 2 uarts - because they are talking to each other. You only need 1. So you must go through the provided code and delete one of the uarts (UART2). 

To make life easy, make sure your uart module in qsys is named UART1. This is because his code expects system.h names to be Uart1 and Uart2. You can give it a different name, but you will have to scrub through the code to make the appropriate changes. 

Include InterruptHandlerforUart.h in your code. 

 

Now in main you want to initialize the uart and enable the software interrupts: 

 

int context_uart; 

InitUart1( <put in a baud rate if uart module did not have fixed baud rate... see the linked code>); 

alt_ic_isr_register(Uart1_IRQ_INTERRUPT_CONTROLLER_ID, Uart1_IRQ,IsrUart1,&context_uart,0x0); 

alt_ic_irq_enable(Uart1_IRQ_INTERRUPT_CONTROLLER_ID, Uart1_IRQ); 

 

finally to transmit, you just write: 

PutUart1( <some character> ); 

The C code provided takes care of the rest (uart statuses, fifoing, etc.) 

 

If you have lots of characters - which you do - then put the PutUart1 into a loop.
Altera_Forum
Honored Contributor I
407 Views

 

--- Quote Start ---  

Yes you have to use interrupts for accurate transmission.  

 

I had the same issue you have when using polling (the while loop in your code). This is because the while loop prevents the nios from doing other tasks. In other words, you are bottlenecking yourself. Interrupts allow you to receive and transmit messages exaclty when you want to, by temporarily pausing the nios to perform the uart task. 

 

To do interrupts, you must connect the interrupt (IRQ) column in qsys (that is a hardware enable). Then you must do a software enable (alt_ic_isr_register and alt_ic_irq_enable) --> this is slightly different than in the code provided. He uses alt_irq_register and alt_irq_enable which are outdated... 

 

Here is what I suggest: 

 

The code i linked to is using 2 uarts - because they are talking to each other. You only need 1. So you must go through the provided code and delete one of the uarts (UART2). 

To make life easy, make sure your uart module in qsys is named UART1. This is because his code expects system.h names to be Uart1 and Uart2. You can give it a different name, but you will have to scrub through the code to make the appropriate changes. 

Include InterruptHandlerforUart.h in your code. 

 

Now in main you want to initialize the uart and enable the software interrupts: 

 

int context_uart; 

InitUart1( <put in a baud rate if uart module did not have fixed baud rate... see the linked code>); 

alt_ic_isr_register(Uart1_IRQ_INTERRUPT_CONTROLLER_ID, Uart1_IRQ,IsrUart1,&context_uart,0x0); 

alt_ic_irq_enable(Uart1_IRQ_INTERRUPT_CONTROLLER_ID, Uart1_IRQ); 

 

finally to transmit, you just write: 

PutUart1( <some character> ); 

The C code provided takes care of the rest (uart statuses, fifoing, etc.) 

 

If you have lots of characters - which you do - then put the PutUart1 into a loop. 

--- Quote End ---  

 

 

Thank you very much for your kind reply, krasner... I am now trying to implement the code and need some time to troubleshoot the errors here and there, keep you updated
Altera_Forum
Honored Contributor I
407 Views

 

--- Quote Start ---  

Yes you have to use interrupts for accurate transmission.  

 

I had the same issue you have when using polling (the while loop in your code). This is because the while loop prevents the nios from doing other tasks. In other words, you are bottlenecking yourself. Interrupts allow you to receive and transmit messages exaclty when you want to, by temporarily pausing the nios to perform the uart task. 

 

To do interrupts, you must connect the interrupt (IRQ) column in qsys (that is a hardware enable). Then you must do a software enable (alt_ic_isr_register and alt_ic_irq_enable) --> this is slightly different than in the code provided. He uses alt_irq_register and alt_irq_enable which are outdated... 

 

Here is what I suggest: 

 

The code i linked to is using 2 uarts - because they are talking to each other. You only need 1. So you must go through the provided code and delete one of the uarts (UART2). 

To make life easy, make sure your uart module in qsys is named UART1. This is because his code expects system.h names to be Uart1 and Uart2. You can give it a different name, but you will have to scrub through the code to make the appropriate changes. 

Include InterruptHandlerforUart.h in your code. 

 

Now in main you want to initialize the uart and enable the software interrupts: 

 

int context_uart; 

InitUart1( <put in a baud rate if uart module did not have fixed baud rate... see the linked code>); 

alt_ic_isr_register(Uart1_IRQ_INTERRUPT_CONTROLLER_ID, Uart1_IRQ,IsrUart1,&context_uart,0x0); 

alt_ic_irq_enable(Uart1_IRQ_INTERRUPT_CONTROLLER_ID, Uart1_IRQ); 

 

finally to transmit, you just write: 

PutUart1( <some character> ); 

The C code provided takes care of the rest (uart statuses, fifoing, etc.) 

 

If you have lots of characters - which you do - then put the PutUart1 into a loop. 

--- Quote End ---  

 

 

 

Hi Krasner, 

 

 

 

 

My current system is done with polling as mentioned earlier using direct register method (IORD_ALTERA_AVALON_UART_STATUS (UART_BASE);  

IOWR_ALTERA_AVALON_UART_TXDATA(UART_BASE, txdata);etc)., now I would like to implement with interrupt as you recommended, but I have few issues I need to understand so that I can fix those errors: 

 

I am able to read serial port and plot the graph real time in Matlab. However, I am having the issue where the data is not updated as frequent as desired. I am using USB-to-Serial interface to the board FTDI UM245R module. 

 

I have a few questions about using interrupt for uart: 

 

 

I want to send data from Nios II to serial port to plot graph real time in Matlab. 

 

 

 

 

1. In function void InitUart(), what is the "Uart1_IRQ_INTERRUPT_CONTROLLER_ID" for? I read in the 

I read in the Altera documentation (https://www.altera.com/en_us/pdfs/literature/hb/nios2/n2sw_nii52010.pdf), the interrupt controller ID is defined in system.h, but I couldn't find any info about it in system.h, should I generate or do something to get this controller id? 

 

 

 

 

 

 

2. I assigned IRQ no.2 in Qsys, I dont understand how doesthe function in InitUart() know that Uart1_IRQ is 2? Is it done automatically or how should I assign? 

 

 

alt_ic_isr_register(Uart1_IRQ_INTERRUPT_CONTROLLER_ID, Uart1_IRQ,IsrUart1,&context_uart,0x0); 

 

 

 

 

alt_ic_irq_enable(Uart1_IRQ_INTERRUPT_CONTROLLER_ID, Uart1_IRQ);  

 

 

3. i can't find how to set the flag to 0x0 as you have written  

 

 

4. Regarding alt_ic_isr_register(Uart1_IRQ_INTERRUPT_CONTROLLER_ID, Uart1_IRQ,IsrUart1,&context_uart,0x0);,  

I know this sounds stupicd, can I write the above line twelve times so I can call the function IsrUart1 twelve times? Reason being, I need to send twelve sets of data, imagine I have twelve sets of "context_uart" , each set of data has 10 elements for instance. If it is not possible to call alt_ic_isr_register for 12 times, is there a smart way to do it? 

 

 

5. In the main function, why do we need the two functions GetUart1() and PutUart2()? I thought in the IsUart1(), we have already transmitted the data  

 

 

6. My current system is done with polling as mentioned earlier, now I would like to implement with interrupt as you recommended, since the current system can display data in correct value and order, but data is not updated as frequent as desired (I posted the thread here http://www.alteraforum.com/forum/showthread.php?t=48165), so do you think I still need to have those codes for buffer size, head and tail etc? 

 

 

In the function PutUart1(), if (++TxHead_1 > (TX_BUFFER_SIZE_1-1)) TxHead_1 = 0; 

z = IORD_ALTERA_AVALON_UART_CONTROL(UART1_BASE) | ALTERA_AVALON_UART_CONTROL_TRDY_MSK; 

IOWR_ALTERA_AVALON_UART_CONTROL(UART1_BASE, z); 

I am wondering what is the purpose of having the codes checking the buffer size and the head and tail? TxHead_1==TxTail_1 

 

7. divisor = (ALT_CPU_FREQ/BaudRate) +1; I assume I dont need this as I have fixed baud rate 115200, am I right? 

 

I know I ask a lot and this is demanding, I really appreciate if you could just give short answer to my questions, really appreciate your help!!
Altera_Forum
Honored Contributor I
407 Views

want2know, 

 

I think you don't fully understand how Qsys ties into Quartus and NIOS IDE. 

 

When you generate your Qsys system you get a .sopcinfo file. When you start a NIOS project - File New > NIOS II Application and BSP from Template - you import your Qsys file. This generates a system.h file (located in the 'project_name'_bsp folder) that contains all of system configuration parameter that you set up in qsys. Specifically, Uart1_IRQ_INTERRUPT_CONTROLLER_ID is a parameter that is specified in the system.h file. 

 

When you first started your project, after importing the .sopcinfo file, you should have seen 2 folders appear ('project_name' and 'project_name'_bsp). If you were to right click the _bsp folder and go to NIOS II > BSP Editor, you could look into the Enable File Generation tab and see that the system.h file is going to be made. Click Generate button and your system.h file will be produced in the _bsp folder. 

 

Now you can view your system.h file (you might need to refresh with F5). In there you should see all the qsys parameters and memory mapped address spaces. 

 

So to answer question# 2: InitUart knows what Uart_IRQ is supposed to be, because you should always include the system.h file in your code (#include "system.h"). 

 

OK. Now let's talk about interrupt enables/register functions (ic_isr_register and irq_enable). In question 3 you ask why the flag is set to 0x0. Please read the documentation for ic_isr_register. It will say to set that parameter to 0x0 since it isn't being used. 

---------------------------------------------------------------------------------------------------- 

 

The reason I want to separate this section from the one previous is that you seem to be confused on how the interrupt/hardware work together. 

 

In question 4 you ask if you can call the ic_isr_register multiple times for the same hardware peripheral (Uart1). This does not make sense. You should only call it once for 1 peripheral... Therefore, you should also have 1 context_uart. 

 

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. 

 

As you know Uart is a serial protocol - which means only 1 piece of data can be sent at a time. However, uart is fairly fast (although not the fastest comm. protocol). The speed depends on your baud rate. I usually use 115200. So to answer question 4: 

 

No, do not call out that line 12 times... Call it out once. Then send your data 1 element at a time. If you have 12 data sets @ 10 elements/data set, you will have to send out 120 elements sequentially. That is ok, because the transfer rate is fast. 

 

All the data will come out from 1 uart port which is what you connect to your PC. 

 

---------------------------------------------------------------------------------------------------- 

 

Question 5: In the example I linked previously, there where 2 uarts used to talk to each other. That's why they have Get/Put_Uart 1 and 2. But in your case you only have 1 uart so you only need to use the Get_Uart1 and Put_Uart1 functions. 

 

You ask, why you need these functions if Isr_Uart is already there. Please examine the Uart code in more detail. You will see that the Isr_Uart is called on an interrupt and it will store data in a buffer (Rx_buffer or Tx_buffer). This is done automatically as the interrupt is triggered. However it is up to you to see what the data actually is. That is what Get_Uart and Put_Uart functions do. Get_Uart reads out of the Rx_buffer while Put_Uart places data in the Tx_buffer. You can think of it as functions that let you interface with the ISR function. 

 

Question 6: Yes you still need that Tails and Heads. Don't change this code. In fact you shouldn't have to modify any of the code in the InterruptHandlerforUart file. 

 

Question 7: IF you have a fixed baud rate then you don't need the divisor. Actually just change the following function is the InterruptHandlerforUart.c file: 

 

void InitUart1() 

ALTERA_AVALON_UART_CONTROL_RRDY_MSK); 

 

and in the header 

 

void InitUart1(); 

 

as you can see I modified the init function to have no inputs since you don't need to set the baud rate - it is already fixed. 

 

Hopefully this helps. Let me know if you need anything else.
Altera_Forum
Honored Contributor I
407 Views

 

--- Quote Start ---  

want2know, 

 

I think you don't fully understand how Qsys ties into Quartus and NIOS IDE. 

 

When you generate your Qsys system you get a .sopcinfo file. When you start a NIOS project - File New > NIOS II Application and BSP from Template - you import your Qsys file. This generates a system.h file (located in the 'project_name'_bsp folder) that contains all of system configuration parameter that you set up in qsys. Specifically, Uart1_IRQ_INTERRUPT_CONTROLLER_ID is a parameter that is specified in the system.h file. 

 

When you first started your project, after importing the .sopcinfo file, you should have seen 2 folders appear ('project_name' and 'project_name'_bsp). If you were to right click the _bsp folder and go to NIOS II > BSP Editor, you could look into the Enable File Generation tab and see that the system.h file is going to be made. Click Generate button and your system.h file will be produced in the _bsp folder. 

 

Now you can view your system.h file (you might need to refresh with F5). In there you should see all the qsys parameters and memory mapped address spaces. 

 

So to answer question# 2: InitUart knows what Uart_IRQ is supposed to be, because you should always include the system.h file in your code (#include "system.h"). 

 

OK. Now let's talk about interrupt enables/register functions (ic_isr_register and irq_enable). In question 3 you ask why the flag is set to 0x0. Please read the documentation for ic_isr_register. It will say to set that parameter to 0x0 since it isn't being used. 

---------------------------------------------------------------------------------------------------- 

 

The reason I want to separate this section from the one previous is that you seem to be confused on how the interrupt/hardware work together. 

 

In question 4 you ask if you can call the ic_isr_register multiple times for the same hardware peripheral (Uart1). This does not make sense. You should only call it once for 1 peripheral... Therefore, you should also have 1 context_uart. 

 

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. 

 

As you know Uart is a serial protocol - which means only 1 piece of data can be sent at a time. However, uart is fairly fast (although not the fastest comm. protocol). The speed depends on your baud rate. I usually use 115200. So to answer question 4: 

 

No, do not call out that line 12 times... Call it out once. Then send your data 1 element at a time. If you have 12 data sets @ 10 elements/data set, you will have to send out 120 elements sequentially. That is ok, because the transfer rate is fast. 

 

All the data will come out from 1 uart port which is what you connect to your PC. 

 

---------------------------------------------------------------------------------------------------- 

 

Question 5: In the example I linked previously, there where 2 uarts used to talk to each other. That's why they have Get/Put_Uart 1 and 2. But in your case you only have 1 uart so you only need to use the Get_Uart1 and Put_Uart1 functions. 

 

You ask, why you need these functions if Isr_Uart is already there. Please examine the Uart code in more detail. You will see that the Isr_Uart is called on an interrupt and it will store data in a buffer (Rx_buffer or Tx_buffer). This is done automatically as the interrupt is triggered. However it is up to you to see what the data actually is. That is what Get_Uart and Put_Uart functions do. Get_Uart reads out of the Rx_buffer while Put_Uart places data in the Tx_buffer. You can think of it as functions that let you interface with the ISR function. 

 

Question 6: Yes you still need that Tails and Heads. Don't change this code. In fact you shouldn't have to modify any of the code in the InterruptHandlerforUart file. 

 

Question 7: IF you have a fixed baud rate then you don't need the divisor. Actually just change the following function is the InterruptHandlerforUart.c file: 

 

void InitUart1() 

ALTERA_AVALON_UART_CONTROL_RRDY_MSK); 

 

and in the header 

 

void InitUart1(); 

 

as you can see I modified the init function to have no inputs since you don't need to set the baud rate - it is already fixed. 

 

Hopefully this helps. Let me know if you need anything else. 

--- Quote End ---  

 

 

Thanks Krasner, you explained very good and it helps me a lot!! 

 

 

I have 6 questions: 

 

1. In the main, I modified by removing the GetUart1() because I dont read data from serial port, I have the data with me (the data is stored at txdata1), I just want to transmit to the serial port, my question is, do I still need the function EmptyUart1()? 

 

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. My second question, in the IsrUart1 function, what are the "context" and "int id" for? I didnt see they are used anywhere?  

 

3. in the IsrUart1 function as below, since I am not doing anything with rxbuffer and rrdy_mask (I only need Txbuffer and Trdy_msk), I assume I am going to remove everything for RxHead and RxTail as I comment out the below lines, but what should I do with the last line else IOWR_ALTERA_AVALON_UART_CONTROL(UART1_BASE, ALTERA_AVALON_UART_CONTROL_RRDY_MSK);? 

void IsrUart1(void* context, unsigned int id) 

int sr; 

 

sr = IORD_ALTERA_AVALON_UART_STATUS(UART1_BASE); 

 

//if(sr & ALTERA_AVALON_UART_STATUS_RRDY_MSK); 

//{ 

//rx_buffer_1[RxHead_1] = IORD_ALTERA_AVALON_UART_RXDATA(UART1_BASE); 

//IOWR_ALTERA_AVALON_UART_STATUS(UART1_BASE, 0);  

//if (++RxHead_1 > (RX_BUFFER_SIZE_1-1)) RxHead_1 = 0; 

//} 

 

if(sr & ALTERA_AVALON_UART_STATUS_TRDY_MSK) 

if(IORD_ALTERA_AVALON_UART_CONTROL(UART1_BASE) & ALTERA_AVALON_UART_CONTROL_TRDY_MSK); 

if (TxTail_1 != TxHead_1) 

IOWR_ALTERA_AVALON_UART_TXDATA(UART1_BASE, tx_buffer_1[TxTail_1]); 

if (++TxTail_1 > (TX_BUFFER_SIZE_1 -1))  

TxTail_1 = 0; 

else IOWR_ALTERA_AVALON_UART_CONTROL(UART1_BASE, ALTERA_AVALON_UART_CONTROL_RRDY_MSK); 

 

 

unsigned char EmptyUart1() 

if(RxHead_1 == RxTail_1) return 1; 

return 0; 

 

4. I tried to understand what is the rxhead, rxtail, txhead,txtail, I dont understand what are they about, if I understand correctly, it saves the received dta in rxhead, then check if txtail and txhead are not same, then transmit, but I dont get the whole idea of using these four terms, forgive me for being stupid 

 

5. In void InitUart1(){ 

IOWR_ALTERA_AVALON_UART_CONTROL(UART1_BASE, ALTERA_AVALON_UART_CONTROL_RRDY_MSK); 

}, since I dont want to receive any data from UART, I just want to transmit, I dont know what to be put here since I dont need the rrdy_msk here, please correct me if I am wrong 

 

 

6. My last question is, alt_ic_isr_register(Uart1_IRQ_INTERRUPT_CONTROLLER_ID, Uart1_IRQ,IsrUart1,&context_uart1,0x0);, what is this &context_uart1? In the documention, it states that it is the input argument points to data structure associated with device driver instance, but I am not quite sure what it actually means... 

 

 

Thank you very much, really appreciate your help, more than I can say
Altera_Forum
Honored Contributor I
407 Views

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.
Altera_Forum
Honored Contributor I
407 Views

 

--- 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
Honored Contributor I
407 Views

TO_BE_DONE

Altera_Forum
Honored Contributor I
407 Views

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
Honored Contributor I
407 Views

 

--- 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
Honored Contributor I
407 Views

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
Honored Contributor I
407 Views

 

--- 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.
Altera_Forum
Honored Contributor I
407 Views

In case your are having trouble with Timer interrupts: here is a good blog on how to use them - http://referencevoltage.com/?page_id=168.

Reply