Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++
12590 Discussions

NiosII Uart Interrupt Handler

Altera_Forum
Honored Contributor II
6,318 Views

Hi!!

 

I wrote Uart Interrupt Handler For NiosII. and use it.

 

[CODE]

//-----------------------------------------------------------------------------

//Description : Uart Interrupt Handler & Q Buffer For NiosII

//Vision : V1.0

//Filename : InterruptHandlerForUart.c 

// Copyright 2006, Cheong Min LEE

// Email: lcm2559@yahoo.co.kr

// The test may be run in NiosII standalone mode

//-----------------------------------------------------------------------------

 

 

#include "system.h"

#include "altera_avalon_uart_regs.h"

 

#define RX_BUFFER_SIZE_1 1024

#define TX_BUFFER_SIZE_1 1024

#define RX_BUFFER_SIZE_2 1024

#define TX_BUFFER_SIZE_2 1024

 

unsigned short TxHead_1=0; 

unsigned short TxTail_1=0;

unsigned char tx_buffer_1[TX_BUFFER_SIZE_1];

 

unsigned short RxHead_1=0;

unsigned short RxTail_1=0;

unsigned char rx_buffer_1[RX_BUFFER_SIZE_1];

 

unsigned short TxHead_2=0;

unsigned short TxTail_2=0;

unsigned char tx_buffer_2[TX_BUFFER_SIZE_2]; 

 

unsigned short RxHead_2=0;

unsigned short RxTail_2=0;

unsigned char rx_buffer_2[RX_BUFFER_SIZE_2];

 

void InitUart1(unsigned int BaudRate)

{

unsigned int divisor;

 

divisor = (ALT_CPU_FREQ/BaudRate) +1;

IOWR_ALTERA_AVALON_UART_DIVISOR(UART1_BASE, divisor);

IOWR_ALTERA_AVALON_UART_CONTROL(UART1_BASE, ALTERA_AVALON_UART_CONTROL_RRDY_MSK);

}

 

void InitUart2(unsigned int BaudRate)

{

unsigned int divisor;

 

divisor = (ALT_CPU_FREQ/BaudRate) +1;

IOWR_ALTERA_AVALON_UART_DIVISOR(UART2_BASE, divisor);

IOWR_ALTERA_AVALON_UART_CONTROL(UART2_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);

}

}

}

 

void IsrUart2(void* context, unsigned int id)

{

int sr;

 

sr = IORD_ALTERA_AVALON_UART_STATUS(UART2_BASE);

if(sr & ALTERA_AVALON_UART_STATUS_RRDY_MSK);

{

rx_buffer_2[RxHead_2] = IORD_ALTERA_AVALON_UART_RXDATA(UART2_BASE);

IOWR_ALTERA_AVALON_UART_STATUS(UART2_BASE, 0); 

if (++RxHead_2 > (RX_BUFFER_SIZE_2-1)) RxHead_2 = 0;

}

if(sr & ALTERA_AVALON_UART_STATUS_TRDY_MSK)

{

if(IORD_ALTERA_AVALON_UART_CONTROL(UART2_BASE) & ALTERA_AVALON_UART_CONTROL_TRDY_MSK);

{

if (TxTail_2 != TxHead_2)

{

IOWR_ALTERA_AVALON_UART_TXDATA(UART2_BASE, tx_buffer_2[TxTail_2]);

if (++TxTail_2 > (TX_BUFFER_SIZE_2 -1)) TxTail_2 = 0;

}

else IOWR_ALTERA_AVALON_UART_CONTROL(UART2_BASE, ALTERA_AVALON_UART_CONTROL_RRDY_MSK);

}

}

}

 

unsigned char EmptyUart1()

