public inbox for linux-media@vger.kernel.org
 help / color / mirror / Atom feed
From: Agustin <gatoguan-os@yahoo.com>
To: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Cc: video4linux-list@redhat.com
Subject: Success with mx3_camera, panic at mx3_cam_dma_done
Date: Fri, 19 Dec 2008 09:34:04 -0800 (PST)	[thread overview]
Message-ID: <879100.96900.qm@web32107.mail.mud.yahoo.com> (raw)
In-Reply-To: <Pine.LNX.4.64.0812191319090.4536@axis700.grange>

[-- Attachment #1: Type: text/plain, Size: 2717 bytes --]

Hi again,

On Fri, 19/12/08, Guennadi Liakhovetski wrote:
> On Fri, 19 Dec 2008, Agustin wrote:
> > I can't tell if I am having a hardware issue...
> > Do you have any modification or fix in your
> > Phytec i.MX31 dev-kit?
> 
> Nothing ground-breaking. The snapshot I uploaded
> for you in November worked for me and it should work
> for you too. By "select timeout" I suspect you're not
> getting any interrupts at all, right?

Indeed.

> That's your first task - to get your setup generate
> at least one interrupt, then it'll be easier:-) You
> say "haven't been able to retrieve a VGA sized dummy
> image" - does it mean you can retrieve other (smaller)
> sizes?

Nope!

> If not, I would check signalling. Check the master
> clock, whether the pixel clock is generated. You're
> using master mode, right? If both clocks are ok, check
> syncs. You said before your logic analyser showed a
> plausible picture...

Indeed I could see those signals quite fine, all the way to devkit connector. Later on it is a pain to attach probes...

I tried swapping the devkit for an older one, and voila! I got my dearest first image right away.

It might be that the connector was not pushed to the end, or it might be some issue with the new devkit Phytec sent me last month, it is quite different, has some manual rework, and it is missing the white ink layer so I can't tell jumpers apart.

> Are you doing 8 or 16 bits? Check output of /proc/interrupts
> _while_ a task is waiting in select, you should be getting
> irq #167 - one per frame.

Yeah but fortunately I didn't have to go that far debugging.

However, I still managed to make mx3_camera driver crash. It is probably a race condition around end-of-capture event, because I can retrieve an arbitrary number of frames without issues, then when application exits the dma gets triggered again and mx3_cam_dma_done() fails, probably trying to access an already freed buffer. If I only use one buffer, there are no issues either, I think it is because mx3_cam_dma_done() anticipates the lack of buffers each time. However, I might be loosing frames in this case.

I attach a log of the crash, along with the still capture test application I am using (a simplification of the 'official' V4L2 example). 'Sixcam' is the name of my project, BTW.

I will try to provide a fix as soon as I get off this Christmas work crunch I am having... But now that I got the data through to userspace (and the prototype boards apparently working) my next weeks of work promise some happy results.

Thanks & regards,
--Agustín.

--
Agustin Ferrin Pozuelo
Embedded Systems Consultant
http://embedded.ferrin.org/
Tel. +34 610502587

[-- Attachment #2: mx3_cam_dma_done-panic.log --]
[-- Type: application/octet-stream, Size: 4762 bytes --]

sixcam_module_init():406
sixcam: TRIGGER High.
camera 0-0: MX3 Camera driver attached to camera 0
sixcam_video_probe():284
camera 0-0: MX3 Camera driver detached from camera 0
camera 0-0: MX3 Camera driver attached to camera 0
sixcam_set_fmt():244
rect->width=640 rect->height=480.
sixcam: camera #0 reg 5h was 0, set to 25.
sixcam: camera #0 reg 6h was 0, set to 9.
sixcam: camera #0 reg 2h was 0, set to 0.
sixcam: camera #0 reg 1h was 0, set to 0.
sixcam: camera #0 reg 4h was 0, set to 639.
sixcam: camera #0 reg 3h was 0, set to 479.
sixcam: camera #0 reg 9h was 0, set to 489.
sixcam_query_bus_param():229
sixcam_try_fmt():266
icd->width=640 icd->height=480.
fmt.pix.width=640 fmt.pix.height=480.
sixcam_set_fmt():244
rect->width=640 rect->height=480.
sixcam: camera #0 reg 5h was 25, set to 25.
sixcam: camera #0 reg 6h was 9, set to 9.
sixcam: camera #0 reg 2h was 0, set to 0.
sixcam: camera #0 reg 1h was 0, set to 0.
sixcam: camera #0 reg 4h was 639, set to 639.
sixcam: camera #0 reg 3h was 479, set to 479.
sixcam: camera #0 reg 9h was 489, set to 489.
sixcam_query_bus_param():229
sixcam_set_bus_param():218
sixcam: sixcam_bus_params <= 0x2215.
sixcam_start_capture():196
sixcam: TRIGGER High.
sixcam: TRIGGER Low.
sixcam_stop_capture():208
Unable to handle kernel NULL pointer dereference at virtual address 0000002c
pgd = c0004000
[0000002c] *pgd=00000000
Internal error: Oops: 17 [#1] PREEMPT
Modules linked in: sixcam mx3_camera soc_camera videobuf_dma_contig videobuf_core
CPU: 0    Not tainted  (2.6.28-rc3-next-20081105gato-03042-g25a4055-dirty #40)
PC is at mx3_cam_dma_done+0x28/0x108 [mx3_camera]
LR is at idmac_interrupt+0x174/0x350
pc : [<bf0134e8>]    lr : [<c0192630>]    psr: a0000113
sp : c0329e48  ip : 0000002c  fp : c0329e64
r10: 00000007  r9 : c0363860  r8 : c88b43c0
r7 : c0328000  r6 : c88a6000  r5 : c88a6030  r4 : 00000000
r3 : 00200200  r2 : 00000004  r1 : 00000080  r0 : c88b43c0
Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
Control: 00c5387f  Table: 861b4000  DAC: 00000017
Process swapper (pid: 0, stack limit = 0xc0328260)
Stack: (0xc0329e48 to 0xc032a000)
9e40:                   c0329e64 c0363700 00000001 c61d696c c0329eac c0329e68 
9e60: c0192630 bf0134cc 14dcb184 00000000 00000003 c0354900 c0329e94 c0363870 
9e80: c00903b8 c6243de0 00000000 00000000 000000a7 c0342780 c0328000 8001e0b8 
9ea0: c0329ecc c0329eb0 c0060a60 c01924c8 c0328000 c033275c c6243de0 000000a7 
9ec0: c0329eec c0329ed0 c0062bb0 c0060a30 00000000 c0342744 c0330034 c0362b90 
9ee0: c0329f14 c0329ef0 c019075c c0062b14 c0329f14 0000002a c035f750 00000000 
9f00: 00000002 00000001 c0329f34 c0329f18 c0022060 c01906cc c0329f44 0000001f 
9f20: fc400000 002a0000 c0329f8c c0329f38 c0022a6c c002200c c034d418 00000000 
9f40: 00000000 c0328000 c0023e7c c0328000 c034cc68 c032bcd4 8001e0ec 4107b364 
9f60: 8001e0b8 c0329f8c c0329f90 c0329f80 c0023eb8 c0023ebc 60000013 ffffffff 
9f80: c0329fac c0329f90 c0023da4 c0023e88 c032bcd4 c0328000 c034c7f4 c034c7e4 
9fa0: c0329fc4 c0329fb0 c0287a20 c0023d7c c034c7f4 c0354c48 c0329ff4 c0329fc8 
9fc0: c0008a08 c02879b8 c00083ac 00000000 00000000 c001fd58 00000000 00c5387d 
9fe0: c034ccd4 c002015c 00000000 c0329ff8 80008034 c0008820 00000000 00000000 
Backtrace: 
[<bf0134c0>] (mx3_cam_dma_done+0x0/0x108 [mx3_camera]) from [<c0192630>] (idmac_interrupt+0x174/0x350)
 r6:c61d696c r5:00000001 r4:c0363700
[<c01924bc>] (idmac_interrupt+0x0/0x350) from [<c0060a60>] (handle_IRQ_event+0x3c/0x74)
[<c0060a24>] (handle_IRQ_event+0x0/0x74) from [<c0062bb0>] (handle_level_irq+0xa8/0x150)
 r7:000000a7 r6:c6243de0 r5:c033275c r4:c0328000
[<c0062b08>] (handle_level_irq+0x0/0x150) from [<c019075c>] (ipu_irq_fn+0x9c/0xd0)
 r7:c0362b90 r6:c0330034 r5:c0342744 r4:00000000
[<c01906c0>] (ipu_irq_fn+0x0/0xd0) from [<c0022060>] (asm_do_IRQ+0x60/0x8c)
 r8:00000001 r7:00000002 r6:00000000 r5:c035f750 r4:0000002a
[<c0022000>] (asm_do_IRQ+0x0/0x8c) from [<c0022a6c>] (__irq_svc+0x4c/0x98)
Exception stack(0xc0329f38 to 0xc0329f80)
9f20:                                                       c034d418 00000000 
9f40: 00000000 c0328000 c0023e7c c0328000 c034cc68 c032bcd4 8001e0ec 4107b364 
9f60: 8001e0b8 c0329f8c c0329f90 c0329f80 c0023eb8 c0023ebc 60000013 ffffffff 
 r6:002a0000 r5:fc400000 r4:0000001f
[<c0023e7c>] (default_idle+0x0/0x48) from [<c0023da4>] (cpu_idle+0x34/0x68)
[<c0023d70>] (cpu_idle+0x0/0x68) from [<c0287a20>] (rest_init+0x74/0x88)
 r6:c034c7e4 r5:c034c7f4 r4:c0328000
[<c02879ac>] (rest_init+0x0/0x88) from [<c0008a08>] (start_kernel+0x1f4/0x270)
 r4:c0354c48
[<c0008814>] (start_kernel+0x0/0x270) from [<80008034>] (0x80008034)
 r6:c002015c r5:c034ccd4 r4:00c5387d
Code: e59f30e0 e2456030 e596402c e284c02c (e594102c) 
Kernel panic - not syncing: Fatal exception in interrupt

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: still.c --]
[-- Type: text/x-csrc; name="still.c", Size: 8051 bytes --]

/*
 *  Based on V4L2 video capture example
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include <fcntl.h>              /* low-level i/o */
#include <unistd.h>
#include <errno.h>
#include <malloc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include <asm/types.h>          /* for videodev2.h */
#include <linux/videodev2.h>

#include "sixcam.h"

#define zerofill(x) memset(&(x),0,sizeof(x))

struct buffer {
    void * start;
    size_t length;
};

static char * dev_name = "/dev/v4l/video0";
static int fd = -1;
struct buffer * buffers = NULL;
static unsigned int n_buffers = 0;

static void errno_exit(const char * s)
{
    fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));
    exit(EXIT_FAILURE);
}

static int xioctl(int fd, int request, void *arg)
{
    int r;

    do r = ioctl(fd, request, arg);
    while(-1 == r && EINTR == errno);

    return r;
}

static void process_image(const void *p)
{
    printf("Got one image.\n");
}

static int read_frame(void)
{
    struct v4l2_buffer buf;

    zerofill(buf);
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;

    if( -1 == xioctl(fd, VIDIOC_DQBUF, &buf))
    {
        switch( errno) {
        case EAGAIN:
            fprintf(stderr, "VIDIOC_DQBUF -EAGAIN.\n");
            return 0;

        case EIO:
            /* Could ignore EIO, see spec. */

            /* fall through */

        default:
            errno_exit("VIDIOC_DQBUF");
        }
    }

    assert(buf.index < n_buffers);

    process_image(buffers[buf.index].start);

    if(-1 == xioctl(fd, VIDIOC_QBUF, &buf))
        errno_exit("VIDIOC_QBUF");

    return 1;
}

static void open_device(void)
{
    struct stat st; 

    if(-1 == stat(dev_name, &st)) {
        fprintf(stderr, "Cannot identify '%s': %d, %s\n",
             dev_name, errno, strerror(errno));
        exit(EXIT_FAILURE);
    }

    if(!S_ISCHR(st.st_mode)) {
        fprintf(stderr, "%s is no device\n", dev_name);
        exit(EXIT_FAILURE);
    }

    fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);

    if(-1 == fd) {
        fprintf(stderr, "Cannot open '%s': %d, %s\n",
             dev_name, errno, strerror(errno));
        exit(EXIT_FAILURE);
    }
}

