2011年5月13日 星期五

Beagleboard xM - Camera board LI-5M03

玩了一陣子LI-BCM3M1 camera board發現不管什麼解析度都只能達到5~8fps.數據相當的難看,主要原因是driver限制住了.
到chip vendor Aptina網站找mt9t112 datasheet 竟然還要簽 NDA,發信去也不鳥我...Shit.

因此轉而試試五百萬畫素的LI-5M03, Aptina 有提供datasheet
http://www.aptina.com/products/image_sensors/mt9p031i12stc/
此外更提供給BeagleBoard XM driver source code放在github,我clone了一份.
https://github.com/gigijoe/BeagleBoard-xM

mt9p031 driver我有做一些修改
其中值得一提的是Camera輸出的影像非常暗,所以我把analog gain調高

@@ -538,12 +538,19 @@
     mdelay(200);
 
     ret |= mt9p031_set_params(priv->client, pix->width, pix->height);
-   
+#if 0   
     ret |= mt9p031_reg_write(client, REG_MT9P031_GREEN_1_GAIN, 0x0051);      //Green1_gain_reg
     ret |= mt9p031_reg_write(client, REG_MT9P031_BLUE_GAIN, 0x0051);      //Blue_gain_reg
     ret |= mt9p031_reg_write(client, REG_MT9P031_RED_GAIN, 0x0051);      //Red_gain_reg
     ret |= mt9p031_reg_write(client, REG_MT9P031_GREEN_2_GAIN, 0x0051);      //Green2_gain_reg
     ret |= mt9p031_reg_write(client, REG_MT9P031_GLOBAL_GAIN, 0x0008);        //Analog Gain
+#endif
+  ret |= mt9p031_reg_write(client, REG_MT9P031_GREEN_1_GAIN, 0x0079);   //Green1_gain_reg
+  ret |= mt9p031_reg_write(client, REG_MT9P031_BLUE_GAIN, 0x0079);    //Blue_gain_reg
+  ret |= mt9p031_reg_write(client, REG_MT9P031_RED_GAIN, 0x0079);   //Red_gain_reg
+  ret |= mt9p031_reg_write(client, REG_MT9P031_GREEN_2_GAIN, 0x0079);   //Green2_gain_reg
+  ret |= mt9p031_reg_write(client, REG_MT9P031_GLOBAL_GAIN, 0x0026);    //Analog Gain



這份driver source code 要自行擺放檔案到正確的位置,以及部份檔案需要手動剪貼.
基本上不困難,我就不在此詳述.更動檔案如下

arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3beagle-camera.c
drivers/media/video/mt9p031.c
drivers/media/video/mt9p031.h
drivers/media/video/Makefile
drivers/media/video/Kconfig

設定mt9p031 kernel config 為
接著重新compile kernel及module並安裝至root file system.

如果driver 順利掛上,在kernel log會看到

mt9p031 2-0048: mt9p031 chip ID 1801

根據driver source 中 README提到可以透過sysfs更改camera 參數.我實際測試卻出現錯誤@@

# cd /sys/devices/platform/i2c_omap.2/i2c-2/2-0048/
# cat gain_val 24
# echo "40" > gain_val
[ 2209.002258] mt9p031 2-0048: Error setting gain.-121
[ 2209.006988] mt9p031: Global gain write failed

Camera 測試的可用gstreamer.
不過實際測試frame rate還是無法到達30fps應該是gstreamer效率的關係,
因此我修改TI提供的demo程式來讀取camera確實就能達到30fps.
接著再把以前曾經實做過的以TI DSP encode H.264加上去,最後再輸出打包為H264RTP封包.
source code放在github

https://github.com/gigijoe/BeagleBoard-xM-video_encode_v4l2_rtp

將project抓下來後請搬到
$DVSDK/dmai_2_20_00_14/packages/ti/sdo/dmai/apps/
cd $DVSDK
make dmai

執行檔位在
dmai_2_20_00_14/packages/ti/sdo/dmai/apps/video_encode_v4l2_rtp/linux/video_encode_v4l2_rtp_dm3730.x470MV

將它複製到root filesystem中 /usr/share/ti/ti-dmai-apps/

萬事具備,執行吧

BeagleBoard xM

cd /usr/share/ti/ti-dmai-apps/
./video_encode_v4l2_rtp_dm3730.x470MV -b 2000000 -c h264enc -i /dev/video0 -o 192.168.168.93 -p 1234 -r 640x480 --benchmark

PC : IP 192.168.168.93

gst-launch udpsrc port=1234 caps="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H264" ! rtph264depay ! ffdec_h264 ! xvimagesink


