linux中断响应gpio中断太慢是什么原因?

hello_world000 2012-09-25 11:55:51
测试发现linux上半部响应GPIO中断的时间有时会慢到20ms之后才响应?大家有遇到这种问题吗?
我们是这样测试的,在一个MCU(装的实时操作系统)里每隔10ms通过一个gpio向CPU发送中断,在LINUX这边的中断服务程序再通过另外一个gpio去中断MCU,MCU接收到中断之后计算中断的环回时间,测试10万次,大多是不到一个毫秒,但出现20ms左右的情况的概率是万分之一,通过示波器也能捕捉到5-7ms的延时的情况,请问大侠们这是什么情况啊?
...全文
1185 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
hello_world000 2014-01-05
  • 打赏
  • 举报
回复


struct partial_pkt
{
    uint8_t tag;//TAG_END
    uint8_t partial_order;
};

const pkt_header_t *pack(const char *buf, unsigned long length)
{
    const pkt_header_t *head = (const pkt_header_t *)buf;
    struct link_package {
        int partial_order;
        char link_buffer[512];
        int total_pkg_len;
        int offset;
    };
    static struct link_package linker = {-1};//init partial_order to -1 to aviod lost first pkt

    //try to judge which pkt it is
    if ((TAG_BEGIN <= head->tag && head->tag < TAG_END) && (head->length < MAX_PKT_LENGTH)) {
        linker.total_pkg_len = head->length + OFFSET_OF_END_MEM(pkt_header_t, length);
        if (linker.total_pkg_len > (int)length) {//need link other partial packages
            linker.partial_order = 0;//init partial_order
            if (length <= sizeof(linker.link_buffer)) {
                memcpy(linker.link_buffer, buf, length);//save first partial package
                linker.offset = length;
            } else {
                goto error;
            }
            goto receive_next;//receive next partial package
        } else {
            return head;//full pkt
        }
    } else if (TAG_END == head->tag) {//check if partial_order effective
        struct partial_pkt *partial = (struct partial_pkt *)buf;
        if (partial->partial_order == (linker.partial_order + 1)) {
            if (linker.offset + length <= sizeof(linker.link_buffer)) {
                ++linker.partial_order;
                memcpy(linker.link_buffer + linker.offset, buf + sizeof(struct partial_pkt), length - sizeof(struct partial_pkt));
                linker.offset += length;
                if (linker.offset >= linker.total_pkg_len) {//link finished 
                    return (pkt_header_t *)linker.link_buffer;
                } else {
                    goto receive_next;//receive next partial package
                }
            }
        }
    }

error://clear linker info when error
    linker.partial_order = -1;
    linker.total_pkg_len = 0;
    linker.offset = 0;
receive_next:
    return NULL;
}

#define MAX_SEND_LEN (32)//size rely on mailbox
int unpack(const void *buf, unsigned long length)
{
    int ret = 0;

    if (length <= MAX_SEND_LEN) {
        //return inputhub_mcu_send((const char *)buf, length);
    } else {
        int partial_order = 0;
        char send_partial_buf[MAX_SEND_LEN];
        int send_cnt = 0;

        //send head
        //ret = inputhub_mcu_send(send_begin, MAX_SEND_LEN);

        ((struct partial_pkt *)send_partial_buf)->tag = TAG_END;
        for (send_cnt = MAX_SEND_LEN; send_cnt < (int)length; send_cnt += (MAX_SEND_LEN - sizeof(struct partial_pkt))) {
            ++((struct partial_pkt *)send_partial_buf)->partial_order;
            memcpy(send_partial_buf + sizeof(struct partial_pkt), (const char *)buf + send_cnt, MAX_SEND_LEN - sizeof(struct partial_pkt));
            //ret = inputhub_mcu_send(send_partial_buf, MAX_SEND_LEN);
        }
    }

    return ret;
}
hello_world000 2014-01-04
  • 打赏
  • 举报
回复

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//#include<stdint.h>
#include"protocol.h"

#define LINK_PACKAGE