{

if(RxHead_1 == RxTail_1) return 1;

return 0;

 

unsigned char EmptyUart2()

{

if(RxHead_2 == RxTail_2) return 1;

return 0;

 

unsigned char GetUart1(void)

{

unsigned char rxChar; 

 

/* buffer is empty */

 

rxChar=rx_buffer_1[RxTail_1];

if (++RxTail_1 > (RX_BUFFER_SIZE_1-1)) RxTail_1=0;

 

return rxChar;

}

 

unsigned char GetUart2(void)

{

unsigned char rxChar; 

 

/* buffer is empty */

 

rxChar=rx_buffer_2[RxTail_2];

if (++RxTail_2 > (RX_BUFFER_SIZE_2-1)) RxTail_2=0;

 

return rxChar;

}

 

unsigned char PutUart1(unsigned char in_char)

{

unsigned short size;

unsigned int z;

 

z = IORD_ALTERA_AVALON_UART_STATUS(UART1_BASE) & ALTERA_AVALON_UART_STATUS_TRDY_MSK;

 

if ((TxHead_1==TxTail_1) && z) IOWR_ALTERA_AVALON_UART_TXDATA(UART1_BASE, in_char);

else

{

if (TxHead_1 >= TxTail_1) size = TxHead_1 - TxTail_1;

else size = ((TX_BUFFER_SIZE_1-1) - TxTail_1) + TxHead_1;

if (size > (TX_BUFFER_SIZE_1 - 3)) return (-1);

tx_buffer_1[TxHead_1] = in_char;

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);

}

return(1);

}

 

unsigned char PutUart2(unsigned char in_char)

{

unsigned short size;

unsigned int z;

 

z = IORD_ALTERA_AVALON_UART_STATUS(UART2_BASE) & ALTERA_AVALON_UART_STATUS_TRDY_MSK;

 

if ((TxHead_2==TxTail_2) && z) IOWR_ALTERA_AVALON_UART_TXDATA(UART2_BASE, in_char);

else

{

if (TxHead_2 >= TxTail_2) size = TxHead_2 - TxTail_2;

else size = ((TX_BUFFER_SIZE_2-1) - TxTail_2) + TxHead_2;

if (size > (TX_BUFFER_SIZE_2 - 3)) return (-1);

tx_buffer_2[TxHead_2] = in_char;

if (++TxHead_2 > (TX_BUFFER_SIZE_2-1)) TxHead_2 = 0;

z = IORD_ALTERA_AVALON_UART_CONTROL(UART2_BASE) | ALTERA_AVALON_UART_CONTROL_TRDY_MSK;

IOWR_ALTERA_AVALON_UART_CONTROL(UART2_BASE, z);

}

return(1);

}

 

 

 

 

//-----------------------------------------------------------------------------

//Description : Uart Interrupt Handler & Q Buffer For NiosII

//Vision : V1.0

//Filename : InterruptHandlerForUart.h 

// Copyright 2006, Cheong Min LEE

// Email: lcm2559@yahoo.co.kr

// The test may be run in NiosII standalone mode

//-----------------------------------------------------------------------------

 

#ifndef _INTERRUPTHANDLERFORUAR_H_

#define _INTERRUPTHANDLERFORUAR_H_

 

/************************************************** ***************************

* Public function prototypes

************************************************** **************************/

void InitUart1(unsigned int BaudRate);

void InitUart2(unsigned int BaudRate);

void IsrUart1();

void IsrUart2();

unsigned char EmptyUart1();

unsigned char EmptyUart2();

unsigned char GetUart1(void);

unsigned char GetUart2(void);

unsigned char PutUart1(unsigned char in_char);

unsigned char PutUart2(unsigned char in_char);

 

#endif //_INTERRUPTHANDLERFORUAR_H_

 

 

 

 

 

//-----------------------------------------------------------------------------

//Description : Uart Interrupt Handler & Q Buffer For NiosII

//Vision : V1.0

//Filename : UartMain.c 

// Copyright 2006, Cheong Min LEE

// Email: lcm2559@yahoo.co.kr

// The test may be run in NiosII standalone mode

//-----------------------------------------------------------------------------

 

#include <stdio.h>

#include <string.h>

#include <unistd.h>

#include <alt_types.h>

#include <io.h>

#include "system.h"

#include "sys/alt_irq.h"

#include "InterruptHandlerForUart.h"

 

#define BAUD_RATE_0 115200 

#define BAUD_RATE_1 115200 

 

void InitUart()

{

int context_uart1,context_uart2;

 

InitUart1(BAUD_RATE_0);

InitUart2(BAUD_RATE_1); 

 

alt_irq_register(UART1_IRQ,&context_uart1,IsrUart1 ); // install UART1 ISR

alt_irq_register(UART2_IRQ,&context_uart2,IsrUart2 ); // install UART2 ISR

 

alt_irq_enable (UART1_IRQ); 

alt_irq_enable (UART2_IRQ); 

}

 

int main()

{

unsigned char ch;

 

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

InitUart();

 

while(1) {

if(!EmptyUart1()) { 

ch = GetUart1(); 

PutUart2(ch);

}

if(!EmptyUart2()) { 

ch = GetUart2(); 

PutUart1(ch);

}

} //while

return 0;

}

 

 

May be some modification required by own SOPC Builder status.

 

Try to test this code and reply some helpful words......

0 Kudos
11 Replies
Altera_Forum
Honored Contributor II
3,249 Views

Hi, your code work!! :) 

