FreeRTOS: Interrupts on SAM4S

sircorono wrote on Monday, September 18, 2017:

Hi
I’m working for the first time with FreeRTOS using a testboard from Atmel (ATSAM4S-XPRO) with the ARM processor SAM4SD32C (Atmel Studio 7.0, FreeRTOS 9.0) and port ARM_CM3.
http://www.microchip.com/DevelopmentTools/ProductDetails.aspx?PartNO=ATSAM4S-XPRO

I tried to implement an example using interrupts and binary semaphores:

//Declarations and definitions
SemaphoreHandle_t xInterrupt_Semaphore;
void pin_edge_handler(const uint32_t id, const uint32_t index);
void vInterrupt_Task(void *pvParameters);

//****************************INTERRUPT TASKS************************//
//Interrupt function called when a button is pressed
void pin_edge_handler(const uint32_t id, const uint32_t index)
{
	if ((id == ID_PIOA) && (index == PIO_PA2)){
		print_str("Interrupt detected");
		
		BaseType_t xHigherPriorityTaskWoken;
		xHigherPriorityTaskWoken = pdFALSE;
		
		if(xInterrupt_Semaphore != NULL){
			xSemaphoreGiveFromISR( xInterrupt_Semaphore, &xHigherPriorityTaskWoken ); 	
		}
		portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
		
	}
	
}

//Task released by the interrupt function
void vInterrupt_Task(void *pvParameters){
	for(;;){
		//Check Semaphore
		if(xInterrupt_Semaphore != NULL){
			BaseType_t sem_taken =	xSemaphoreTake( xInterrupt_Semaphore, pdMS_TO_TICKS(10000) );
					
			if(sem_taken == pdPASS){
				print_str("Interrupt Task processed");
			}
			else{
				print_str("No Interrupt in 10s");
			}
		}
	}
}


//****************************END INTERRUPT TASKS************************//

//Part of main
int main (void)
{
...

	//Create semaphore
	xInterrupt_Semaphore = xSemaphoreCreateBinary();
		
	if(xInterrupt_Semaphore != NULL){
			
			//Create Task releasd by the interrupt function
			xTaskCreate(vInterrupt_Task,"Interrupt Task",configMINIMAL_STACK_SIZE+1000,NULL,2, &vInterrupt_Task_id);
		
        
			//Configure Interrupt on Pin PA2 (button) with interrupt function "pin_edge_handler"
			pio_handler_set(PIOA, ID_PIOA, PIO_PA2, PIO_IT_FALL_EDGE, pin_edge_handler);
			//Start Interrupt
			pio_enable_interrupt(PIOA, PIO_PA2);
			NVIC_EnableIRQ(PIOA_IRQn);
    }
 vTaskStartScheduler();
}

This does not work, the programm jumps to the following code in the portmacro.h when I press the interrupt button for the first time:

uint32_t ulNewBASEPRI;

	__asm volatile
	(
		"	mov %0, %1												\n"	\
		"	msr basepri, %0											\n" \
		"	isb														\n" \
		"	dsb														\n" \
		:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
	);
}

Pressing the button further times has no effect, the debugger says that I didn’t return to the interrupt task.

As soon as I delete the “xSemaphoreGiveFromISR” line, it works and I can enter the interrupt task several times.

Any idea?

Thanks!

Sebastian

hs2sf wrote on Monday, September 18, 2017:

I might be wrong, but isn’t SAM4S a Cortex-M4 ? In this case you’re bettter off using the ARM_CM4 port.

rtel wrote on Monday, September 18, 2017:

Cortex-M3 devices always use the /source/[compiler]/ARM_CM3 port.

Cortex-M4 devices that do NOT have an MPU use the same port layer as
Cortex-M3 devices.

Cortex-M4 devices that DO have an MPU use the
/source/[compiler]/ARM_CM4F port layer.

Cortex-M7 devices that have an r0p1 core use the
/source/[compiler]/ARM_CM7/r0p1 port layer.

All other Cortex-M7 devices use the same port layer as Cortex-M4 FPU
devices.

rtel wrote on Monday, September 18, 2017:

What happens if you take the call to print_str() out of the ISR?
Printing in interrupts is normally a really bad idea, unless you are
100% sure of the print() functions implementation (the print function
must use a very tiny stack, be thread safe, not mess with interrupts, etc.).

sircorono wrote on Monday, September 18, 2017:

According to this threat:
https://sourceforge.net/p/freertos/discussion/382005/thread/b8ca2d6e/?limit=25#470f

the Sam4S is a Cortex-M4, but there is no ARM_CM4 port. I can use the ARM_CM4F if I enable the floating point unit. I’ve disabled the FPU, so I’m using the ARM_CM3

But I’ve found the problem:
http://www.freertos.org/RTOS-Cortex-M3-M4.html

I need to set a priority fo the interrupt. So I’ve added one line:

			//Interrupt konfigurieren
			pio_handler_set(PIOA, ID_PIOA, PIO_PA2, PIO_IT_FALL_EDGE, pin_edge_handler);
			//Set priority
**			pio_handler_set_priority(PIOA, PIOA_IRQn, 170);**
			//Interrupt am Pin PA2 starten (Button)
			pio_enable_interrupt(PIOA, PIO_PA2);
			NVIC_EnableIRQ(PIOA_IRQn);

But I don’t understand why only priority values between 170 and 255 work. In my FreeRTOS config file:

/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			0x0f

/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	10

/* Interrupt priorities used by the kernel port layer itself.  These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY 		( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

configPRIO_BITS is 4

Shifted with 0:
10<<4 = 10100000 = 160
0x0f<<4 = 11110000 = 240

Shifted with 1:
10<<4 = 10101111 = 175
0x0f<<4 = 11111111 = 255

In my opinion, 175 should be the limit and not 170.

Sebastian

sircorono wrote on Monday, September 18, 2017:

Already tried, didn’t change. I know the print() function is not a good idea, it is just for testing at the moment.

rtel wrote on Monday, September 18, 2017:

Does the pio_handler_set_priority() expect the interrupt to be specified
in the shifted on non-shifted way - as described on the
http://www.freertos.org/RTOS-Cortex-M3-M4.html page you liked to.

Are you using a recent version of FreeRTOS? The more recent the more
assert()s there are to catch priority configuration issues. I would
recommend using the head revision from SVN as I think that will catch
just about all misconfigurations now - assuming configASSERT() is defined.

sircorono wrote on Monday, September 18, 2017:

configAsssert is defined:

#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }

taskDISABLE_INTERRUPTS() is linked to:

portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;

	__asm volatile
	(
		"	mov %0, %1												\n"	\
		"	msr basepri, %0											\n" \
		"	isb														\n" \
		"	dsb														\n" \
		:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
	);
}

That answers the question why I land in this section.

I’m using FreeRTOS 9.0.0.

The pio_handler_set_priority():

...
NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */
...

That solves the problem. The interrupt priority is already shifted, so I need to enter values between 10 and 15. 170 is probably because of an overflow.

Thanks for the help.

Sebastian