最後在透過usb ethernet 傳送影像會hang住,網路上有人發生過但還沒有答案.

http://groups.google.com/group/beagleboard/browse_thread/thread/375026c833e1308b/528751f3690c7d5b?lnk=raot

[  103.995117] ------------[ cut here ]------------
[  103.999908] WARNING: at net/sched/sch_generic.c:255 dev_watchdog+0x17c/0x280()
[  104.007202] NETDEV WATCHDOG: usb0 (smsc95xx): transmit queue 0 timed out
[  104.014099] Modules linked in: sdmak lpm_omap3530 dsplinkk cmemk bufferclass_ti omaplfb pvrsrvkm ipv6 rtc_twl rtc_core mt9p031
[  104.025756] [ ] (unwind_backtrace+0x0/0xdc) from [ ] (warn_slowpath_common+0x48/0x60)
[  104.035247] [ ] (warn_slowpath_common+0x48/0x60) from [ ] (warn_slowpath_fmt+0x24/0x30)
[  104.044921] [ ] (warn_slowpath_fmt+0x24/0x30) from [ ] (dev_watchdog+0x17c/0x280)
[  104.054199] [ ] (dev_watchdog+0x17c/0x280) from [ ] (run_timer_softirq+0x268/0x378)
[  104.063568] [ ] (run_timer_softirq+0x268/0x378) from [ ] (__do_softirq+0xf0/0x1ec)
[  104.072784] [ ] (__do_softirq+0xf0/0x1ec) from [ ] (irq_exit+0x48/0x9c)
[  104.081024] [ ] (irq_exit+0x48/0x9c) from [ ] (asm_do_IRQ+0x74/0x90)
[  104.089019] [ ] (asm_do_IRQ+0x74/0x90) from [ ] (__irq_svc+0x44/0xa8)
[  104.097076] Exception stack(0xc0603f88 to 0xc0603fd0)
[  104.102172] 3f80:                   00000000 80000013 00f9982c 00000000 c0602000 c064db9c
[  104.110412] 3fa0: c002f014 c0605e68 8002cc0c 413fc082 0000001f 00000000 c06085b8 c0603fd0
[  104.118774] 3fc0: c0045450 c0036f1c 60000013 ffffffff
[  104.123962] [ ] (__irq_svc+0x44/0xa8) from [ ] (cpu_idle+0x78/0xbc)
[  104.131866] [ ] (cpu_idle+0x78/0xbc) from [ ] (start_kernel+0x260/0x2c0)
[  104.140197] [ ] (start_kernel+0x260/0x2c0) from [<80008034>] (0x80008034)
[  104.147827] ---[ end trace 640b83e4eff706c8 ]---

我猜應該是hardware的問題,因為我用USB Wifi也會當.
目前的解法是從USB otg port接USB hub再接USB wifi.
這樣,網路就不會斷了...

Reference :
http://maxgalemin.blogspot.com/2011/04/li-5m03-camera-on-beagleboard-xm.html

http://gitorious.org/rowboat/hardware-ti-omap3/blobs/e82865bd56a086480972fecdecc6f38308c05c35/liboverlay/v4l2_utils.c

http://blogold.chinaunix.net/u/19273/showart_2254379.html

http://e2e.ti.com/support/dsp/davinci_digital_media_processors/f/100/t/7826.aspx

http://e2e.ti.com/support/dsp/omap_applications_processors/f/447/p/87922/303994.aspx






2011年5月5日 星期四

BeagleBoard Uart Level Shift

There are three Uart port can be use on BeagleBoard, while Uart 3 as default console port, Uart 1 & 2 are free to use. There are many devices can be connect to Uart, such as GPS module, blue tooth module and PWM controller.

But, there's a serious problem. The BeagleBoard I/O works at 1.8v and for most of devices 1.8v is not "High" enough. So, I'm trying to higher the 1.8v signal to 5v signal.
Google this issue, I found the procdure is called "Level Shift" and can be done with two n-channel FET. The actual electronic circuit as below.

http://www-g.eng.cam.ac.uk/mmg/teaching/linearcircuits/mosfet.html

 

The n-channel FET is 2N7000
http://www.fairchildsemi.com/ds/2N/2N7000.pdf

According to BeagleBoard SRM (System Reference Manual), Uart 2 pins can be found on the expansion header.

PIN 6 - UART2_TX

Make sure the pin mux is correct configured. It should be work.




2011年5月4日 星期三

BeagleBoard i2c SRF08 example code

According to http://www.robot-electronics.co.uk/htm/srf08tech.shtml


i2c_srf08.h



