PIC32 _CHANGE_NOTICE_VECTOR freezes running processes

robertloejr wrote on Tuesday, December 01, 2015:

I’m working with the PIC32 USB Starter Kit II with a PIC32MX795F512L. The 18 sample software projects provided by FreeRTOS.org in the purchased manual used version 7.5.3.

I made a project that creates a CHANGE_NOTICE_VECTOR interrupt that responds to an SW1 button press. In addition, I created another task that flashes an LED (25ms ON / 50ms OFF).

When I press SW1, I get a message from my task that responds to the interrupt, but I notice the LED flashing is interrupted. When I press and hold SW1, the LED does not flash at all, and I don’t get my message until I release SW1.

I tried increasing the priority of my LED flashing task. I also switched from using assembly code for the interrupt to straight C. I looked for other configuration settings for the change notice. Nothing seems to help.

I also have a UART2 interrupt and related task that seems to operate properly without affecting the LED flash rate.

Any help would be appreciated.

Code:

#include <p32xxxx.h>
#include <plib.h>

#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "basic_io.h"

#pragma config FPLLODIV = DIV_1, FPLLMUL = MUL_20, FPLLIDIV = DIV_2
#pragma config FWDTEN = OFF, FPBDIV = DIV_2, POSCMOD = XT, FNOSC = PRIPLL, CP = OFF
#pragma config FSRSSEL = PRIORITY_7

static void vHandlerTask( void *pvParameters );
static void vHandlerTask2( void *pvParameters );

void vSetupEnvironment( void );
static void vTimerFunction( void *pvParameters );

xSemaphoreHandle xBinarySemaphore, xBinarySemaphore2;

#define DESIRED_BAUDRATE (9600)
#define SYSCLK (80000000L)

#define MAXCOMMANDSIZE 256
char CommandString[MAXCOMMANDSIZE];
int CommandLoc = 0;

int main( void ) {
    vSetupEnvironment();

    vSemaphoreCreateBinary( xBinarySemaphore );
    vSemaphoreCreateBinary( xBinarySemaphore2 );

    if( xBinarySemaphore != NULL && xBinarySemaphore2 != NULL) {
        xTaskCreate( vHandlerTask, ( signed char * ) "Handler", 240, NULL, 2, NULL );
        xTaskCreate( vHandlerTask2, ( signed char * ) "Handler 2", 240, NULL, 2, NULL );
		xTaskCreate( vTimerFunction, ( signed char * ) "LED Task", 240, NULL, 3, NULL );
        vTaskStartScheduler();
    }

    for( ;; );
    return 0;
}

static void vHandlerTask( void *pvParameters ) {
    xSemaphoreTake( xBinarySemaphore, 0 );

    for( ;; ) {
        xSemaphoreTake( xBinarySemaphore, portMAX_DELAY );
		putsUART2("Command string: ");
		putsUART2(CommandString);
		putsUART2("\n");
		CommandLoc = 0;
    }
}

static void vHandlerTask2( void *pvParameters ) {
    xSemaphoreTake( xBinarySemaphore2, 0 );

    for( ;; ) {
        xSemaphoreTake( xBinarySemaphore2, portMAX_DELAY );
		putsUART2("button event\n");
    }
}

void __ISR(_CHANGE_NOTICE_VECTOR, ipl1) vButtonISRHandler(void) {
	long sHigherPriorityTaskWoken = pdFALSE;

    mCNClearIntFlag();
	xSemaphoreGiveFromISR( xBinarySemaphore2, &sHigherPriorityTaskWoken );
    portEND_SWITCHING_ISR( sHigherPriorityTaskWoken );
}

void __ISR(_UART2_VECTOR, ipl2) IntUart2Handler(void) {
	unsigned int ch;
	long sHigherPriorityTaskWoken = pdFALSE;

	if(INTGetFlag(INT_SOURCE_UART_RX(UART2))) {
	    INTClearFlag(INT_SOURCE_UART_RX(UART2));

		while (DataRdyUART2()) {
			ch = getcUART2();
			putcUART2(ch);
			if (ch == 10 || ch == 13) {
				if (CommandLoc > 0)
					xSemaphoreGiveFromISR( xBinarySemaphore, &sHigherPriorityTaskWoken );
			}
			else if (CommandLoc < MAXCOMMANDSIZE-1) {
				CommandString[CommandLoc++] = ch;
				CommandString[CommandLoc] = 0;
			}
			else {
				xSemaphoreGiveFromISR( xBinarySemaphore, &sHigherPriorityTaskWoken );
			}
		}
	}

	if ( INTGetFlag(INT_SOURCE_UART_TX(UART2)) ) {
            INTClearFlag(INT_SOURCE_UART_TX(UART2));
	}

    portEND_SWITCHING_ISR( sHigherPriorityTaskWoken );
}

