XMega interrupt not working (some pins work some don't)

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am for some time busy with programming my own fancontroller and related controls. The last 128a3u which I had I blew up by putting 5V on an input port ....

 

Now I had a new one (after my vacation), so I flashed my software and the new one was coming to live. However unexpectedly not all interrupts are captured.

I have PORTA and PORTE, on PORTA PIN 0 to 4 and on E PIN 0 to 3.

PortA only works with Pin0 to 3 and Port E not at all.

 

I am wondering what I am doing wrong, or what I am missing.

Related code:

 

ISR (PORTA_INT0_vect)
{
	//uint8_t changedbits;
	//uint8_t our_pina;
	register8_t our_pina;
	register8_t changedbits;
	
	our_pina = PORTA.IN; //read once
	
	changedbits = ~porthistoryA & our_pina;
	porthistoryA = our_pina;
	
	// PA0 changed & high 
	if(changedbits & PIN0_bm)
	{
		rpmcount[0]++;
	}
	// PA1 changed & high 
	if(changedbits & PIN1_bm)
	{
		rpmcount[1]++;
	}
	// PA2 changed & high 
	if(changedbits & PIN2_bm)
	{
		rpmcount[2]++;
	}
	// PA3 changed & high 
	if(changedbits & PIN3_bm)
	{
		rpmcount[3]++;
	}
	// PA4 changed & high 
	if(changedbits & PIN4_bm)
	{
		rpmcount[4]++;
	}	
}

ISR (PORTE_INT0_vect)
{
	uint8_t changedbits;
	uint8_t our_pine;
	
	our_pine = PORTE.IN; //read once
	
	changedbits = ~porthistoryE & our_pine;
	porthistoryE = our_pine;
	
	// PE0 changed & high 
	if(changedbits & PIN0_bm)
	{
		rpmcount[5]++;
	}
	// PE1 changed & high 
	if(changedbits & PIN1_bm)
	{
		rpmcount[6]++;
	}
	// PE2 changed & high 
	if(changedbits & PIN2_bm)
	{
		rpmcount[7]++;
	}
	// PE3 changed & high 
	if(changedbits & PIN3_bm)
	{
		rpmcount[8]++;
	}
}

void INPUT_Init()
{
	
	// Configure data direction for PORTA (PIN 0 to 4) 
	PORTA.DIRCLR =  PIN0_bm | PIN1_bm | PIN2_bm | PIN3_bm | PIN4_bm;							// Define all PINS from PORTA as input (0 = input & 1 = output)
	
	// Mask for ports to switch
	//PORTCFG.MPCMASK=0x1F;
	
	// React on both edges and high and low like 0 or 1
	PORTA.PIN0CTRL= PORT_OPC_TOTEM_gc | PORT_ISC_BOTHEDGES_gc;
	PORTA.PIN1CTRL= PORT_OPC_TOTEM_gc | PORT_ISC_BOTHEDGES_gc;
	PORTA.PIN2CTRL= PORT_OPC_TOTEM_gc | PORT_ISC_BOTHEDGES_gc;
	PORTA.PIN3CTRL= PORT_OPC_TOTEM_gc | PORT_ISC_BOTHEDGES_gc;
	PORTA.PIN4CTRL= PORT_OPC_TOTEM_gc | PORT_ISC_BOTHEDGES_gc;

	// Configure Interrupt0 to have low interrupt level, triggered by pin 0, 1 ,2, 3, 4 . 
	//PORT_ConfigureInterrupt0( &PORTA, PORT_INT0LVL_LO_gc, 0x1F );
	
	PORTA.INT0MASK = PIN0_bm | PIN1_bm | PIN2_bm | PIN3_bm | PIN4_bm;
	PORTA.INTCTRL = PORT_INT0LVL_LO_gc;
	
	// Configure data direction for PORTE (PIN 0 to 3) 
	PORTE.DIRCLR = PIN0_bm | PIN1_bm | PIN2_bm | PIN3_bm;											// Define all PINS from PORTE as input (0 = input & 1 = output)
		
	// Mask for ports to switch
	//PORTCFG.MPCMASK=0x1F;
		
	// React on both edges and high and low like 0 or 1
	PORTE.PIN0CTRL= PORT_OPC_TOTEM_gc | PORT_ISC_BOTHEDGES_gc;
	PORTE.PIN1CTRL= PORT_OPC_TOTEM_gc | PORT_ISC_BOTHEDGES_gc;
	PORTE.PIN2CTRL= PORT_OPC_TOTEM_gc | PORT_ISC_BOTHEDGES_gc;
	PORTE.PIN3CTRL= PORT_OPC_TOTEM_gc | PORT_ISC_BOTHEDGES_gc;

	// Configure Interrupt0 to have low interrupt level, triggered by pin 0, 1 ,2, 3. 
	//PORT_ConfigureInterrupt0( &PORTE, PORT_INT0LVL_LO_gc, 0x1F );
	PORTE.INT0MASK = PIN0_bm | PIN1_bm | PIN2_bm | PIN3_bm;
	PORTE.INTCTRL = PORT_INT0LVL_LO_gc;
	
}

int main(void)
{
	// Initialize program parameters/functionalities
	
	cli();													// Disable interrupt
	CPUfreq();												// Initialize CPU
	INPUT_Init();											// Initialize Input ports & Input interrupt
	OUTPUT_Init();											// Initialize Output ports
	timer_init();											// Initialize Timer
	
	
	//PWM_Init();												// Initialize PWM
	Init_uart();											// Initialize UART functionality

	
	
	// Release High-,Medium- and Low level Interrupts
	PMIC.CTRL |= PMIC_HILVLEN_bm |PMIC_MEDLVLEN_bm|PMIC_LOLVLEN_bm;
	
	// Start Program
	sei();	
}

Do I need to set a fuse bit (have been looking through this, but does not seem have any options applicable to me. Furthermore can't remember that I did this with the last one AND cannot find anything in the manual for these PORTA and E)

This topic has a solution.

Last Edited: Mon. Jan 25, 2016 - 02:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmz, strange, seems to be a problem with rpmcount[0] to rpmcount[8] -> till rpmcount[3] it works, above does not...

Tomorrow a new day

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Put infinite loop at end of your main() function. Refer this example for further understanding.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Mandar Joshi wrote:

Put infinite loop at end of your main() function. Refer this example for further understanding.

@ Sebas06, The reason for this is that the code that calls main() looks like this:

void _exit(void){
    cli();
    while(1);
}

void CRT(void) {
    R1 = 0;
    SREG = R1;
    SP = RAMEND;
    _do_copy_data();
    _do_copy_bss();
    main();
    _exit();
}

So if you return from main() you will go to _exit: and there it will immediatley cli() then enter an infinite loop. As such you won't get interrupts once the CLI has acted. You were actually luck to get even one if you did!!

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Found the code this morning. The above parts are just snippets from the complete code. While I was thinking it had to be in those parts.

While I had no device to test I also changed the array memcpy and memset to "variable".

 

Instead of the length of the array (uint_16) I was taking the amount of elements in the array (9->8 if counting with 0), this is actually copying only the first 4.5 elements, because a uint_16 consists of 2 bytes. Changed it to underneath code:

 

	timer_tick ++;
	if (timer_tick == SAMPLERATE){
		// Trigger frequency calculation
		flag=1;
		memcpy(rpmcalc, rpmcount, 2+ sizeof(rpmcount));		// copy contents of rpmcount so interrupt can stay running					
		memset(rpmcount, 0, 2+ sizeof(rpmcount));			// Reset array "rpmcount"
		timer_tick = 0;										// Reset timer
	}

So now the rpm reader is working again and can return to building my PWM reader.