/*
 * i2c_srf08.h : SRF08 ultra sonic range finder
 *
 *  (C) 2011 by Steve Chang
 *  stevegigijoe@yahoo.com.tw
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifndef _I2C_SRF08_H
#define _I2C_SRF08_H

#include "bool.h"

typedef struct I2cSrf08 I2cSrf08;

I2cSrf08 *I2cSrf08_DefaultInstance(char *device);
int I2cSrf08_Open(I2cSrf08 *is);
void I2cSrf08_Close(I2cSrf08 *is);
void I2cSrf08_SetMaxRange(I2cSrf08 *is, unsigned char range);
void I2cSrf08_SetMaxGain(I2cSrf08 *is, unsigned char gain);
int I2cSrf08_BlockRangeInCentimeters(I2cSrf08 *is);
int I2cSrf08_RangingInCentimeters(I2cSrf08 *is);
int I2cSrf08_GetRange(I2cSrf08 *is);

#endif


i2c_srf08.c


/*
 * i2c_srf08.c : SRF08 ultra sonic range finder
 *
 *  (C) 2011 by Steve Chang
 *  stevegigijoe@yahoo.com.tw
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include
#include
#include
#include
#include
#include
#include

#include "i2c_srf08.h"

struct I2cSrf08  {
  int fd;
  char *device;
  unsigned char range;
  unsigned char gain;
  bool ranging;
};

I2cSrf08 *I2cSrf08_DefaultInstance(char *device)
{
  static I2cSrf08 i2csrf08;
 
  if(!device)
    return 0;

  memset(&i2csrf08, 0, sizeof(I2cSrf08));
 
  i2csrf08.device = strdup(device);
#if 0 
  i2csrf08.range = 0xff; /*  11 m : default */
  i2csrf08.range = 0x8c; /*  6 m */
  i2csrf08.range = 0x18; /*  1 m */
  i2csrf08.range = 0x1;  /*  86 mm */
  i2csrf08.range = 0x0;  /*  43 mm */
#endif
  i2csrf08.range = 0xff; /*  11 m : default */

#if 0
  i2csrf08.gain = 0x0; /*  min 94 */
  i2csrf08.gain = 0x1f; /* default & max 1025 */
#endif
  i2csrf08.gain = 0x1f;
 
  return &i2csrf08;
}

#define SRF08_I2C_ADDR  0x70

int I2cSrf08_Open(I2cSrf08 *is)
{
  is->fd = open(is->device, O_RDWR);
  if(is->fd == -1)
    return -1;
 
  if(ioctl(is->fd, I2C_SLAVE, SRF08_I2C_ADDR) < 0)  {
    printf("[SRF08] None exist device address 0x%x\n", SRF08_I2C_ADDR);
    close(is->fd);
    is->fd = 0;
    return -1;
  }
 
  unsigned char buf[2];
 
  buf[0] = 0x1; /*  Register 1  */
  buf[1] = is->gain;  /*  Gain */
  if(write(is->fd, buf, 2) != 2)
    return -1;

  buf[0] = 0x2; /*  Register 2  */
  buf[1] = is->range;  /*  Range */
  if(write(is->fd, buf, 2) != 2)
    return -1;
 
  return is->fd;
}

void I2cSrf08_Close(I2cSrf08 *is)
{
  if(is->fd)
    close(is->fd);
  is->fd = 0;
}

void I2cSrf08_SetMaxRange(I2cSrf08 *is, unsigned char range)
{
  is->range = range;
 
  unsigned char buf[2];
 
  buf[0] = 0x2; /*  Register 2  */
  buf[1] = is->range;  /*  Range */
  if(write(is->fd, buf, 2) != 2)
    printf("[SRF08] Fail to write !!!\n");
 
  return;
}

void I2cSrf08_SetMaxGain(I2cSrf08 *is, unsigned char gain)
{
  if(gain > 0x1f)
    gain = 0x1f;
 
  is->gain = gain;
 
  unsigned char buf[2];
 
  buf[0] = 0x1; /*  Register 1  */
  buf[1] = is->gain;  /*  Gain */
  if(write(is->fd, buf, 2) != 2)
    printf("[SRF08] Fail to write !!!\n");
 
  return;
}