#define OFFSET(struct_t, member) ((int)&(((struct_t *)0)->member))
#define OFFSET_OF_END_MEM(struct_t, member) (OFFSET(struct_t, member) + sizeof((((struct_t *)0)->member)))
#define OFFSET_INTERVAL(struct_t, member1, member2) (OFFSET_OF_END_MEM(struct_t, member2) - OFFSET_OF_END_MEM(struct_t, member1))


#ifdef LINK_PACKAGE

int generate_crc(const void *buf, unsigned long length)
{
    return 0;
}

struct partial_pkt
{
    uint8_t tag;//TAG_END
    uint8_t partial_order;
};
/*
typedef struct
{
    uint8_t tag;
    uint8_t cmd;
    uint8_t resp;//value CMD_RESP means need resp, CMD_NO_RESP means need not resp
    uint8_t reserve;
    uint16_t tranid;
    uint16_t length;
}pkt_header_t;

typedef struct
{
    uint8_t tag;
    uint8_t cmd;
    uint8_t resp;
    uint8_t reserve;
    uint16_t tranid;
    uint16_t length;
    uint32_t errno;
}pkt_header_resp_t;
*/
const pkt_header_t *pack(const char *buf, unsigned long length)
{
    const pkt_header_t *head = (const pkt_header_t *)buf;
    struct link_package {
        bool full_pkg;
        char link_buffer[512];
        int offset;
        int total_pkg_len;
        int partial_order;
    };
    static struct link_package linker = {true};

begin:
    if (linker.full_pkg) {
        head = (const pkt_header_t *)buf;
        linker.total_pkg_len = head->length + OFFSET_OF_END_MEM(pkt_header_t, length);
        if (linker.total_pkg_len > (int)length) {//need link other partial packages
            linker.full_pkg = false;
            linker.partial_order = 0;
            if (length <= sizeof(linker.link_buffer)) {
                memcpy(linker.link_buffer, buf, length);//save first partial package
            } else {
                //printf("data length error from mcu in %s!\n", __func__);
            }
            linker.offset = length;
            return NULL;//receive next partial package.
        }
    } else {
        if (linker.offset + length <= sizeof(linker.link_buffer)) {
            struct partial_pkt *partial = (struct partial_pkt *)buf;
            if (TAG_END == partial->tag) {//partial pkt
                if (partial->partial_order != (linker.partial_order + 1)) {
                    ++linker.partial_order;
                    memcpy(linker.link_buffer + linker.offset, buf + sizeof(struct partial_pkt), length - sizeof(struct partial_pkt));
                } else {//lost one partial pkt, so we will drop all partial pkt belongs
                    ;
                }
            } else if (TAG_BEGIN <= head->tag && head->tag < TAG_END && head->length < MAX_PKT_LENGTH) {//may be next full pkt
                linker.full_pkg = true;
                linker.offset = 0;
                linker.partial_order = 0;
                goto begin;
            } else {//error
                ;
            }
            
        } else {
            //printf("data length error from mcu in %s!\n", __func__);
        }
        linker.offset += length;
        if (linker.offset >= linker.total_pkg_len) {//link finished
            head = (pkt_header_t *)linker.link_buffer;
            linker.full_pkg = true;
        } else {
            return NULL;//receive next partial package.
        }
    }

    return head;
}

#define MAX_SEND_LEN (32)//size rely on mailbox
int unpack(const void *buf, unsigned long length, int *crc)
{
    int ret = 0;
    const char *send_begin = (const char *)buf;
    const char *send_end = send_begin + length;

    *crc = generate_crc(buf, length);
    do {
        //ret = inputhub_mcu_send(send_begin, MAX_SEND_LEN);
        if (ret) {
            //printf("send data failed in %s\n", __func__);
            break;
        }
        send_begin += MAX_SEND_LEN;
    } while (send_begin < send_end);

    return ret;
}
#endif

int main()
{
    
    system("pause");
    return 0;
}
hello_world000 2014-01-04
  • 打赏
  • 举报
回复

