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

Posible Problem with ISR Edge PIO

Altera_Forum
Contributeur émérite II
1 608 Visites

Hello, 

 

This is more a theoretical view, but think it could be important to you. 

 

When working with an IRQ generating PIO with Edge Capture Register and multiple inputs, a ISR proccesing routine should look like this: 

 

void my_isr_procedure(...) __attribute__ ((section (".internal_ram.txt"))); void my_isr_procedure(...) {  // read capture register  register alt_u32 edge_capture=IORD_ALTERA_AVALON_PIO_EDGE_CAP(IRQ_PIO_BASE);    // clear it imediatly  IOWR_ALTERA_AVALON_PIO_EDGE_CAP(IRQ_PIO_BASE, 0);        ... do interrupt work ...  if (edge_capture & ???) ... // do something  // set mask  IOWR_ALTERA_AVALON_PIO_IRQ_MASK(IRQ_PIO_BASE, 0xF); } 

 

As you see, reading the capture register and clearing must be done imediate after each other. Otherwise, if clearing edge register at the end of your ISR, the possibility increases that a slightly async captured edge, which could apear during your ISR processing, get's lost. 

 

But, when i think a bit about it, i guess that even between reading and writing the edge capture register, a edge could get lost, if it is half long and half async to the cpu clock. Am i right?  

I guess so, because read and write are together no atomar operations and take two cpu cycles to handle the capture register. So, if a edge is captured right after i have read the edge capture register but not yet cleared the edge register, it will not get recognized. 

So i come to the conclusion that in certain situations, an edge can get lost. 

 

To avoid this, an atomar instruction which executes in one CPU cycle is needed, which deletes only the bits from the edge register, which has been detected. 

in pseudocode it whould look like this: edgeCapReg=edgeCapReg AND NOT ( bits ) 

I looked to the Altera HAL, but did not find anything simular.  

 

Regards
0 Compliments
4 Réponses
Altera_Forum
Contributeur émérite II
628 Visites

It can be a much longer time between the two instructions : suppose you are running from SDRAM --> when the SDRAM controller decides to insert a refresh cycle just between the fetch of the two instructions, .... 

 

The only easy way to solve this kind of issues is to reset the register in hardware automatically during the read operation. You must hower have a single clock read operation for that. That is the way I do it most of the time.
0 Compliments
Altera_Forum
Contributeur émérite II
628 Visites

 

--- Quote Start ---  

originally posted by svhb@Sep 6 2006, 07:58 AM 

the only easy way to solve this kind of issues is to reset the register in hardware automatically during the read operation. you must hower have a single clock read operation for that. that is the way i do it most of the time. 

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

--- quote end ---  

 

--- Quote End ---  

 

 

Does such an operation exists for nios2 processor?  

Which operation are you using?  

Can you give an example?
0 Compliments
Altera_Forum
Contributeur émérite II
628 Visites

It is in fact how the hardware peripheral response to a read operation on its slave interface. I don&#39;t think you can do in software.  

 

In Verilog HDL it should look like this : 

 

reg LatchedInput; reg InputEdge; assign IrqStatus = IrqEnable & InputEdge; always @*  case (Address)    ...    `IRQ_STATUS : Dout = IrqStatus;  // read out the interrupt status    ...  endcase always @(posedge Clk or posedge Reset)  if (Reset)    begin      InputEdge <= 0;      LatchedInput <= 0;    end  else    begin      LatchedInput <= Input;          // this resets the input edge capture when reading the interrupt status      if (!nRd && Address == `IRQ_STATUS)        InputEdge <= 0;      //this sets the capture register, with higher priority than resetting      //when a new edge occurs just at reading the irq status, it will generate e new interrupt      if (Input && !LatchedInput)        InputEdge <= 1;    end 

 

 

Maybe there is a software trick for it like disabling interrupts, changing order of commands, ... I&#39;m not an "Altera PIO component"-specialist, I usually roll my own. 

 

For the edge capture, I don&#39;t think the miss of an edge is so critical, what happens if a new edge comes in when the older is not processed yet? It is lost anyway. For this you need a counter to remeber how much edges occured.
0 Compliments
Altera_Forum
Contributeur émérite II
628 Visites

Here is working example of edge capture 

volatile int edge_capture_coin; 

 

static void handle_coin_interrupts(void* context, alt_u32 id) 

/* Cast context to edge_capture&#39;s type. It is important that this be  

* declared volatile to avoid unwanted compiler optimization. 

*/ 

volatile int* edge_capture_ptr = (volatile int*) context; 

/* Store the value in the Button&#39;s edge capture register in *context. */ 

*edge_capture_ptr = IORD_ALTERA_AVALON_PIO_EDGE_CAP(COIN_IN_BASE); 

/* Reset the Button&#39;s edge capture register. */ 

IOWR_ALTERA_AVALON_PIO_EDGE_CAP(COIN_IN_BASE, 0); 

 

static void init_coin_in_pio() 

/* Recast the edge_capture pointer to match the alt_irq_register() function 

* prototype. */ 

void* edge_capture_ptr = (void*) &edge_capture_coin; 

/* Enable all 8 ways interrupts. */ 

IOWR_ALTERA_AVALON_PIO_IRQ_MASK(COIN_IN_BASE, 0xff); 

/* Reset the edge capture register. */ 

IOWR_ALTERA_AVALON_PIO_EDGE_CAP(COIN_IN_BASE, 0x0); 

/* Register the interrupt handler. */ 

alt_irq_register( COIN_IN_IRQ, edge_capture_ptr, handle_coin_interrupts );  

 

 

void coin() 

int i,j; 

int exit=1; 

char ch; 

init_coin_in_pio(); 

 

while(1) 

{  

if (edge_capture_coin!=0) 

{  

switch (edge_capture_coin) 

case ACC_COIN0 : printf("\ncoin_in0 - ok"); break; 

case ACC_COIN1 : printf("\ncoin_in1 - ok"); break; 

case ACC_COIN2 : printf("\ncoin_in2 - ok"); break; 

case ACC_COIN3 : printf("\ncoin_in3 - ok"); break; 

case ACC_COIN4 : printf("\ncoin_in4 - ok"); break; 

case ACC_COIN5 : printf("\ncoin_in5 - ok"); break; 

case ACC_COIN6 : printf("\ncoin_in6 - ok"); break; 

case ACC_COIN7 : printf("\ncoin_in7 - ok"); break; 

edge_capture_coin=0; 

}
0 Compliments
Répondre