int I2cSrf08_BlockRangeInCentimeters(I2cSrf08 *is)
{
  unsigned char buf[2];
 
  buf[0] = 0x0; /*  Register 0  */
  buf[1] = 81;  /*  Range in centimeters */
  if(write(is->fd, buf, 2) != 2)
    return -1;
 
  while(1)  {
    usleep(65000);

    buf[0] = 0x0; /*  Register 0 : software reversion */
    if(write(is->fd, buf, 1) != 1)  {
      usleep(100);
      continue;
    }
   
    if(read(is->fd, buf, 1) != 1)  {
      usleep(100);
      continue;
    }
   
    if(buf[0] != 0xff)  /*  While ranging it returns 0xff */
      break;  /*  Range data ready now  */
  }
 
  int i;
  char hb, lb;
  unsigned short r = 0;
  for(i=0;i<17;i++) { /*  There are 17 echo buffers */
    buf[0] = 2 + (i << 1); /*  Register 2, 4, 6 ...  */
    if(write(is->fd, buf, 1) != 1)
      return -1;
    if(read(is->fd, buf, 1) != 1)
      return -1;
    hb = buf[0];

   
    buf[0] = 3 + (i << 1); /*  Register 3, 5, 7 ...  */
    if(write(is->fd, buf, 1) != 1)
      return -1;
    if(read(is->fd, buf, 1) != 1)
      return -1;
    lb = buf[0];

    if(hb == 0 && lb == 0)
      break;
/*   
    printf("High byte : %d\n", hb);
    printf("Low byte : %d\n", lb);
*/
    r = (hb << 8) + lb;
    printf("[SRF08] %dst echo range = %u\n", i, r);
  }
 
  return 0;
}

int I2cSrf08_RangingInCentimeters(I2cSrf08 *is)
{
  if(is->ranging == true)
    return 0;

  unsigned char buf[2];

  buf[0] = 0x0; /*  Register 0  */
  buf[1] = 81;  /*  Range in centimeters */
  if(write(is->fd, buf, 2) != 2)
    return -1;
 
  is->ranging = true;
 
  return 0;
}

int I2cSrf08_GetRange(I2cSrf08 *is)
{
  if(is->ranging == false)
    return 0;

  unsigned char buf[1];

  char hb, lb;

  buf[0] = 0x0; /*  Register 0 : software reversion */
  if(write(is->fd, buf, 1) != 1)
    return -1;
  if(read(is->fd, buf, 1) != 1) {
    printf("[SRF08] Fail to read !!!\n");
    return -1;
  }

  if(buf[0] == 0xff)  {
    printf("[SRF08] Range data not ready !!!\n");
    return -1;
  }

  buf[0] = 2; /*  Register 2, 4, 6 ...  */
  if(write(is->fd, buf, 1) != 1)
    return -1;

  if(read(is->fd, buf, 1) != 1)
    return -1;

  hb = buf[0];

  buf[0] = 3; /*  Register 3, 5, 7 ...  */
  if(write(is->fd, buf, 1) != 1)
    return -1;

  if(read(is->fd, buf, 1) != 1)
    return -1;

  lb = buf[0];

  is->ranging = false;
 
  if(hb == 0 && lb == 0)  {
    printf("[SRF08] Fail to get range !!!\n");
    return -1;
  }

  unsigned short r = (hb << 8) + lb;
 
  return (int)r;
}


ultra_sonic.c


/*
 * ultra_sonic.c : SRF08 ultra sonic range finder sample program
 *
 *  (C) 2011 by Steve Chang
 *  stevegigijoe@yahoo.com.tw
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include

#include "i2c_srf08.h"

#define I2C_SRF08_DEVICE  "/dev/i2c-2"

int main(int argc, char **argv)
{
  I2cSrf08 *is = I2cSrf08_DefaultInstance(I2C_SRF08_DEVICE);
 
  int r = I2cSrf08_Open(is);
  if(r == -1) {
    printf("Fail to open %s\n", I2C_SRF08_DEVICE);
    goto leave;
  }

  while(1)
    I2cSrf08_BlockRangeInCentimeters(is);

leave:
  I2cSrf08_Close(is);

  return r;
}


The result as below

# ./ultra_sonic
[  851.740844] i2c_omap i2c_omap.2: Transmit error
[SRF08] 0st echo range = 32
[SRF08] 1st echo range = 86
[SRF08] 2st echo range = 150
[SRF08] 3st echo range = 216
[SRF08] 4st echo range = 280
[SRF08] 5st echo range = 344
[SRF08] 6st echo range = 410
[SRF08] 7st echo range = 474
[SRF08] 8st echo range = 560
[SRF08] 9st echo range = 795
[SRF08] 10st echo range = 926
[SRF08] 11st echo range = 1050
[SRF08] 0st echo range = 33
[SRF08] 1st echo range = 87
[SRF08] 2st echo range = 151
[SRF08] 3st echo range = 217
[SRF08] 4st echo range = 281
[SRF08] 5st echo range = 346
[SRF08] 6st echo range = 410
[SRF08] 7st echo range = 474
[SRF08] 8st echo range = 563
[SRF08] 9st echo range = 630
[SRF08] 10st echo range = 795