int write_customize_cmd(const struct write_info *wr, struct read_info *rd)
{
    char buf[MAX_PKT_LENGTH];
    int ret = 0;

    if (NULL == wr) {
        hwlog_err("NULL pointer in %s\n", __func__);
        return -EINVAL;
    }
    //[TAG_BEGIN, TAG_END)
    if (wr->tag < TAG_BEGIN || wr->tag >= TAG_END) {
        hwlog_err("tag = %d error in %s\n", wr->tag, __func__);
        return -EINVAL;
    }
    if (wr->wr_len + sizeof(pkt_header_t) > MAX_PKT_LENGTH) {
        hwlog_err("-----------> wr_len = %d is too large in %s\n", wr->wr_len, __func__);
        return -EINVAL;
    }

    //转换成MCU需要的协议格式
    ((pkt_header_t *)buf)->tag = wr->tag;
    ((pkt_header_t *)buf)->cmd = wr->cmd;
    ((pkt_header_t *)buf)->resp = ((rd != NULL) ? (RESP) : (NO_RESP));
    ((pkt_header_t *)buf)->length = wr->wr_len;
    if (wr->wr_buf != NULL) {
        memcpy(buf + sizeof(pkt_header_t), wr->wr_buf, wr->wr_len);
    }
    if (NULL == rd) {//tag cmd need not resp
        return inputhub_mcu_write_cmd(buf, sizeof(pkt_header_t) + wr->wr_len);
    } else {//tag cmd need resp
        unsigned long flags = 0;
        mutex_lock(&type_record.lock_mutex);
        spin_lock_irqsave(&type_record.lock_spin, flags);
        type_record.pkt_info = ((pkt_header_t *)buf);
        type_record.rd = rd;
        spin_unlock_irqrestore(&type_record.lock_spin, flags);

        //send data to mcu
        if ((ret = inputhub_mcu_write_cmd(buf, sizeof(pkt_header_t) + wr->wr_len)) != 0) {
            hwlog_err("send cmd to mcu failed in %s\n", __func__);
            goto clear_info;
        }

        //wait for resp or timeout
        hwlog_info("down ------------------------------------------------------> in %s\n",  __func__);
        if ((ret = down_timeout(&type_record.sem, HZ * 2)) != 0) {
            hwlog_err("------->timeout in %s\n", __func__);//timeout
        }

clear_info:
        //clear infor
        spin_lock_irqsave(&type_record.lock_spin, flags);
        type_record.pkt_info = NULL;
        type_record.rd = NULL;
        spin_unlock_irqrestore(&type_record.lock_spin, flags);
        mutex_unlock(&type_record.lock_mutex);
    }

    return ret;
}

static int report_resp_data(const pkt_header_resp_t *head)
{
    int ret = 0;
    unsigned long flags = 0;

    spin_lock_irqsave(&type_record.lock_spin, flags);
    if (type_record.rd != NULL && type_record.pkt_info != NULL//check record info
        && (cmd_match(type_record.pkt_info->cmd, head->cmd))
        && (type_record.pkt_info->tranid == head->tranid)) {//rcv resp from mcu
        if (head->length <= (MAX_PKT_LENGTH + sizeof(head->errno))) {//data length ok
            type_record.rd->errno = head->errno;//fill errno to app
            type_record.rd->data_length = (head->length - sizeof(head->errno));//fill data_length to app, data_length means data lenght below
            memcpy(type_record.rd->data, (char *)head + sizeof(pkt_header_resp_t), type_record.rd->data_length);//fill resp data to app
        } else {//resp data too large
            type_record.rd->errno = -EINVAL;
            type_record.rd->data_length = 0;
            hwlog_err("data too large from mcu in %s\n", __func__);
        }
        up(&type_record.sem);
        hwlog_info("up ------------------------------------------------------> in %s\n",  __func__);
    }
    spin_unlock_irqrestore(&type_record.lock_spin, flags);

    return ret;
}
zhengmeifu 2012-11-21
  • 打赏
  • 举报
回复
还没明白你描述的问题。一般linux的时间片是10ms左右,不可能实时的。MCU那边你的程序是否有问题呢?
hello_world000 2012-11-19
  • 打赏
  • 举报