void vSetupEnvironment( void ) {
	unsigned int dummy;
	int pbClk;

    SYSTEMConfigPerformance( configCPU_CLOCK_HZ );
    mOSCSetPBDIV( OSC_PB_DIV_2 );

   	mPORTDClearBits(BIT_0 | BIT_1 | BIT_2);
   	mPORTDSetPinsDigitalOut(BIT_0 | BIT_1 | BIT_2 );
    PORTSetPinsDigitalIn(IOPORT_D, BIT_6 | BIT_7);

    mCNOpen((CN_ON | CN_FRZ_OFF), (CN15_ENABLE), 0);
    dummy = mPORTDRead();
	ConfigIntCN((CHANGE_INT_ON | CHANGE_INT_PRI_1));

	pbClk=SYSTEMConfig( SYSCLK, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

	OpenUART2( UART_EN, UART_RX_ENABLE | UART_TX_ENABLE, pbClk/16/DESIRED_BAUDRATE-1);

	INTEnable(INT_SOURCE_UART_RX(UART2), INT_ENABLED);
	INTSetVectorPriority(INT_VECTOR_UART(UART2), INT_PRIORITY_LEVEL_2);
	INTSetVectorSubPriority(INT_VECTOR_UART(UART2), INT_SUB_PRIORITY_LEVEL_0);

	INTConfigureSystem(INT_SYSTEM_CONFIG_MULT_VECTOR);

    INTEnableSystemMultiVectoredInt();

	while( BusyUART2());
	putsUART2( "Startup\r\n");
}

static void vTimerFunction( void *pvParameters ) {
	const int DLY1 = 25;
	const int DLY2 = 50;
	portTickType xLastWakeTime;

	mPORTDClearBits(BIT_2);
	xLastWakeTime = xTaskGetTickCount();

	for( ;; ) {
		mPORTDSetBits(BIT_2);
		vTaskDelayUntil( &xLastWakeTime, DLY1 / portTICK_RATE_MS );

		mPORTDClearBits(BIT_2);
		vTaskDelayUntil( &xLastWakeTime, DLY2 / portTICK_RATE_MS );
	}
}

rtel wrote on Wednesday, December 02, 2015:

Is the button interrupt edge or level sensitive? If it is level sensitive then you may be continuously re-entering the interrupt while the button is being held down, preventing other code from running.

Regards.

robertloejr wrote on Thursday, December 03, 2015:

Thanks for your response. I looked through the PIC32 manual, and unless I missed something, there is no way to set the CNx inputs to a rising or falling edge. The INT0 - INT4 external inputs do allow an edge setting. I will try INT0 and see if it solves the problem.

tlafleur wrote on Thursday, December 03, 2015:

Not true, I do not have the data sheet here, but you can set edge or state on each pin for interrupt. Re read data sheet.

tlafleur wrote on Thursday, December 03, 2015:

“The CNENx registers contain the CN interrupt enable control bits for each of the input pins. Setting any of these bits enables a CN interrupt for the corresponding pins.”

This will give you an interrupt when a pin changes state, you must in the interrupt service routine, clear the interrupt, check if it’s a state you are looking for, set a flag or mutex, exit the routine… It will only interrupt on a pin state change, a 1 to a 0, or a 0 to a 1

tlafleur wrote on Thursday, December 03, 2015:

It interrupts on BOTH edge, so a small state machine can set a flag on edge you want.

robertloejr wrote on Thursday, December 03, 2015:

It doesn’t seem to interrupt on both edges. I get an interrupt only when the button is released. I don’t have a problem getting the change notice interrupt. The problem is: when the button is held down the other running processes halt.

robertloejr wrote on Thursday, December 03, 2015:

INT0 / RD0 was tied to an LED on the board so I used INT1. There were no problems with the LED flashing when multiple interrupts were generated on INT1.

void __ISR(_EXTERNAL_1_VECTOR, ipl1) vExternalInterrupt1(void)
{
	long sHigherPriorityTaskWoken = pdFALSE;
	mINT1ClearIntFlag();

	xSemaphoreGiveFromISR( xBinarySemaphore2, &sHigherPriorityTaskWoken );
    portEND_SWITCHING_ISR( sHigherPriorityTaskWoken );
}

//inside SetupEnvironment:

	ConfigINT1(EXT_INT_PRI_1 | FALLING_EDGE_INT | EXT_INT_ENABLE);

rtel wrote on Friday, December 04, 2015:

Run the code in the debugger, press and hold the button so the symptom shows itself, then while holding down the button pause the debugger…which code is running?

robertloejr wrote on Friday, December 04, 2015:

It turns out I was missing a call to mPORTDRead() in the interrupt handler. That is why I did not get an interrupt on both edges as stated by lafleur. With the following code I can press the button without interferring with the LED flashing.

void __ISR(_CHANGE_NOTICE_VECTOR, ipl1) vButtonISRHandler(void)
{
	long sHigherPriorityTaskWoken = pdFALSE;
	mPORTDRead();
    mCNClearIntFlag();

	xSemaphoreGiveFromISR( xBinarySemaphore2, &sHigherPriorityTaskWoken );
    portEND_SWITCHING_ISR( sHigherPriorityTaskWoken );
}