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++
12748 Discussions

Getting variables out of Interrupts

Altera_Forum
Honored Contributor II
1,386 Views

I'm in the process of learning Quartus, SOPC and NIOS and I have many years of programming embedded micros in assembler and C. I have managed to get a littlle system up and running on a 2C20 dev board, including, after much trial, error, reading this forum and Altera apps notes, some interrupt routines. What I just don't seem to be able to do is save a value within a routine and pass it to the main loop. 

 

I have managed to get a serial interrupt handler going and write the ASCII vale of the received character onto the seven segment displays but I can only do that by calling the routines to write to the seven segment displays from within the serial interrupt routine!  

 

What I have tried to do is have a global variable called Flags. Within the serial routine I have a line: 

 

Flags |= HAD_SERIAL;  

 

where HAD_SERIAL is a# define value of 0x01 

 

In the main loop I have the code: 

if ((Flags & HAD_SERIAL == HAD_SERIAL)  

{  

Flags &= ~HAD_SERIAL;  

WriteToSevSeg(NUMBER1,(ByteRec & 0x0F)); 

WriteToSevSeg(NUMBER0,((ByteRec >> 4) & 0x0F));  

}  

 

The serial handler looks like this: 

 

void UART_RxD_Int(void* context, alt_u32 id) 

 

ByteRec = IORD(UART_0_BASE, ALTERA_AVALON_UART_RXDATA_REG);  

// WriteToSevSeg(NUMBER1,(ByteRec & 0x0F)); 

// WriteToSevSeg(NUMBER0,((ByteRec >> 4) & 0x0F));  

Flags = 1;  

 

}  

 

ByteRec and Flags are global variables.  

 

Although I can break within the serial interrupt, the program just refuses to behave properly! It simply will not go to the WriteToSevSeg routine.  

 

If I set a breakpoint in the interrupt Flags is allegedly getting set to 1. If I comment out those lines in the interrupt routine, the ASCII value of the character sent is displayed on the seven segment displays. 

 

This is exactly the way I handled countless serial interrupts over the years on various "normal" processors. Can anyone tell me what I am doing wrong? I have a suspicion you have to do this with pointers, but I've had a play with them too and can't get it to work.  

 

Thanks in advance!
0 Kudos
6 Replies
Altera_Forum
Honored Contributor II
695 Views

Hi Di, 

 

Your code looks ok to me but there are some things I'd check. 

1) Is the Rx the only interrupt enabled? You don't read the status register to ensure the Rx is the correct source so if another interrupt occurs you will corrupt ByteRec (repeatedly). 

2) This is one I've done before. Have you declared Flags as an int in the serial file and then reference it from main as an external char. The test in main reads the wrong char. 

3) Is the read of Flags optimised out by the compiler? As it gets altered in the IRQ its best to declare it as volatile. I guess this is the most likley cause of your problem. 

 

Banx.
0 Kudos
Altera_Forum
Honored Contributor II
695 Views

Hi Banx, 

 

Thanks for the suggestions. I don't think they helped, but I have got it going now, without understand it properly. I still think it's something to do with pointers. 

 

I have referenced my interrupt as follows: 

 

alt_irq_register( UART_0_IRQ, Flags, UART_RxD_Int); 

 

Flags is declared as a global: 

 

volatile char Flags; 

 

This now completely works, but I get a warning on the above line: 

 

warning: passing arg 2 of `alt_irq_register' makes pointer from integer without a cast 

 

I've tried modifying the line to: 

 

alt_irq_register( UART_0_IRQ, (volatile char)Flags, UART_RxD_Int);  

 

Which helps not one jot! 

 

Also, what I find completely bizarre is, in the serial interrupt my variable ByteRec, which is used as following... 

 

ByteRec = IORD(UART_0_BASE, ALTERA_AVALON_UART_RXDATA_REG); 

 

...Is just fine and works without complaining. That's just declared a s a global: 

 

char ByteRec; 

 

So why does Flags need to be put in the alt_irq_register, and once that's done ByteRec work just fine? Also, even though it works, why does it throw up that warning? 

 

This void* business in the protoype for alt_irq_register totally mystifies me. I have to confess I find pointers in C very hard to understand in general and I find that other friends who are C programmers completely fail to explain them to me which makes me supect they don&#39;t understand either! http://forum.niosforum.com/work2/style_emoticons/<#EMO_DIR#>/tongue.gif  

 

DIB.
0 Kudos
Altera_Forum
Honored Contributor II
695 Views

Look at the Count Binary software example...shipped with the EDS. 

 

- slacker
0 Kudos
Altera_Forum
Honored Contributor II
695 Views

 

--- Quote Start ---  

originally posted by slacker@Jan 30 2007, 09:08 PM 

look at the count binary software example...shipped with the eds. 

 

- slacker 

<div align='right'><{post_snapback}> (index.php?act=findpost&pid=21041) 

--- quote end ---  

 

--- Quote End ---  

 

 

Thanks, Slacker. I had already seen that and to an extent it&#39;s how I managed to stumble across the solution (if I can call it that) in the first place.  

 

The problem (for me) is that I don&#39;t understand what is going on. I don&#39;t actually understand what this line does: 

 

alt_irq_register( UART_0_IRQ, Flags, UART_RxD_Int); 

 

I don&#39;t understand why it makes the Flags variable work and I don&#39;t get why ByteRec works when it&#39;s not referenced in the interrupt set-up in the same way. Also, The above line gives me that warning. What does that warning actually mean? Could it potentially be a problem?
0 Kudos
Altera_Forum
Honored Contributor II
695 Views

Two things to explain, I&#39;d gather... 

 

void* 

===== 

The void* pointer in C means a pointer to anything (struct, simple variable, whatever...). It&#39;s the job of the function that receives the void* argument to cast it correctly.  

 

So, in the case of Count Binary, a pointer to edge_capture is passed as alt_irq_register()&#39;s "context" argument. alt_irq_register() creates an irq "id" based structure containing handler (function pointer to ISR) and context (argument passed into ISR). It&#39;s the ISR&#39;s job to interpret the "context" data, correctly. For Count Binary, this meant to cast it to volatile int*. 

 

NOTE: context should be passed as a void* pointer. 

 

volatile 

===== 

This tells the compiler not to optimize a variable&#39;s value away. It&#39;s commonly used for variables containing hardware register values. In the case of Count Binary, it represents the value of the edge capture register. 

 

So, to get rid of your warning you need to pass a void* pointer of ByteRec into alt_irq_register -- and then in your ISR, you need to cast this to the correct type. Though, as you already know, this is not necessary as the compiler has already done this for you.... 

 

Hope that helps! 

 

Regards, 

 

- slacker
0 Kudos
Altera_Forum
Honored Contributor II
695 Views

Thanks, Slacker, that&#39;s clearly put. I&#39;ll go away and look at that example program again bearing your explanation in mind. Your help is much appreciated.

0 Kudos
Reply