You are here

Custom App using Interrupt

12 posts / 0 new
Last post
CTSchorsch
Offline
Last seen: 4 months 2 weeks ago
VESC Free
Joined: 2018-07-13 09:55
Posts: 101
Custom App using Interrupt

Dear all,

i want to use a pin change interrupt in a custom application. There is less documentation, but i figured out how to set up the interrupt, but the vesc crashes when the interrupt occours.

Do i have to configure GPIOC 14/15 in a special way because the pins are OSC_OUT ?  Or is the interrupt init at the wrong place ?

Thanks in advance

GEorg

hwconf/hw_gsvesc.h:

...
//Trigger and Speed Hall Pins
#define HW_HALL_TRIGGER_GPIO            GPIOC
#define HW_HALL_TRIGGER_PIN             13
#define HW_HALL_ROTARY_A_GPIO           GPIOC
#define HW_HALL_ROTARY_A_PIN            14
#define HW_HALL_ROTARY_B_GPIO           GPIOC
#define HW_HALL_ROTARY_B_PIN            15
#define HW_HALL_ROTARY_A_EXTI_PORTSRC   EXTI_PortSourceGPIOC
#define HW_HALL_ROTARY_A_EXTI_PINSRC    EXTI_PinSource14
#define HW_HALL_ROTARY_A_EXTI_CH        EXTI15_10_IRQn
#define HW_HALL_ROTARY_A_EXTI_LINE      EXTI_Line14
#define HW_HALL_ROTARY_A_EXTI_ISR_VEC   EXTI15_10_IRQHandler
...

application/app_dpv.c:

#include "ch.h" // ChibiOS
#include "hal.h" // ChibiOS HAL
#include "mc_interface.h" // Motor control functions
#include "hw.h" // Pin mapping on this hardware
#include "timeout.h" // To reset the timeout
#include "commands.h" //just for printf in terminal
#define AVAILABLE_POWERS 3

CH_IRQ_HANDLER(HW_HALL_ROTARY_A_EXTI_ISR_VEC) {
        if (EXTI_GetITStatus(HW_HALL_ROTARY_A_EXTI_LINE) != RESET) {

                commands_printf("Rotary A Interrupt fired");
                // Clear the EXTI line pending bit
                EXTI_ClearITPendingBit(HW_HALL_ROTARY_A_EXTI_LINE);
        }
}

// Diving Vehicle thread
static THD_FUNCTION(dpv_thread, arg);
static THD_WORKING_AREA(dpv_thread_wa, 2048); // 2kb stack for this thread

void app_dpv_init(void) {
        EXTI_InitTypeDef   EXTI_InitStructure;

        // Set the UART TX pin as an input with pulldown
        palSetPadMode(HW_HALL_TRIGGER_GPIO, HW_HALL_TRIGGER_PIN, PAL_MODE_INPUT_PULLUP);
        palSetPadMode(HW_HALL_ROTARY_A_GPIO, HW_HALL_ROTARY_A_PIN, PAL_MODE_INPUT_PULLUP);
        palSetPadMode(HW_HALL_ROTARY_B_GPIO, HW_HALL_ROTARY_B_PIN, PAL_MODE_INPUT_PULLUP);

        // Interrupt on HALL ROTARY A Pin
        // Connect EXTI Line to pin
        SYSCFG_EXTILineConfig(HW_HALL_ROTARY_A_EXTI_PORTSRC, HW_HALL_ROTARY_A_EXTI_PINSRC);

        // Configure EXTI Line
        EXTI_InitStructure.EXTI_Line = HW_HALL_ROTARY_A_EXTI_LINE;
        EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
        EXTI_InitStructure.EXTI_LineCmd = ENABLE;
        EXTI_Init(&EXTI_InitStructure);

        // Enable and set EXTI Line Interrupt to the highest priority
        nvicEnableVector(HW_HALL_ROTARY_A_EXTI_CH, 0);

       chThdCreateStatic(dpv_thread_wa, sizeof(dpv_thread_wa),
                NORMALPRIO, dpv_thread, NULL);
}

static THD_FUNCTION(dpv_thread, arg) {
        (void)arg;

        chRegSetThreadName("app_dpv");
        static bool need_to_change_power_in_future = false;
        static float power[AVAILABLE_POWERS] = {0.7, 1, 0.5};
        static int power_index = 0;

 

        for(;;) {

                if (palReadPad(HW_HALL_TRIGGER_GPIO, HW_HALL_TRIGGER_PIN)) {
                        mc_interface_set_duty(power[power_index]);
                        need_to_change_power_in_future = true;
                } else {
                        if(need_to_change_power_in_future){
                                need_to_change_power_in_future = false;
                                power_index=(power_index+1)%AVAILABLE_POWERS;
                        }
                        // If the button is not pressed, release the motor
                        mc_interface_release_motor();
                }

                // Run this loop at 100Hz
                chThdSleepMilliseconds(10);

                // Reset the timeout
                timeout_reset();
        }
}

 

 

 

 

CTSchorsch
Offline
Last seen: 4 months 2 weeks ago
VESC Free
Joined: 2018-07-13 09:55
Posts: 101

mmh, second post with no answer. maybe i should leave the Free Status ?

 

gpzhao
Offline
Last seen: 5 years 3 weeks ago
VESC Original
Joined: 2018-01-28 13:02
Posts: 3