static void init_mmap(void)
{
    struct v4l2_requestbuffers req;
    int i;

    zerofill(req);

    req.count               = 2;
    req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory              = V4L2_MEMORY_MMAP;

    if(-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
        if(EINVAL == errno) {
            fprintf(stderr, "%s does not support "
                 "memory mapping\n", dev_name);
            exit(EXIT_FAILURE);
        } else {
            errno_exit("VIDIOC_REQBUFS");
        }
    }

    printf("Got %i buffers\n", req.count);
    if(req.count < 1) {
        fprintf(stderr, "Insufficient buffer memory on %s\n", dev_name);
        exit(EXIT_FAILURE);
    }

    buffers = calloc(req.count, sizeof(*buffers));

    if(!buffers) {
        fprintf(stderr, "Out of memory\n");
        exit(EXIT_FAILURE);
    }

    for(i = 0; i < req.count; ++i) {
        struct v4l2_buffer buf;

        zerofill(buf);

        buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory      = V4L2_MEMORY_MMAP;
        buf.index       = i;

        if(-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
            errno_exit("VIDIOC_QUERYBUF");

        printf("m-mapping buffer #%i at %p, size 0x%X...\n", i, buf.m.offset
                , buf.length);
        buffers[i].length = buf.length;
        buffers[i].start =
            mmap(NULL /* start anywhere */,
                  buf.length,
                  PROT_READ | PROT_WRITE        /* recommended */,
                  MAP_SHARED                    /* recommended */,
                  fd, buf.m.offset);

        if(MAP_FAILED == buffers[i].start)
            errno_exit("mmap");
    }
    n_buffers = i;
}

static void init_device(void)
{
    struct v4l2_capability cap;
    struct v4l2_cropcap cropcap;
    struct v4l2_crop crop;
    struct v4l2_format fmt;
    unsigned int min;

    if(-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) {
        if(EINVAL == errno) {
            fprintf(stderr, "%s is no V4L2 device\n",
                 dev_name);
            exit(EXIT_FAILURE);
        } else {
            errno_exit("VIDIOC_QUERYCAP");
        }
    }

    if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
        fprintf(stderr, "%s is no video capture device\n",
             dev_name);
        exit(EXIT_FAILURE);
    }

    if(!(cap.capabilities & V4L2_CAP_STREAMING)) {
        fprintf(stderr, "%s does not support streaming i/o\n",
             dev_name);
        exit(EXIT_FAILURE);
    }

    /* Select video input, video standard and tune here. */

    zerofill(cropcap);

    cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    if(0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
        crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        crop.c = cropcap.defrect; /* reset to default */

        if(-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
            switch(errno) {
            case EINVAL:
                /* Cropping not supported. */
                break;
            default:
                /* Errors ignored. */
                break;
            }
        }
    } else {        
        /* Errors ignored. */
    }


    zerofill(fmt);

    fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width       = 640; 
    fmt.fmt.pix.height      = 480;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
    fmt.fmt.pix.field       = V4L2_FIELD_ANY;

    if(-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
        errno_exit("VIDIOC_S_FMT");

    /* Note VIDIOC_S_FMT may change width and height. */
    printf("VIDIOC_S_FMT returned width %i and height %i.\n"
        , fmt.fmt.pix.width, fmt.fmt.pix.height);

    init_mmap();
}

static void start_capturing(void)
{
    unsigned int i;
    enum v4l2_buf_type type;

    for(i = 0; i < n_buffers; i++)
    {
        struct v4l2_buffer buf;

        zerofill(buf);

        buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory      = V4L2_MEMORY_MMAP;
        buf.index       = i;

        /* Enqueue buffer */
        if(-1 == xioctl(fd, VIDIOC_QBUF, &buf))
            errno_exit("VIDIOC_QBUF");
    }
    
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    if(-1 == xioctl(fd, VIDIOC_STREAMON, &type))
        errno_exit("VIDIOC_STREAMON");
}

static void mainloop(void)
{
    unsigned int count;

    count = 7;

    while(count-- > 0) {
        for(;;) {
            fd_set fds;
            struct timeval tv;
            int r;

            FD_ZERO(&fds);
            FD_SET(fd, &fds);

            /* Timeout. */
            tv.tv_sec = 10;
            tv.tv_usec = 0;

            r = select(fd + 1, &fds, NULL, NULL, &tv);

            if(-1 == r) {
                if(EINTR == errno)
                    continue;

                errno_exit("select");
            }

            if(0 == r) {
                fprintf(stderr, "Select timeout.\n");
                exit(EXIT_FAILURE);
            }

            if(read_frame())
                break;
    
            /* EAGAIN - continue select loop. */
        }
    }
}

static void stop_capturing(void)
{
    enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    if(-1 == xioctl(fd, VIDIOC_STREAMOFF, &type))
        errno_exit("VIDIOC_STREAMOFF");
}

static void uninit_device(void)
{
    unsigned int i;

    for(i = 0; i < n_buffers; ++i)
        if(-1 == munmap(buffers[i].start, buffers[i].length))
            errno_exit("munmap");

    free(buffers);
}

static void close_device(void)
{
    if(-1 == close(fd))
        errno_exit("close");

    fd = -1;
}

int main(int argc, char ** argv)
{
    if( argc > 1 ) dev_name = argv[1];
    open_device();
    init_device();
    start_capturing();
    mainloop();
    stop_capturing();
    uninit_device();
    close_device();

    return 0;
}

[-- Attachment #4: Type: text/plain, Size: 164 bytes --]

--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

  reply	other threads:[~2008-12-19 17:35 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20081218170015.10DD88E03CC@hormel.redhat.com>
2008-12-19 11:58 ` soc-camera: current stack Agustin
2008-12-19 12:29   ` Guennadi Liakhovetski
2008-12-19 17:34     ` Agustin [this message]
2008-12-22  9:32   ` Robert Schwebel
2008-12-22 10:30     ` Guennadi Liakhovetski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=879100.96900.qm@web32107.mail.mud.yahoo.com \
    --to=gatoguan-os@yahoo.com \
    --cc=g.liakhovetski@gmx.de \
    --cc=video4linux-list@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox