GPIO Ngắt phát hành


7

Tôi đã làm theo hướng dẫn này, Raspberry Pi GPIO ngắt trong không gian kernel , để tạo một mô-đun hạt nhân xử lý ngắt GPIO. Vấn đề là mã này không có phần mềm gỡ lỗi được triển khai.

Bạn có thể vui lòng cho tôi lời khuyên về cách thực hiện gỡ lỗi phần mềm, hoặc cách khác, làm thế nào để dễ dàng thực hiện một hệ thống gỡ lỗi phần cứng?


Bạn có thể di chuyển mã của mình đến phần trả lời (bạn có thể trả lời câu hỏi của riêng mình). Cách này sẽ sạch hơn nhiều. Hãy nhớ rằng, đây không phải là một diễn đàn.
Krzysztof Adamski

Câu trả lời:


7

Tôi chưa bao giờ thử làm điều này không có RPi, nhưng tôi đã có trên nền tảng Arduino nhiều lần và tôi đã sử dụng một cái gì đó dọc theo dòng mã Arduino này. Lưu ý bạn sẽ phải viết lại một chức năng tương tự như vậy cho bất kỳ ngôn ngữ nào bạn đang sử dụng:

unsigned long last_interrupt_time = 0;

void my_interrupt_handler()
{
  unsigned long interrupt_time = millis();
  // If interrupts come faster than 200ms, assume it's a bounce and ignore
  if (interrupt_time - last_interrupt_time > 200) 
  {
    ... Interrupt okay, do something;
  }
  last_interrupt_time = interrupt_time;
}

ok, tôi đã thực hiện nó ... millis () không phải là hàm Raspberry, vì vậy tôi phải tự thực hiện nó. Đây là mã nguồn được sửa đổi
Flavio Barisi

@FlavioBarisi Xin lỗi về điều đó. Đây là mã cho Arduino, chỉ bao gồm làm ví dụ. Tôi đã không có thời gian ngày hôm qua để viết lại nó bằng Python của C. Tôi sẽ ghi chú điều đó trong câu trả lời.
Butters

1

đơn giản nhất là trình gỡ lỗi phần cứng, bao gồm bộ lọc RC theo sau là trình kích hoạt schmitt hoặc chỉ bộ lọc RC, nếu bạn lười biếng. các bộ phận rẻ tiền, có sẵn ở mọi nơi và có thể dễ dàng chứa trong bất kỳ mạch nào bạn sẽ kết nối với Raspberry Pi.


1

Thực hiện nó!

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/time.h>

#define DRIVER_AUTHOR "Igor <hardware.coder@gmail.com>"
#define DRIVER_DESC   "Tnterrupt Test"

// we want GPIO_17 (pin 11 on P5 pinout raspberry pi rev. 2 board)
// to generate interrupt
#define GPIO_ANY_GPIO                17

// text below will be seen in 'cat /proc/interrupt' command
#define GPIO_ANY_GPIO_DESC           "Some gpio pin description"

// below is optional, used in more complex code, in our case, this could be
// NULL
#define GPIO_ANY_GPIO_DEVICE_DESC    "some_device"


/****************************************************************************/
/* Interrupts variables block                                               */
/****************************************************************************/
short int irq_any_gpio    = 0;

unsigned int last_interrupt_time = 0;
static uint64_t epochMilli;

unsigned int millis (void)
{
  struct timeval tv ;
  uint64_t now ;

  do_gettimeofday(&tv) ;
  now  = (uint64_t)tv.tv_sec * (uint64_t)1000 + (uint64_t)(tv.tv_usec / 1000) ;

  return (uint32_t)(now - epochMilli) ;
}

/****************************************************************************/
/* IRQ handler - fired on interrupt                                         */
/***************************************************************************/
static irqreturn_t r_irq_handler(int irq, void *dev_id, struct pt_regs *regs) {
   unsigned long flags;
   unsigned int interrupt_time = millis();

   if (interrupt_time - last_interrupt_time < 1000) 
   {
     printk(KERN_NOTICE "Ignored Interrupt!!!!! [%d]%s \n",
          irq, (char *) dev_id);
     return IRQ_HANDLED;
   }
   last_interrupt_time = interrupt_time;

   // disable hard interrupts (remember them in flag 'flags')
   local_irq_save(flags);

   printk(KERN_NOTICE "Interrupt [%d] for device %s was triggered !.\n",
          irq, (char *) dev_id);

   // restore hard interrupts
   local_irq_restore(flags);

   return IRQ_HANDLED;
}




/****************************************************************************/
/* This function configures interrupts.                                     */
/****************************************************************************/
void r_int_config(void) {

  struct timeval tv ;

  do_gettimeofday(&tv) ;
  epochMilli = (uint64_t)tv.tv_sec * (uint64_t)1000    + (uint64_t)(tv.tv_usec / 1000) ;

   if (gpio_request(GPIO_ANY_GPIO, GPIO_ANY_GPIO_DESC)) {
      printk("GPIO request faiure: %s\n", GPIO_ANY_GPIO_DESC);
      return;
   }

   if ( (irq_any_gpio = gpio_to_irq(GPIO_ANY_GPIO)) < 0 ) {
      printk("GPIO to IRQ mapping faiure %s\n", GPIO_ANY_GPIO_DESC);
      return;
   }

   printk(KERN_NOTICE "Mapped int %d\n", irq_any_gpio);

   if (request_irq(irq_any_gpio,
                   (irq_handler_t ) r_irq_handler,
                   IRQF_TRIGGER_FALLING,
                   GPIO_ANY_GPIO_DESC,
                   GPIO_ANY_GPIO_DEVICE_DESC)) {
      printk("Irq Request failure\n");
      return;
   }

   return;
}


/****************************************************************************/
/* This function releases interrupts.                                       */
/****************************************************************************/
void r_int_release(void) {

   free_irq(irq_any_gpio, GPIO_ANY_GPIO_DEVICE_DESC);
   gpio_free(GPIO_ANY_GPIO);

   return;
}


/****************************************************************************/
/* Module init / cleanup block.                                             */
/****************************************************************************/
int r_init(void) {

   printk(KERN_NOTICE "Hello !\n");
   r_int_config();

   return 0;
}

void r_cleanup(void) {
   printk(KERN_NOTICE "Goodbye\n");
   r_int_release();

   return;
}


module_init(r_init);
module_exit(r_cleanup);


/****************************************************************************/
/* Module licensing/description block.                                      */
/****************************************************************************/
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);

1

Điều gì nếu bạn theo dõi giá trị / điều kiện trước đó của pin / GPIO?

Tôi đã phải sử dụng usleep()trong vòng lặp while để tránh việc đập / đua CPU, Xem câu trả lời này cho C, lỗi biên dịch trong khi sử dụng chức năng của us us ngủ .

Điều này hoạt động cho mục đích của tôi:

#include <unistd.h>
uint8_t prevStatus;

void sendStatus (void) {
        uint8_t status = digitalRead(ISR_Pin);
        if (prevStatus != status) {
                if (status == 0)
                         falling();
                else
                         rising();
        }
        prevStatus = status;
}


int main (void) {
    /// Make sure WiringPi is installed and cofigured
    if ( wiringPiSetup() == -1 )
        exit( 1 );

    /// Set-up GPIO as INPUT, with Pull-down
    pinMode (ISR_Pin, INPUT);
    pullUpDnControl(TISR_Pin, PUD_DOWN); // If you need it or PUD_UP for Pull-up

    /// Set-up Hardware Interrupt for BOTH Falling & Rising Edge
    wiringPiISR(ISR_Pin, INT_EDGE_BOTH, &sendStatus);

    /// Wait for ISR_Pin pin change
    while (1) {
         usleep(50000);
    }

    return(0);
}

1

Tôi đã làm điều đó bằng cách kiểm tra các jiffies thay vì thời gian. Tôi nghĩ rằng có ít chi phí theo cách này. Tuy nhiên, tôi vẫn đang tìm cách cải thiện thuật toán gỡ lỗi vì tôi không hoàn toàn hài lòng với nó: vẫn có những lần thoát mặc dù chúng ít thường xuyên hơn trước.

#include <linux/jiffies.h>

extern unsigned long volatile jiffies;

static irqreturn_t irq_handler(int irq, void *dev_id, struct pt_regs *regs) {

   static unsigned long old_jiffie = 0;
   unsigned long diff = jiffies - old_jiffie;
   if (diff < 20)
   {
     return IRQ_HANDLED;
   }

   printk(KERN_NOTICE "Interrupt [%d] for device %s was triggered, jiffies=%lu, diff=%lu, direction: %d \n",
          irq, (char *) dev_id, jiffies, diff, gpio_get_value(GPIO_BUTTON1));

   old_jiffie = jiffies;
   return IRQ_HANDLED;
}