I have a similar interrupt problem (see my post here https://vesc-project.com/node/377). Really like to know how to trigger the communication in the custom app with interrupts. 

CTSchorsch
Offline
Last seen: 4 months 2 weeks ago
VESC Free
Joined: 2018-07-13 09:55
Posts: 101

Hi gpzhao,

i solved the interrupt problem. i don't know if i did it in the "vesc" way, but it works for me :)

Have a look at https://github.com/CTSchorsch/blcd in the app_dpv branch. there is a application/app_dpv.c file where i set up the interrupt this way:

   // Interrupt on HALL ROTARY A Pin
        // Connect EXTI Line to pin
        SYSCFG_EXTILineConfig(HW_HALL_ROTARY_A_EXTI_PORTSRC, HW_HALL_ROTARY_A_EXTI_PINSRC);

        // Configure EXTI Line
        EXTI_InitStructure.EXTI_Line = HW_HALL_ROTARY_A_EXTI_LINE;
        EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
        EXTI_InitStructure.EXTI_LineCmd = ENABLE;
        EXTI_Init(&EXTI_InitStructure);

        // Enable and set EXTI Line Interrupt to the highest priority
        nvicEnableVector(HW_HALL_ROTARY_A_EXTI_CH, 0);

the interrupt handler is found in irq_handlers.c

i add:

H_IRQ_HANDLER(HW_HALL_ROTARY_A_EXTI_ISR_VEC) {
        if (EXTI_GetITStatus(HW_HALL_ROTARY_A_EXTI_LINE) != RESET) {
                dpv_rotary_isr();
                // Clear the EXTI line pending bit
                EXTI_ClearITPendingBit(HW_HALL_ROTARY_A_EXTI_LINE);
        }
}

If i understand the datasheet correctly, you have only one Interrupt per PIN Number. so watch out if there are any other pins with interrupt functions

Regards Georg

TechAUmNu
Offline
Last seen: 3 months 1 week ago
Joined: 2017-09-22 01:27
Posts: 575

I wouldn't set your app interrupt to the highest priority...

CTSchorsch
Offline
Last seen: 4 months 2 weeks ago
VESC Free
Joined: 2018-07-13 09:55
Posts: 101

Hi TechAUmNu,

thanks, yes maybe. I thought about it too.

But, can you explain why ? I found this somewhere in another custom app and copy it

Regards

Georg

TechAUmNu
Offline
Last seen: 3 months 1 week ago
Joined: 2017-09-22 01:27
Posts: 575

I don't know what other interrupts are being used, but generally system critical stuff is highest priority like system timer. User inputs are normally fairly slow so can tolerate being on a lower priority.

benjamin
Offline
Last seen: 2 weeks 1 hour ago
VESC FreeVESC OriginalVESC Platinum
Joined: 2016-12-26 15:20
Posts: 490

Regarding interrupts in applications, as CTSchorsch pointed out, there many pins often share the same ISR handler, which can be a problem if it is used somewhere else. In the latest version of ChibiOS, the PAL driver has pin interrupt support and makes it super easy to set up interrupts and interrupt handlers. I'm planning to move to that version soon, but it requires a bit of work and testing. After that I will make an example custom app that uses interrupts, terminal callbacks and the now supported IMU and AHRS filter. For now you can go with the example above.

One thing you have to keep in mind though is that you cannot use any communication functions from interrupts, and most mc_interface functions are unsafe. What you can do instead is something like this:

// Note: This code is untested and might not even compile...

static THD_WORKING_AREA(isr_thd_wa, 2048);
static THD_FUNCTION(isr_thd, arg);
static thread_t *isr_tp;

void init(void) {
	// Set up interrupt..

	// Start thread
	chThdCreateStatic(isr_thd_wa, sizeof(isr_thd_wa),
		NORMALPRIO, isr_thd, NULL);
}

void interrupt_handler(void) {
	// Trigger thread to run once
	chSysLockFromISR();
	chEvtSignalI(isr_tp, (eventmask_t)1);
	chSysUnlockFromISR();
}

static THD_FUNCTION(log_uart_thread, arg) {
	(void)arg;

	chRegSetThreadName("ISR");

	isr_tp = chThdGetSelfX();

	for (;;) {
		chEvtWaitAny((eventmask_t) 1);
		
		// Run your code from here
	}
}

Here a thread is waiting for an event, which is generated from the interrupt handler causing the thread to run one iteration in the loop. ChibiOS should reschedule directly after exiting the interrupt, so the thread should be activated quickly. From the thread you can then use all functions safely.

CTSchorsch
Offline
Last seen: 4 months 2 weeks ago
VESC Free
Joined: 2018-07-13 09:55
Posts: 101

Hi Benjamin,

thanks for your reply. Just for my understanding: the mc_interface is unsafe if this functions are used IN an interrupt service routine ? the use in the custom app thread is safe ?

Georg

benjamin
Offline
Last seen: 2 weeks 1 hour ago
VESC FreeVESC OriginalVESC Platinum
Joined: 2016-12-26 15:20
Posts: 490

That is correct, everything in mc_interface (and most functions in other files) are safe to use from threads.

CTSchorsch
Offline
Last seen: 4 months 2 weeks ago
VESC Free
Joined: 2018-07-13 09:55
Posts: 101

Hi again,

i updated to FW 3.53 this night. Now my custom app is not working any more :(

Did you change something in the interrupt handling ? Is now something use external interrupt on pin14 ?

Regards Georg

foxthefox
Offline
Last seen: 8 months 2 weeks ago
Joined: 2022-02-23 21:45
Posts: 1

Hi Benjamin,

any news on updating to a newer ChibiOS ?

As you said Pin Interrupt support on the new ChibiOS is really neat and easy to use.

Would appreciate it.

best regards

Thomas