回复
引用 6 楼 zhenghn2010 的回复:
在LINUX这边的中断服务程序再通过另外一个gpio去中断MCU? 这个肯定要相对耗时吧。怎么实行的
做环回测试时,只是在LINUX这边的中断上半部给MCU一个下降沿,MCU是实时的操作系统,响应非常快。
zhenghn2010 2012-11-19
  • 打赏
  • 举报
回复
在LINUX这边的中断服务程序再通过另外一个gpio去中断MCU? 这个肯定要相对耗时吧。怎么实行的
bjtea 2012-11-18
  • 打赏
  • 举报
回复
简单的判断,就是偶遇到更高级的较长时间的中断服务,导致没能及时响应你希望的GPIO中断; 具体的,就需要分析你现有的程序和系统程序的功能了。
hello_world000 2012-11-18
  • 打赏
  • 举报
回复
ssize_t inputhub_route_read(unsigned short port, char __user *buf, size_t count) { struct inputhub_route_table *route_item; int read_len = 0; char my_test[100];//test if (inputhub_route_item(port, &route_item) != 0) { printk(KERN_ERR"inputhub_route_item failed in inputhub_route_read\n"); return 0; } if (0 == route_item->cnt) { //block here printk(KERN_INFO "blocked int inputhub_route_read\n"); data_ready = 0; wait_event_freezable(read_wait, data_ready); printk(KERN_INFO "unblocked from inputhub_route_read\n"); } if (count > route_item->cnt) { count = route_item->cnt; } while (count > 0) { int full_pkg_length; int tail_half_len; if (route_item->rd + LENGHT_SIZE > route_item->end) { int package_length; tail_half_len = route_item->end - route_item->rd; memcpy(&package_length, route_item->rd, tail_half_len); memcpy((char *)&package_length + tail_half_len, route_item->start, LENGHT_SIZE - tail_half_len); full_pkg_length = package_length + LENGHT_SIZE; } else { full_pkg_length = *((int *)route_item->rd) + LENGHT_SIZE; } printk(KERN_INFO "full_pkg_length = %d\n", full_pkg_length); if (full_pkg_length > count) { printk(KERN_ERR "!!!!!!!!!!!!!!full_pkg_length > count!!!!!!!!!!!!!!!!!\n"); break; } if (route_item->end - route_item->rd > full_pkg_length) { if (0 == copy_to_user(buf, route_item->rd, full_pkg_length)) { route_item->rd += full_pkg_length; } else { printk(KERN_ERR "copy to user failed\n"); return -1; } } else { tail_half_len = route_item->end - route_item->rd; if ((0 == copy_to_user(buf, route_item->rd, tail_half_len)) && (0 == copy_to_user(buf + tail_half_len, route_item->start, (full_pkg_length - tail_half_len)))) { route_item->rd = route_item->start + (full_pkg_length - tail_half_len); printk(KERN_ERR "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); } else { printk(KERN_ERR "copy to user failed\n"); return -1; } } copy_from_user(&my_test, buf, full_pkg_length); printk(KERN_INFO "pkg_length = %d\n", *(int *)my_test); printk(KERN_INFO "time = %lld\n", *(int64_t *)(my_test + 4)); printk(KERN_INFO "type = %d\n", *(unsigned short *)(my_test + 12)); printk(KERN_INFO "length = %d\n", *(unsigned short *)(my_test + 14)); printk(KERN_INFO "x = %d\n", *(int *)(my_test + 16)); printk(KERN_INFO "y = %d\n", *(int *)(my_test + 20)); printk(KERN_INFO "z = %d\n", *(int *)(my_test + 24)); buf += full_pkg_length; count -= full_pkg_length; read_len += full_pkg_length; printk(KERN_INFO "read a full package with sizeof %d, count = %d\n", full_pkg_length, count); } mutex_lock(&data_mutex); route_item->cnt -= read_len; mutex_unlock(&data_mutex); printk(KERN_INFO "total read packages with sizeof %d\n", read_len); return read_len; }
Binzo 2012-11-17
  • 打赏
  • 举报
回复
linux不是实时的。
hello_world000 2012-11-17
  • 打赏
  • 举报
回复
//1.__user *buf 需要使用copy_to_user //2.在write时在写完time+tl时应该buf += 4; //3.写时完整的代码都要加锁 //4. //memcpy((char *)&head + tail_half_len, route_item->rd + tail_half_len, sizeof(pkg_head) - tail_half_len); //--> //memcpy((char *)&head + tail_half_len, route_item->start, sizeof(pkg_head) - tail_half_len); ssize_t inputhub_route_read(unsigned short port, char __user *buf, size_t count) { struct inputhub_route_table *route_item; int read_len = 0; if (inputhub_route_item(port, &route_item) != 0) { printk(KERN_ERR"inputhub_route_item failed in inputhub_route_read\n"); return 0; } if (0 == route_item->cnt) {//无数据时阻塞 //block here printk(KERN_INFO "blocked at inputhub_route_read\n"); data_ready = 0; wait_event_freezable(read_wait, data_ready); printk(KERN_INFO "unblocked from inputhub_route_read\n"); } if (count > route_item->cnt) { count = route_item->cnt; } while (count > 0) { int full_pkg_length; int tail_half_len; if (route_item->rd + sizeof(pkg_head) > route_item->end) { pkg_head head; tail_half_len = route_item->end - route_item->rd; memcpy(&head, route_item->rd, tail_half_len);//将后半部数据拷贝到 memcpy((char *)&head + tail_half_len, route_item->start, sizeof(pkg_head) - tail_half_len); full_pkg_length = head.pkg_len + sizeof(pkg_head); } else { full_pkg_length = ((pkg_head *)route_item->rd)->pkg_len + sizeof(pkg_head); } printk(KERN_INFO "full_pkg_length = %d\n", full_pkg_length); if (full_pkg_length > count) {//用户空间的剩余空间不足以完整的读取这个包 break; } if (route_item->end - route_item->rd > full_pkg_length) { copy_to_user(buf, route_item->rd, full_pkg_length); route_item->rd += full_pkg_length; } else { tail_half_len = route_item->end - route_item->rd; copy_to_user(buf, route_item->rd, tail_half_len); copy_to_user(buf + tail_half_len, route_item->start, (full_pkg_length - tail_half_len)); route_item->rd = route_item->start + (full_pkg_length - tail_half_len); } buf += full_pkg_length;//更新 count -= full_pkg_length; read_len += full_pkg_length; printk(KERN_INFO "read a full package with sizeof %d\n", full_pkg_length); } mutex_lock(&data_mutex); route_item->cnt -= read_len; mutex_unlock(&data_mutex); return read_len; } static void write_to_fifo(struct inputhub_route_table *route_item, char *buf, int count) { int tmp; for (tmp = count; tmp > 0; --tmp) { *route_item->wr++ = *buf++; if (route_item->wr == route_item->end) { route_item->wr = route_item->start; } } mutex_lock(&data_mutex); route_item->cnt += count; mutex_unlock(&data_mutex); } ssize_t inputhub_route_write(unsigned short port, char *buf, size_t count, int is_test) { struct inputhub_route_table *route_item; int64_t time; count += sizeof(pkg_head); if (inputhub_route_item(port, &route_item) != 0) { printk(KERN_ERR"inputhub_route_item failed in inputhub_route_write\n"); return 0; } if ((route_item->buf_size - route_item->cnt) < count) { printk(KERN_ERR"remain_size = %d, need_size = %d\n", (route_item->buf_size - route_item->cnt), count); count = 0; } else { time = getTimestamp(); write_to_fifo(route_item, (char *)&time, sizeof(time));//write time write_to_fifo(route_item, buf, count + OFFSET(???));//write tlv, ???是v在TLV中的偏移量 } data_ready = 1; wake_up_interruptible(&read_wait); return count; }
hello_world000 2012-09-25
  • 打赏
  • 举报
回复
请大侠们指教,多谢!

21,597

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 驱动开发/核心开发
社区管理员
  • 驱动开发/核心开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