with the correct SOPC. 

I Probe the code in my SOPC and work. 

Excelente code.
0 Kudos
Altera_Forum
Honored Contributor II
3,249 Views

Hi blugem1, 

 

I am working on nios2 project using 1 uart and 1 ethernet port and your code helps me very much. My system works exactly as I need now. Where do you get the information of primitive function such as ALTERA_AVALON_UART_STATUS_TRDY_MSK and IORD_ALTERA_AVALON_UART_STATUS? Maybe I will need that the source for ethernet part of my system. I didn't use that kind of function in my previous code so that my system only worked from PC to FPGA and not in otherwise. Thank you very much..
0 Kudos
Altera_Forum
Honored Contributor II
3,249 Views

your code is good,thanks a lot!

0 Kudos
Altera_Forum
Honored Contributor II
3,249 Views

Your are great. Code is very use full.

0 Kudos
Altera_Forum
Honored Contributor II
3,249 Views

 

--- Quote Start ---  

Hi blugem1, 

 

I am working on nios2 project using 1 uart and 1 ethernet port and your code helps me very much. My system works exactly as I need now. Where do you get the information of primitive function such as ? Maybe I will need that the source for ethernet part of my system. I didn't use that kind of function in my previous code so that my system only worked from PC to FPGA and not in otherwise. Thank you very much.. 

--- Quote End ---  

 

 

ariefgrand, 

you can find ALTERA_AVALON_UART_STATUS_TRDY_MSK and IORD_ALTERA_AVALON_UART_STATUS in altera_avalon_uart_regs.h that in <altera install directory>/ip/altera/sopc_builder_ip
0 Kudos
Altera_Forum
Honored Contributor II
3,249 Views

Nice code..! 

 

One little thing though. In your both your ISR functions you have a stray ";" at the end of the first IF statement. 

 

if(IORD_ALTERA_AVALON_UART_CONTROL(UART1_BASE) & ALTERA_AVALON_UART_CONTROL_TRDY_MSK);
0 Kudos
Altera_Forum
Honored Contributor II
3,249 Views

TO_BE_DONE

0 Kudos
Altera_Forum
Honored Contributor II
3,249 Views

Hi everyone, I was directed here by a forumer Krasner when I posted my problem in this forum. 

 

 

 

 

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 hope someone could just give short answer to my questions, really appreciate your help!!
0 Kudos
Altera_Forum
Honored Contributor II
3,249 Views

Dear want2know, 

 

Regarding you 4th query, Interrupt for UART (or any other IP core) is required to be registered only once, and repeating any such lines like "alt_ic_isr_register(uart1_irq_interrupt_controller _id, uart1_irq,isruart1,&context_uart,0x0);" will not make any difference, its only the number of times the interrupt comes that matters. Like in the code of bluegem he has enabled only the interrupt for RXDATA register, by writing to the CONTROL register of the UART, read the Altera Peripherals IP guide for details regarding the UART IP core. 

 