Tôi đã quản lý để tinh chỉnh thêm thuật toán gỡ lỗi. Bây giờ tôi kích hoạt ngắt khi dòng đạt đến THẤP thay vì cạnh giảm. Sau đó, trong trình xử lý ngắt, sau đó tôi thay đổi ngắt để kích hoạt ở mức CAO vào lần tới, sau đó ở mức THẤP và cứ thế. Điều này kết hợp với phương pháp jiffies từ trên làm giảm đáng kể các lần thoát.

Tôi nghĩ đó là thứ tốt nhất có thể đạt được trong phần mềm. Để cải thiện hơn nữa tôi nghĩ rằng điều này phải được thực hiện trong phần cứng, thực sự. Khi tôi có thời gian tôi sẽ thử với một tụ điện và những thứ như thế này.

Mã đầy đủ dưới đây:

#include <linux/module.h>   
#include <linux/kernel.h>   
#include <linux/init.h>

#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/jiffies.h>

#define DRIVER_AUTHOR ""
#define DRIVER_DESC   "Button pad"


extern unsigned long volatile jiffies;
struct _Button
{
    unsigned gpio;
    int irq;
    const char* description;
    char last_value;
};
typedef struct _Button Button;

// we want GPIO's 17,27,22 (pin 11,13,15 on P5 pinout raspberry pi rev. 2 board) to generate interrupt
Button button1 = {17, 0, "Gpio for button 1", 1 };
Button button2 = {27, 0, "Gpio for button 2", 1 };
Button button3 = {22, 0, "Gpio for button 3", 1 };

/****************************************************************************/
/* IRQ handler - fired on interrupt                                         */
/****************************************************************************/
static irqreturn_t irq_handler(int irq, void *dev_id, struct pt_regs *regs) 
{
   Button* button = (Button*) dev_id; 
   char value = gpio_get_value(button->gpio);

   if (value == button->last_value)
       return IRQ_HANDLED;

   if (0 == value)
   {
        static unsigned long old_jiffie = 0;
        unsigned long diff = jiffies - old_jiffie;
        if (diff < 23)
        {
          button->last_value = value;
          irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
          // old_jiffie = jiffies;
          return IRQ_HANDLED;
        }

        printk(KERN_NOTICE "Interrupt [%d] for device %s was triggered, jiffies=%lu, diff=%lu, direction: %d \n",
               irq, button->description, jiffies, diff, value);
        irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
        old_jiffie = jiffies;
   }

   else
   {
     irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
   }

   button->last_value = value;
   return IRQ_HANDLED;
}
/****************************************************************************/
/* This function configures interrupts.                                     */
/****************************************************************************/
void int_config(Button* button)
{
   if (!button || gpio_request(button->gpio, button->description)) {
      printk("GPIO request faiure: %s\n", button->description);
      return;
   }
   gpio_direction_input(button->gpio);

   if ( (button->irq = gpio_to_irq(button->gpio)) < 0 ) {
      printk("GPIO to IRQ mapping faiure %s\n", button->description);
      return;
   }

   printk(KERN_NOTICE "Mapped int %d\n", button->irq);

   if (request_irq(button->irq,
                   (irq_handler_t ) irq_handler,
                   IRQF_TRIGGER_LOW,
                   button->description,
                   button)) {
      printk("Irq Request failure\n");
      return;
   }
   return;
}

/****************************************************************************/
/* This function releases interrupts.                                       */
/****************************************************************************/
void int_release(Button* button) {

   free_irq(button->irq, button);
   gpio_free(button->gpio);

   return;
}

int init_module(void)
{
    printk(KERN_INFO "init_module() called\n");
    int_config(&button1);
        int_config(&button2);
        int_config(&button3);

    return 0;
}

void cleanup_module(void)
{
    printk(KERN_INFO "cleanup_module() called\n");
    int_release(&button1);
    int_release(&button2);
    int_release(&button3);
}

/****************************************************************************/
/* Module licensing/description block.                                      */
/****************************************************************************/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("");
MODULE_DESCRIPTION("Driver for RaspeberryPi's GPIO");
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.