Regarding 5th query, In IsrUart1(), bluegem is receiving the data, and writing to rx_buffer_1 most of the times, because the interrupt for Data Reception is permanently enabled and he enables the interrupt generation for Transmission, only when the UART is still not ready to accept new data for Transmission. This thing he is doing in PutUart1() function, and he is writing the data to tx_buffer_1 when the UART is not ready for Immediate Transmission of data. Hence whenever the next Interrupt from UART arrives (but now since both the Interrupts, i.e. for Transmission & Reception are enabled, hence Interrupt can happen because of both reasons), lets assume that this time interrupt arrives for Transmission, hence the data to be Transmitted is written in TXDATA register for Transmission. 

 

Regarding your query for below 

"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" 

 

TxHead just points to data which is to be transmitted and TxTail points to the Data which has been Transmitted and the difference between them gives the pending data which is yet to be transmitted. In the above case, bluegem is first checking whether UART is ready for accepting a new data for transmission, if it is ready then the condition txhead_1==txtail_1 will hold true, otherwise the data will be written in tx_buffer_1 and TxHead_1 will be incremented, this is further followed by enabling of Interrupt generation for Transmission, this he is doing in following code-segment "z = iord_altera_avalon_uart_control(uart1_base) | altera_avalon_uart_control_trdy_msk;iowr_altera_avalon_uart_control(uart1_base, z);". And whenever the next Interrupt from UART arrives the data pointed by TxTail_1 is written in the TXDATA register of UART for Transmission. 

 

I think I have tried for clarifying your queries, any more update on the same please tell me or correct me if I am wrong
Altera_Forum
Honored Contributor II
3,249 Views

 

--- Quote Start ---  

Dear want2know, 

 

Regarding you 4th query, Interrupt for UART (or any other IP core) is required to be registered only once, and repeating any such lines like "alt_ic_isr_register(uart1_irq_interrupt_controller _id, uart1_irq,isruart1,&context_uart,0x0);" will not make any difference, its only the number of times the interrupt comes that matters. Like in the code of bluegem he has enabled only the interrupt for RXDATA register, by writing to the CONTROL register of the UART, read the Altera Peripherals IP guide for details regarding the UART IP core. 

 

Regarding 5th query, In IsrUart1(), bluegem is receiving the data, and writing to rx_buffer_1 most of the times, because the interrupt for Data Reception is permanently enabled and he enables the interrupt generation for Transmission, only when the UART is still not ready to accept new data for Transmission. This thing he is doing in PutUart1() function, and he is writing the data to tx_buffer_1 when the UART is not ready for Immediate Transmission of data. Hence whenever the next Interrupt from UART arrives (but now since both the Interrupts, i.e. for Transmission & Reception are enabled, hence Interrupt can happen because of both reasons), lets assume that this time interrupt arrives for Transmission, hence the data to be Transmitted is written in TXDATA register for Transmission. 

 

Regarding your query for below 

 

"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" 

 

TxHead just points to data which is to be transmitted and TxTail points to the Data which has been Transmitted and the difference between them gives the pending data which is yet to be transmitted. In the above case, bluegem is first checking whether UART is ready for accepting a new data for transmission, if it is ready then the condition txhead_1==txtail_1 will hold true, otherwise the data will be written in tx_buffer_1 and TxHead_1 will be incremented, this is further followed by enabling of Interrupt generation for Transmission, this he is doing in following code-segment "z = iord_altera_avalon_uart_control(uart1_base) | altera_avalon_uart_control_trdy_msk;iowr_altera_avalon_uart_control(uart1_base, z);". And whenever the next Interrupt from UART arrives the data pointed by TxTail_1 is written in the TXDATA register of UART for Transmission. 

 

I think I have tried for clarifying your queries, any more update on the same please tell me or correct me if I am wrong 

--- Quote End ---  

 

 

hey,can you please tell me this code is in c language or embedded c ???
0 Kudos
Altera_Forum
Honored Contributor II
3,249 Views

hey can anyone please tell me this code is in c language or embedded c???

0 Kudos
Reply