顯示具有 OMAP3530 標籤的文章。 顯示所有文章
顯示具有 OMAP3530 標籤的文章。 顯示所有文章

2011年4月27日 星期三

BeagleBoard i2c SRF08

SRF08 is an ultra sonic range finder, I'm trying to connect it to BeagleBoard. The hardware interface is i2c and we need to do some modify to kernel & u-boot to get it work.

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

Reference
http://yetanotherhackersblog.wordpress.com/2011/04/07/interfacing-the-beagleboard-with-an-srf08-ultrasonic-ranger-over-i2c/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+BeagleBoard+%28BeagleBoard.org%29&utm_content=FaceBook

1.Hardware interface
BeagleBoard i2c interface runs at 1.8v and SRF08 i2c interface runs at 5v. In order to get it work, we need i2c level shift. There are some chips can do it, what I got is PCA9517.
http://elinux.org/BeagleBoard_Hardware_Interfacing

http://ics.nxp.com/support/documents/interface/pdf/an97055.pdf

2.The circuit


We are planing to use BeagleBoard I2C2 interface, which pins are at expansion connector pin 23 and 24.

Be attention ! all the 10k resisters are rquired.
http://groups.google.com/group/beagleboard/browse_thread/thread/a6c42ef56c6a2da2/1608e6c0f0207a8d?lnk=raot

3.u-boot
First, make sure the pin mux is correct.

boards/ti/beagle/beagle.h

-MUX_VAL((CP(I2C2_SCL), (IEN | PTU | EN | M4) \
-MUX_VAL((CP(I2C2_SDA), (IEN | PTU | EN | M4) \
+MUX_VAL((CP(I2C2_SCL), (IEN | PTU | EN | M0) \
+MUX_VAL((CP(I2C2_SDA), (IEN | PTU | EN | M0) \


Then enable pull-up internal resister on i2c2
http://groups.google.com/group/beagleboard/browse_thread/thread/f5d308f24b27bb38/21febf1a98e0be0c?lnk=raot


4.kernel
Enable I2C2 interface

static int __init omap3_beagle_i2c_init(void)
{
        omap_register_i2c_bus(1, 2600, beagle_i2c_boardinfo,
                        ARRAY_SIZE(beagle_i2c_boardinfo));

+#if defined CONFIG_INPUT_ST_MOTION_SENSOR
        omap_cfg_reg(AE4_34XX_GPIO136);
        omap_register_i2c_bus(2, 400, beagle_i2c2_boardinfo,
                        ARRAY_SIZE(beagle_i2c2_boardinfo));
+#else
+       omap_register_i2c_bus(2, 100, NULL, 0);
+#endif
        /* Bus 3 is attached to the DVI port where devices like the pico DLP
         * projector don't work reliably with 400kHz */
        omap_register_i2c_bus(3, 100, NULL, 0);
        return 0;
}

Then you can find /dev/i2c-2 device node

5.Testing

# ls /dev/i2c-2 -al
crw-rw----    1 root     root      89,   2 Jan  1 00:00 /dev/i2c-2

# i2cdetect -r 2
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-2 using read byte commands.
I will probe address range 0x03-0x77.
Continue? [Y/n] y
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: 70 -- -- -- -- -- -- --                        


Get range in centimeters

# i2cset 2 112 0 81
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will write to device file /dev/i2c-2, chip address 0x70, data address
0x00, data 0x51, mode byte.
Continue? [Y/n] y
# i2cget 2 112 2
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will read from device file /dev/i2c-2, chip address 0x70, data address
0x02, using read byte data.
Continue? [Y/n] y
0x00
# i2cget 2 112 3
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will read from device file /dev/i2c-2, chip address 0x70, data address
0x03, using read byte data.
Continue? [Y/n] y
0x25

We got 0x25 = 37 cm




2011年1月20日 星期四

BeagleBoard PWM with RC Servo


OMAP3 PWM resource

http://elinux.org/BeagleBoardPWM

http://www.jumpnowtek.com/index.php?option=com_content&view=article&id=56&Itemid=63

RC Servo resource

http://robot.avayanex.com/?tag=rc-servo

http://robot.pixnet.net/blog/post/26779024

RC Servo duty cycle 最短要 20.83 ms, 也就是48Hz 以下.
Pulse width範圍在 1~2.5 ms左右,各廠牌型號Servo略有不同

2.OMAP3 PWM
OMAP3 總共支援 4 個PWM channel, 在BeagleBoard線路有拉出來的有3組,分別是PWM 9, 10, 11
位於Expansion Connector Pin 4,  8, 10. (參考BBSRM Table 20)

3.kernel 需要稍作修改(2.6.29)
將mux設為PWM pin(參考 OMAP35x Technical Reference Manual (Rev.M) 7.4.4.3 p.772)

arch/arm/mach-omap2/mux.c
...

#if 0
/* UART2 */
MUX_CFG_34XX("AA25_34XX_UART2_TX", 0x178,
        OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
MUX_CFG_34XX("AD25_34XX_UART2_RX", 0x17A,
        OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
MUX_CFG_34XX("AB25_34XX_UART2_RTS", 0x176,
        OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
MUX_CFG_34XX("AB26_34XX_UART2_CTS", 0x174,
        OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
#endif

/* PWM */
/*  OMAP35x Technical Reference Manual (Rev.M) 7.4.4.3 p.772*/
MUX_CFG_34XX("AA25_34XX_UART2_TX", 0x178,
    OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
MUX_CFG_34XX("AD25_34XX_UART2_RX", 0x17A,
    OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
MUX_CFG_34XX("AB25_34XX_UART2_RTS", 0x176,
    OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
MUX_CFG_34XX("AB26_34XX_UART2_CTS", 0x174,
    OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)

再來要disable CONFIG_OMAP_RESET_CLOCKS這樣PWM才能正常工作.

3.OMAP3 PWM driver

https://github.com/scottellis/omap3-pwm

https://github.com/neo01124/omap3-pwm

以上面兩個PWM driver為基礎作修改可分別控制3組PWM.
Device node
/dev/pwm/9
/dev/pwm/10
/dev/pwm/11

Clock source從文件及source code所了解的應該是可以更改.
我實際測試的結果是

PWM9    13MHz
PWM10  32KHz
PWM11  32KHz

不只是更改GPTi input frequency 這麼單純,必須實際修改omap34xx clock source.
搞了半天還是不能把32KHz 換成 13MHz

Frequency預設是48Hz
13MHz clock source 精確度很好.
32KHz clock source 的 duty cycle 範圍約在 4 ~ 13%, 約只有50個刻度.因此精確度並不高.



4.PWM Driver source

From github : git@github.com:gigijoe/omap3-pwm.git

omap_pwm.h

/*
 Copyright (c) 2010, Scott Ellis
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY Scott Ellis ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL Scott Ellis BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 

 Register definitions used by the pwm driver.
 Some for the PADCONF pin muxing, the rest for the PWM timer control.
*/

#ifndef PWM_H
#define PWM_H

#define OMAP34XX_PADCONF_START  0x48002030
#define OMAP34XX_PADCONF_SIZE   0x05cc

#define GPT8_MUX_OFFSET        (0x4800217A - OMAP34XX_PADCONF_START)
#define GPT9_MUX_OFFSET        (0x48002174 - OMAP34XX_PADCONF_START)
#define GPT10_MUX_OFFSET    (0x48002176 - OMAP34XX_PADCONF_START)
#define GPT11_MUX_OFFSET    (0x48002178 - OMAP34XX_PADCONF_START)

#define PWM_ENABLE_MUX        0x0002    /* IDIS | PTD | DIS | M2 */

#define CLK_32K_FREQ    32768
#define CLK_13K_FREQ    13312
#define CLK_SYS_FREQ    13000000

#define GPTIMER8        0x4903E000
#define GPTIMER9        0x49040000
#define GPTIMER10         0x48086000
#define GPTIMER11        0x48088000

#define GPT_REGS_PAGE_SIZE      4096

#define PWM8_CTL_BASE        GPTIMER8
#define PWM9_CTL_BASE        GPTIMER9
#define PWM10_CTL_BASE        GPTIMER10
#define PWM11_CTL_BASE        GPTIMER11


/* GPT register offsets */
#define GPT_TIOCP_CFG 0x010
#define GPT_TISTAT    0x014
#define GPT_TISR      0x018
#define GPT_TIER      0x01C
#define GPT_TWER      0x020
#define GPT_TCLR      0x024
#define GPT_TCRR      0x028
#define GPT_TLDR      0x02C
#define GPT_TTGR      0x030
#define GPT_TWPS      0x034
#define GPT_TMAR      0x038
#define GPT_TCAR1     0x03C
#define GPT_TSICR     0x040
#define GPT_TCAR2     0x044
#define GPT_TPIR      0x048
#define GPT_TNIR      0x04C
#define GPT_TCVR      0x050
#define GPT_TOCR      0x054
#define GPT_TOWR      0x058  

/* TCLR bits for PWM */
#define GPT_TCLR_ST         (1 << 0)    /* stop/start */
#define GPT_TCLR_AR         (1 << 1)    /* one shot/auto-reload */
#define GPT_TCLR_PTV_MASK        (7 << 2)    /* prescaler value 2^(PTV + 1) */
#define GPT_TCLR_PRE        (1 << 5)    /* disable/enable prescaler */
#define GPT_TCLR_CE         (1 << 6)    /* disable/enable compare */
#define GPT_TCLR_SCPWM      (1 << 7)    /* PWM value when off */
#define GPT_TCLR_TCM_MASK        (3 << 8)    /* transition capture mode */

#define GPT_TCLR_TRG_MASK     (3 << 10)    /* trigger output mode */
#define GPT_TCLR_TRG_OVFL    (1 << 10)    /* trigger on overflow */
#define GPT_TCLR_TRG_OVFL_MATCH    (2 << 10)    /* trigger on overflow and match */   

#define GPT_TCLR_PT         (1 << 12)    /* pulse/toggle modulation */
#define GPT_TCLR_CAPT_MODE      (1 << 13)    /* capture mode config */
#define GPT_TCLR_GPO_CFG        (1 << 14)    /* pwm or capture mode */

/* Ioctl definitions */

#define PWM_IOC_MAGIC 0x00

#define PWM_SET_DUTYCYCLE _IOW(PWM_IOC_MAGIC , 1, int)
#define PWM_GET_DUTYCYCLE _IOW(PWM_IOC_MAGIC , 2, int)
#define PWM_SET_FREQUENCY _IOW(PWM_IOC_MAGIC , 3, int)
#define PWM_GET_FREQUENCY _IOW(PWM_IOC_MAGIC , 4, int)
#define PWM_ON _IO(PWM_IOC_MAGIC , 5)
#define PWM_OFF _IO(PWM_IOC_MAGIC , 6)
#define PWM_SET_POLARITY _IOW(PWM_IOC_MAGIC , 7, int)
#define PWM_SET_CLK _IOW(PWM_IOC_MAGIC , 8, int)
#define PWM_SET_PRE _IOW(PWM_IOC_MAGIC , 9, int)
#define PWM_PLUS_DUTYCYCLE _IOW(PWM_IOC_MAGIC , 10, int)
#define PWM_MINUS_DUTYCYCLE _IOW(PWM_IOC_MAGIC , 11, int)

#define PWM_IOC_MAXNR 11

#endif /* ifndef PWM_H */





omap_pwm.c

/*
 Copyright (c) 2010, Scott Ellis
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY Scott Ellis ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL Scott Ellis BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#include "omap_pwm.h"

/* default frequency of 1 kHz */
//#define DEFAULT_TLDR    0xFFFFFFE0
/* default frequency of 48 Hz */
//#define DEFAULT_TLDR    0xFFFFFD55

/* default 50% duty cycle */
/* TMAR = (0xFFFFFFFF - ((0xFFFFFFFF - (DEFAULT_TLDR + 1)) / 2)) */
//#define DEFAULT_TMAR    0xFFFFFFEF
//#define DEFAULT_TMAR    0xFFFFFEAB

/* default TCLR is off state */
#define DEFAULT_TCLR (GPT_TCLR_PT | GPT_TCLR_TRG_OVFL_MATCH | GPT_TCLR_CE | GPT_TCLR_AR)

//#define DEFAULT_PWM_FREQUENCY 1024
#define DEFAULT_PWM_FREQUENCY 48

static int defaultFrequency = DEFAULT_PWM_FREQUENCY;
module_param(defaultFrequency, int, S_IRUGO);
MODULE_PARM_DESC(defaultFrequency, "The PWM frequency, power of two, max of 16384");


#define USER_BUFF_SIZE    128

struct gpt {
    u32 timer_num;
    u32 mux_offset;
    u32 gpt_base;
    u32 input_freq;
    u32 old_mux;
    u32 tldr;
    u32 tmar;
    u32 tclr;
    u32 num_freqs;
};

struct pwm_dev {
    int frequency;
    struct semaphore sem;
    struct gpt gpt;
    char *user_buff;
};

static dev_t devt;
static struct cdev cdev;

static struct pwm_dev pwm9_dev;
static struct pwm_dev pwm10_dev;
static struct pwm_dev pwm11_dev;


static int init_mux(struct pwm_dev *pwm_dev)
{
    void __iomem *base;

    base = ioremap(OMAP34XX_PADCONF_START, OMAP34XX_PADCONF_SIZE);
    if (!base) {
        printk(KERN_ALERT "init_mux(): ioremap() failed\n");
        return -1;
    }

    pwm_dev->gpt.old_mux = ioread16(base + pwm_dev->gpt.mux_offset);
    iowrite16(PWM_ENABLE_MUX, base + pwm_dev->gpt.mux_offset);
    iounmap(base);   

    return 0;
}

static int restore_mux(struct pwm_dev *pwm_dev)
{
    void __iomem *base;

    if (pwm_dev->gpt.old_mux) {
        base = ioremap(OMAP34XX_PADCONF_START, OMAP34XX_PADCONF_SIZE);
   
        if (!base) {
            printk(KERN_ALERT "restore_mux(): ioremap() failed\n");
            return -1;
        }

        iowrite16(pwm_dev->gpt.old_mux, base + pwm_dev->gpt.mux_offset);
        iounmap(base);   
    }

    return 0;
}

static int set_pwm_frequency(struct pwm_dev *pwm_dev, int frequency)
{
    void __iomem *base;

    base = ioremap(pwm_dev->gpt.gpt_base, GPT_REGS_PAGE_SIZE);
    if (!base) {
        printk(KERN_ALERT "set_pwm_frequency(): ioremap failed\n");
        return -1;
    }

    if (frequency < 0) {
        frequency = DEFAULT_PWM_FREQUENCY;
    } else {
        /* only powers of two, for simplicity */
        //frequency &= ~0x01;

        if (frequency > (pwm_dev->gpt.input_freq / 2))
            frequency = pwm_dev->gpt.input_freq / 2;
        else if (frequency == 0)
            frequency = DEFAULT_PWM_FREQUENCY;
    }

    pwm_dev->frequency = frequency;

    /* PWM_FREQ = 32768 / ((0xFFFF FFFF - TLDR) + 1) */
    pwm_dev->gpt.tldr = 0xFFFFFFFF - ((pwm_dev->gpt.input_freq / pwm_dev->frequency) - 1);

    /* just for convenience */   
    pwm_dev->gpt.num_freqs = 0xFFFFFFFE - pwm_dev->gpt.tldr;   

    iowrite32(pwm_dev->gpt.tldr, base + GPT_TLDR);

    /* initialize TCRR to TLDR, have to start somewhere */
    iowrite32(pwm_dev->gpt.tldr, base + GPT_TCRR);

    iounmap(base);

    return 0;
}

static int pwm_off(struct pwm_dev *pwm_dev)
{
    void __iomem *base;

    base = ioremap(pwm_dev->gpt.gpt_base, GPT_REGS_PAGE_SIZE);
    if (!base) {
        printk(KERN_ALERT "pwm_off(): ioremap failed\n");
        return -1;
    }

    pwm_dev->gpt.tclr &= ~GPT_TCLR_ST;
    iowrite32(pwm_dev->gpt.tclr, base + GPT_TCLR);
    iounmap(base);

    return 0;
}

static int pwm_on(struct pwm_dev *pwm_dev)
{
    void __iomem *base;

    base = ioremap(pwm_dev->gpt.gpt_base, GPT_REGS_PAGE_SIZE);

    if (!base) {
        printk(KERN_ALERT "pwm_on(): ioremap failed\n");
        return -1;
    }

    /* set the duty cycle */
    iowrite32(pwm_dev->gpt.tmar, base + GPT_TMAR);
   
    /* now turn it on */
    pwm_dev->gpt.tclr = ioread32(base + GPT_TCLR);
    pwm_dev->gpt.tclr |= GPT_TCLR_ST;

    iowrite32(pwm_dev->gpt.tclr, base + GPT_TCLR);
     iounmap(base);

    return 0;
}

static int scpwm(struct pwm_dev *pwm_dev, int sc)
{
    void __iomem *base;

    base = ioremap(pwm_dev->gpt.gpt_base, GPT_REGS_PAGE_SIZE);
    if (!base) {
        printk(KERN_ALERT "pwm_off(): ioremap failed\n");
        return -1;
    }

    if (sc == 1)
        pwm_dev->gpt.tclr |= GPT_TCLR_SCPWM;
    else
        pwm_dev->gpt.tclr &= ~GPT_TCLR_SCPWM;

    iowrite32(pwm_dev->gpt.tclr, base + GPT_TCLR);
    iounmap(base);

    return 0;
}

static int prescale(struct pwm_dev *pwm_dev, int div)
{
    void __iomem *base;
    int i = 0;
    base = ioremap(pwm_dev->gpt.gpt_base, GPT_REGS_PAGE_SIZE);

    if (!base) {
        printk(KERN_ALERT "pwm_off(): ioremap failed\n");
        return -1;
    }

    while (div > 2) {
        i++;
        div /= 2;
    }

    pwm_dev->gpt.tclr |= GPT_TCLR_PRE; //enable prescaler
    pwm_dev->gpt.tclr &= i << 2; //set prescaler ratio
    iowrite32(pwm_dev->gpt.tclr, base + GPT_TCLR);
    iounmap(base);

    return 0;
}

static int set_duty_cycle(struct pwm_dev *pwm_dev, unsigned int duty_cycle)
{
    unsigned int new_tmar;

    pwm_off(pwm_dev);

    if (duty_cycle == 0)
        return 0;
 
    new_tmar = (duty_cycle * pwm_dev->gpt.num_freqs) / 100;

    if (new_tmar < 1)
        new_tmar = 1;
    else if (new_tmar > pwm_dev->gpt.num_freqs)
        new_tmar = pwm_dev->gpt.num_freqs;
       
    pwm_dev->gpt.tmar = pwm_dev->gpt.tldr + new_tmar;
printk("TMAR : 0x%08x\n", pwm_dev->gpt.tmar);   
    return pwm_on(pwm_dev);
}

static ssize_t pwm_read(struct file *filp, char __user *buff, size_t count,
            loff_t *offp)
{
    size_t len;
    unsigned int duty_cycle;
    ssize_t error = 0;

      struct pwm_dev *pwm_dev = (struct pwm_dev *)filp->private_data;
 
    if (!buff)
        return -EFAULT;

    /* tell the user there is no more */
    if (*offp > 0)
        return 0;

    if (down_interruptible(&pwm_dev->sem))
        return -ERESTARTSYS;

    if (pwm_dev->gpt.tclr & GPT_TCLR_ST) {
        duty_cycle = (100 * (pwm_dev->gpt.tmar - pwm_dev->gpt.tldr))
                / pwm_dev->gpt.num_freqs;

        snprintf(pwm_dev->user_buff, USER_BUFF_SIZE,
                "PWM%d Frequency %u Hz Duty Cycle %u%%\n",
                pwm_dev->gpt.timer_num, pwm_dev->frequency, duty_cycle);
    }
    else {
        snprintf(pwm_dev->user_buff, USER_BUFF_SIZE,
                "PWM%d Frequency %u Hz Stopped\n",
                pwm_dev->gpt.timer_num, pwm_dev->frequency);
    }

    len = strlen(pwm_dev->user_buff);
 
    if (len + 1 < count)
        count = len + 1;

    if (copy_to_user(buff, pwm_dev->user_buff, count))  {
        printk(KERN_ALERT "pwm_read(): copy_to_user() failed\n");
        error = -EFAULT;
    }
    else {
        *offp += count;
        error = count;
    }

    up(&pwm_dev->sem);

    return error;   
}

static ssize_t pwm_write(struct file *filp, const char __user *buff,
            size_t count, loff_t *offp)
{
    size_t len;
    unsigned int duty_cycle;
    ssize_t error = 0;
   
      struct pwm_dev *pwm_dev = (struct pwm_dev *)filp->private_data;

    if (down_interruptible(&pwm_dev->sem))
        return -ERESTARTSYS;

    if (!buff || count < 1) {
        printk(KERN_ALERT "pwm_write(): input check failed\n");
        error = -EFAULT;
        goto pwm_write_done;
    }
   
    /* we are only expecting a small integer, ignore anything else */
    if (count > 8)
        len = 8;
    else
        len = count;
       
    memset(pwm_dev->user_buff, 0, 16);

    if (copy_from_user(pwm_dev->user_buff, buff, len)) {
        printk(KERN_ALERT "pwm_write(): copy_from_user() failed\n");
        error = -EFAULT;    
        goto pwm_write_done;
    }

    if(pwm_dev->user_buff[0] == '+')    {
        pwm_off(pwm_dev);
        if(pwm_dev->user_buff[1] != '\0')
            pwm_dev->gpt.tmar += simple_strtoul(&pwm_dev->user_buff[1], NULL, 0);
        pwm_on(pwm_dev);
printk("TMAR : 0x%08x\n", pwm_dev->gpt.tmar);
    } else if(pwm_dev->user_buff[0] == '-')    {
        pwm_off(pwm_dev);
        if(pwm_dev->user_buff[1] != '\0')
            pwm_dev->gpt.tmar -= simple_strtoul(&pwm_dev->user_buff[1], NULL, 0);
        pwm_on(pwm_dev);
printk("TMAR : 0x%08x\n", pwm_dev->gpt.tmar);
    } else    {
        duty_cycle = simple_strtoul(pwm_dev->user_buff, NULL, 0);

        set_duty_cycle(pwm_dev, duty_cycle);

    }
    /* pretend we ate it all */
    *offp += count;

    error = count;
pwm_write_done:

    up(&pwm_dev->sem);
   
    return error;
}

static int pwm_open(struct inode *inode, struct file *filp)
{
    int error = 0;

    struct pwm_dev *pwm_dev = 0;
   
    unsigned int minor = iminor(inode);

    switch(minor)    {
        case 9:        pwm_dev = &pwm9_dev;   
            break;
        case 10:    pwm_dev = &pwm10_dev;   
            break;
        case 11:    pwm_dev = &pwm11_dev;
            break;
    }
     
    if(pwm_dev == 0)
        return -EFAULT;

    filp->private_data = pwm_dev;

    if (down_interruptible(&pwm_dev->sem))
        return -ERESTARTSYS;

    if (pwm_dev->gpt.old_mux == 0) {
        if (init_mux(pwm_dev)) 
            error = -EIO;
        else if (set_pwm_frequency(pwm_dev, defaultFrequency))
            error = -EIO;
    }

    if (!pwm_dev->user_buff) {
        pwm_dev->user_buff = kmalloc(USER_BUFF_SIZE, GFP_KERNEL);
        if (!pwm_dev->user_buff)
            error = -ENOMEM;
    }

    up(&pwm_dev->sem);

    return error;   
}

int pwm_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
    int retval = 0;
      struct pwm_dev *pwm_dev = (struct pwm_dev *)filp->private_data;

    /*
    * extract the type and number bitfields, and don't decode
    * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
    */
    if (_IOC_TYPE(cmd) != PWM_IOC_MAGIC)
        return -ENOTTY;
    if (_IOC_NR(cmd) > PWM_IOC_MAXNR)
        return -ENOTTY;

     switch (cmd) {
        case PWM_ON:
            if (pwm_on(pwm_dev))
                retval = -EIO;
            break;
        case PWM_OFF:
            if (pwm_off(pwm_dev))
                retval = -EIO;
            break;
        case PWM_SET_DUTYCYCLE:
            if (set_duty_cycle(pwm_dev, arg))
                retval = -EIO;
            break;
        case PWM_GET_DUTYCYCLE:
            if (pwm_dev->gpt.tclr & GPT_TCLR_ST) { //PWM is on
                retval = (100 * (pwm_dev->gpt.tmar - pwm_dev->gpt.tldr))
                        / pwm_dev->gpt.num_freqs; //real duty cycle
            } else {
                printk(KERN_ALERT "PWM%d is OFF\n", pwm_dev->gpt.timer_num);
                retval = -EIO;
            }
            break;
        case PWM_SET_FREQUENCY:
            if (set_pwm_frequency(pwm_dev, arg))
                retval = -EIO;
            break;
        case PWM_GET_FREQUENCY:
            retval = pwm_dev->frequency;
            break;
        case PWM_SET_POLARITY:
            if (scpwm(pwm_dev, arg))
                retval = -EIO;
            break;
        case PWM_SET_CLK:
/* Do no change clock source !!! */
/*
            if (pwm_dev->gpt.timer_num == 9) {
                printk(KERN_ALERT "Only 32K clk can be used with GPT9\n");
                retval = -EIO;
            } else {
                if (arg == 1)
                    pwm_dev->gpt.input_freq = CLK_13K_FREQ;
                else
                    pwm_dev->gpt.input_freq = CLK_32K_FREQ;
            }
*/
        break;
        case PWM_SET_PRE:
            if (prescale(pwm_dev, arg))
                retval = -EIO;
            break;
        case PWM_PLUS_DUTYCYCLE:
            pwm_off(pwm_dev);
            pwm_dev->gpt.tmar++;
            pwm_on(pwm_dev);
            break;
        case PWM_MINUS_DUTYCYCLE:
            pwm_off(pwm_dev);
            if(pwm_dev->gpt.tmar > 0)
                pwm_dev->gpt.tmar--;
            pwm_on(pwm_dev);
            break;
        default: /* redundant, as cmd was checked against MAXNR */
            return -ENOTTY;
    }

    return retval;
}

static struct file_operations pwm_fops = {
    .owner = THIS_MODULE,
    .read = pwm_read,
    .write = pwm_write,
    .open = pwm_open,
    .ioctl = pwm_ioctl,
};

static int __init pwm_init_cdev(void)
{
    int error;

    error = alloc_chrdev_region(&devt, 9, 3, "pwm");    /*    minor number start from 9, count 3*/

    if (error < 0) {
        printk(KERN_ALERT "alloc_chrdev_region() failed: %d \n",
            error);
        return -1;
    }

    cdev_init(&cdev, &pwm_fops);
    cdev.owner = THIS_MODULE;
   
    error = cdev_add(&cdev, devt, 3);
    if (error) {
        printk(KERN_ALERT "cdev_add() failed: %d\n", error);
        unregister_chrdev_region(devt, 3);
        return -1;
    }   

    return 0;
}
 
static int __init pwm_init(void)
{
    memset(&pwm9_dev, 0, sizeof(struct pwm_dev));

    /* change these 4 values to use a different PWM */
    pwm9_dev.frequency = defaultFrequency;
    pwm9_dev.gpt.timer_num = 9;
    pwm9_dev.gpt.mux_offset = GPT9_MUX_OFFSET;
    pwm9_dev.gpt.gpt_base = PWM9_CTL_BASE;
    pwm9_dev.gpt.input_freq = CLK_SYS_FREQ;    /* GPT9 can only use 13MHz clock source */

    pwm9_dev.gpt.tldr = 0xFFFFFFFF - (pwm9_dev.gpt.input_freq / pwm9_dev.frequency) + 1;
    pwm9_dev.gpt.tmar = 0xFFFFFFFF - ((0xFFFFFFFF - (pwm9_dev.gpt.tldr + 1)) / 2);
    pwm9_dev.gpt.tclr = DEFAULT_TCLR;

    sema_init(&pwm9_dev.sem, 1);

    memset(&pwm10_dev, 0, sizeof(struct pwm_dev));

    /* change these 4 values to use a different PWM */
    pwm10_dev.frequency = defaultFrequency;
    pwm10_dev.gpt.timer_num = 10;
    pwm10_dev.gpt.mux_offset = GPT10_MUX_OFFSET;
    pwm10_dev.gpt.gpt_base = PWM10_CTL_BASE;
    pwm10_dev.gpt.input_freq = CLK_32K_FREQ;

    pwm10_dev.gpt.tldr = 0xFFFFFFFF - (pwm10_dev.gpt.input_freq / pwm10_dev.frequency) + 1;
    pwm10_dev.gpt.tmar = 0xFFFFFFFF - ((0xFFFFFFFF - (pwm10_dev.gpt.tldr + 1)) / 2);
    pwm10_dev.gpt.tclr = DEFAULT_TCLR;

    sema_init(&pwm10_dev.sem, 1);

    memset(&pwm11_dev, 0, sizeof(struct pwm_dev));

    /* change these 4 values to use a different PWM */
    pwm11_dev.frequency = defaultFrequency;
    pwm11_dev.gpt.timer_num = 11;
    pwm11_dev.gpt.mux_offset = GPT11_MUX_OFFSET;
    pwm11_dev.gpt.gpt_base = PWM11_CTL_BASE;
    pwm11_dev.gpt.input_freq = CLK_32K_FREQ;

    pwm11_dev.gpt.tldr = 0xFFFFFFFF - (pwm11_dev.gpt.input_freq / pwm11_dev.frequency) + 1;
    pwm11_dev.gpt.tmar = 0xFFFFFFFF - ((0xFFFFFFFF - (pwm11_dev.gpt.tldr + 1)) / 2);
    pwm11_dev.gpt.tclr = DEFAULT_TCLR;

    sema_init(&pwm11_dev.sem, 1);

    if (pwm_init_cdev())
        goto init_fail;

    printk(KERN_INFO "OMAP3 PWM: character device initialized (major=%d)\n", MAJOR(devt));

    return 0;

init_fail:
    return -1;
}
module_init(pwm_init);

static void __exit pwm_exit(void)
{
    cdev_del(&cdev);

    pwm_off(&pwm9_dev);
    restore_mux(&pwm9_dev);

    if (pwm9_dev.user_buff)
        kfree(pwm9_dev.user_buff);

    pwm_off(&pwm10_dev);
    restore_mux(&pwm10_dev);

    if (pwm10_dev.user_buff)
        kfree(pwm10_dev.user_buff);

    pwm_off(&pwm11_dev);
    restore_mux(&pwm11_dev);

    if (pwm11_dev.user_buff)
        kfree(pwm11_dev.user_buff);

    unregister_chrdev_region(devt, 3);

}
module_exit(pwm_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Scott Ellis - Jumpnow");
MODULE_AUTHOR("Steve Chang");
MODULE_DESCRIPTION("PWM example for Gumstix Overo");







2010年4月14日 星期三

OMAP3530 USB Wifi - RALINK RT73

1.Download 2009_0713_RT73_Linux_STA_Drv1.1.0.3 from ralink web site
2.Build driver.

cp Makefile.6 Makefile
Patch Makefile (Fix LINUX_SRC as yours)

--- Makefile.6    2009-07-13 02:32:22.000000000 +0800
+++ Makefile    2010-04-14 19:41:21.000000000 +0800
@@ -2,8 +2,9 @@
 #    Module Name: Makefile
 #    Abstract: Makefile for rt73 linux driver on kernel series 2.6
 ######################################################################
-PLATFORM=PC
+#PLATFORM=PC
 #PLATFORM=CMPC
+PLATFORM=BeagleBoard
 
 #Enable for wpa_supplicant's spcific driver "driver_ralink.c", default enabled.
 HAS_RALINK_WPA_SUPPLICANT_SUPPORT=y
@@ -40,6 +41,9 @@
 ifeq ($(PLATFORM),CMPC)
 LINUX_SRC = /home/fonchi/vendor/kernel-default-2.6.21/linux-2.6.21
 endif
+ifeq ($(PLATFORM),BeagleBoard)
+LINUX_SRC = ${HOME}/BeagleBoard/kernel
+endif
 
 EXTRA_CFLAGS += -I$(LINUX_SRC)/include
 
3.make all
4.Copy rt73.ko to root file system /etc/Wireless/RT73STA/rt73.ko
5.Booting target
6.Get it work

# insmod /etc/Wireless/RT73STA/rt73.ko
usbcore: registered new interface driver rt73
#
# usb 1-2: new high speed USB device using ehci-omap and address 2
usb 1-2: New USB device found, idVendor=148f, idProduct=2573
usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 1-2: Product: 802.11 bg WLAN
usb 1-2: Manufacturer: Ralink
usb 1-2: configuration #1 chosen from 1 choice
idVendor = 0x148f, idProduct = 0x2573
rausb0 (rt73): not using net_device_ops yet

# iwconfig
lo        no wireless extensions.

usb0      no wireless extensions.

rausb0    RT73 WLAN  ESSID:off/any  Nickname:""
          Mode:Auto  Frequency=2.412 GHz 
          RTS thr:off   Fragment thr:off
          Encryption key:off
          Link Quality=0/100  Signal level:-121 dBm  Noise level:-111 dBm
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:0   Missed beacon:0

# iwpriv
lo        no private ioctls.

usb0      no private ioctls.

rausb0    Available private ioctls :
          set              (8BE2) : set 1024 char  & get   0     
          show             (8BF3) : set 1024 char  & get   0     
          stat             (8BE9) : set 1024 char  & get 1024 char
          get_site_survey  (8BED) : set 1024 char  & get 1024 char
          get_RaAP_Cfg     (8BEF) : set 1024 char  & get   0     
          auth             (8BE7) : set   1 int   & get   0     
          enc              (8BE8) : set   1 int   & get   0     
          wpapsk           (8BEA) : set  64 char  & get   0     
          psm              (8BEB) : set   1 int   & get   0     

# ifconfig rausb0 up
=> usb_rtusb_open
# iwlist rausb0 scan
rausb0    Scan completed :
          Cell 01 - Address: 00:24:01:41:CA:97
                    Mode:Managed
                    ESSID:"Bendi"
                    Channel:1
                    Encryption key:on
                    Bit Rates:0 kb/s
          Cell 02 - Address: 00:90:CC:DD:6E:AC
                    Mode:Managed
                    ESSID:"3F_S/W_AP"
                    Channel:4
                    Encryption key:on
                    Bit Rates:0 kb/s
          Cell 03 - Address: 00:19:5B:25:7E:BE
                    Mode:Managed
                    ESSID:"26962315"
                    Channel:6
                    Encryption key:on
                    Bit Rates:4 Mb/s
          Cell 04 - Address: 00:26:5A:40:C6:EE
                    Mode:Managed
                    ESSID:"dlink"
                    Channel:11
                    Encryption key:on
                    Bit Rates:4 Mb/s

# iwconfig rausb0 essid 3F_S/W_AP
# iwconfig rausb0 mode managed
# iwpriv rausb0 set AuthMode=WPAPSK
# iwpriv rausb0 set EncrypType=TKIP
# MlmeAssocReqAction(): WPA/WPAPSK, Fill the ReqVarIEs with CipherTmp!

# MlmeAssocReqAction(): WPA/WPAPSK, Fill the ReqVarIEs with CipherTmp!
iwpriv rausb0 set WPAPSK=MlmeAssocReqAction(): WPA/WPAPSK, Fill the ReqVarIEs with CipherTmp!
MlmeAssocReqAction(): WPA/WPAPSK, Fill the ReqVarIEs with CipherTmp!
0289131323
# MlmeAssocReqAction(): WPA/WPAPSK, Fill the ReqVarIEs with CipherTmp!

7.USB EHCI with USB hub Problem...

hub 1-0:1.0: port 2 disabled by hub (EMI?), re-enabling...
usb 1-2: USB disconnect, address 5
usb 1-2.1: USB disconnect, address 6
usb 1-2.1.3: USB disconnect, address 8
uvcvideo: Failed to resubmit video URB (-19).
uvcvideo: Failed to resubmit video URB (-19).
uvcvideo: Failed to resubmit video URB (-19).
uvcvideo: Failed to resubmit video URB (-19).
uvcvideo: Failed to resubmit video URB (-19).
unregister_netdev()
usb 1-2.3: USB disconnect, address 7
ehci-omap ehci-omap.0: force halt; handhake d8064814 0000c000 00000000 -> -110

http://markmail.org/message/og4ts5gcn7if4v4l#query:disabled%20by%20hub%20(EMI%3F)%20beagleboard+page:1+mid:xl2txfnz7gvar65u+state:results

確定是H/W issue. BeagleBoard C2/C3都中


2009年11月3日 星期二

OMAP3530 DSP Howto ( Really works by DSPLINK)

搞了一段很長的時間終於把DSP功能弄起來了,該是回頭紀錄一下"眉角"了.

1.Before touch anything
目前有兩種方式可以控制DSP,一個是TI DVSDK提供的DSPLINK,另一個則是DSPBRIDGE.
以我從google搜尋之後的了解DSPBRIDGE目前是沒有繼續maintain.
DSPLINK是TI比較建議的方式.

所搭配的media library為
DSPLINK + gstreamer
DSPBRIDGE + openmax + gstreamer
http://felipec.wordpress.com/2009/10/13/new-project-gst-dsp-with-beagleboard-demo-image/
http://felipec.wordpress.com/2008/12/12/gst-openmax-demo-on-the-beagleboard/

這邊我選擇DSPLINK控制DSP

2.Software

dvsdk_3_00_02_44
gst-ti-plugin-full-1.00.02
gst-omapfb

Build and install to target root file system (過程就省略了)

可參考以下作法
http://ossie.wireless.vt.edu/trac/wiki/BeagleBoard_CodecEngine

安裝目錄
DVSDK : /opt/dvsdk
gstreamer : /opt

3.Setup
DSPLINK透過share memory的方式跟DSP交換資料所以有另一個driver叫cmemk.ko負責建立memory pool. 但這塊memory必須脫離kernel的掌控因此必須要空出一塊memory讓cmemk.ko使用.至於大小要看實際memory size跟DSP所需要的size來決定.

http://pixhawk.ethz.ch/wiki/tutorials/omap/dsplink/memorymap

依照以上說明修改以下檔案

dsplink_1_61_03/packages/dsplink/config/all/CFG_OMAP3530_SHMEM.c
dsplink_1_61_03/packages/dsplink/dsp/inc/DspBios/5.XX/OMAP3530/dsplink-omap3530-base.tci
dsplink_1_61_03/packages/dsplink/config/all/CFG_OMAP3530_SHMEM.c

我的target board有256MB DDR,因此記憶體配置如下

# 0x40200000    60 KB   CMEM (internal memory, see comment below)
# 0x80000000    200 MB   Linux
# 0x8C900000    16 MB   CMEM (external memory)
# 0x8D900000     2 MB   DSPLINK (MEM)
# 0x8DB00000     unused

kernel boot command 加上 mem=200M

For kernel 2.6.27

optargs=init=/init omapfb.video_mode=1280x1024MR-16@60 vram=12M omapfb.vram=4M,4M,4M omapfb.debug=1 omap-dss.def_disp=lcd omap-dss.debug=1 mem=200M

For kernel 2.6.29

setenv optargs 'init=/init omapdss.def_disp=dvi omapfb.mode=dvi:1280x1024MR-16@60 vram=12M omapfb.vram=0:4M,1:4M,2:4M mem=200M'

memory pool配置如下

insmod cmemk.ko phys_start=0x8C900000 phys_end=0x8D900000 pools=20x4096,10x131072,2x1048576,1x5250000,4x829440,2x691200

gstreamer需要設定target上的環境變數好讓系統找的到執行檔及plug-in

export PATH=$PATH:/opt/gstreamer/bin
export GST_PLUGIN_PATH=/opt/gstreamer/lib/gstreamer-0.10
export LD_LIBRARY_PATH=/opt/gstreamer/lib

3.Get DSP work

載入drivers

#cd /opt/dvsdk
#./loadmodules.sh
CMEMK module: built on Oct 30 2009 at 20:23:52
  Reference Linux version 2.6.28
  File /home/gigijoe/OMAP3530/dvsdk_3_00_02_44/linuxutils_2_24_02/packages/ti/sdo/linuxutils/cmem/src/module/cmemk.c
ioremap_nocache(0x8c900000, 16777216)=0xcf000000
allocated heap buffer 0xcf000000 of size 0x32c000
cmem initialized 6 pools between 0x8c900000 and 0x8d900000
DSPLINK Module (1.61.03) created on Date: Oct 30 2009 Time: 20:20:31

# lsmod
lpm_omap3530 8276 0 - Live 0xbf02c000
dsplinkk 114052 1 lpm_omap3530, Live 0xbf00b000
cmemk 24428 0 - Live 0xbf000000

測試omapfb, 應該會在畫面上看到彩色條紋.

gst-launch videotestsrc num-buffers=1000 ! omapfbsink

播放TI h.264 raw data sample

gst-launch --gst-debug-level=1 filesrc location="/media/dcim/100andro/ntsc.264" ! typefind ! TIViddec2 ! omapfbsink

Play avi file

gst-launch --gst-debug-no-color --gst-debug=TI*:2 filesrc location=/media/dcim/100andro/aris.mpeg ! typefind ! qtdemux name=demux demux.audio_00 ! queue max-size-buffers=8000 max-size-time=0 max-size-bytes=0 ! typefind ! TIAuddec1 ! audioconvert ! osssink demux.video_00 ! typefind ! TIViddec2 ! omapfbsink

Play mpeg4 file

gst-launch --gst-debug-no-color --gst-debug=TI*:2 filesrc location=/media/dcim/100andro/KenBlock-TopGear.mp4 ! typefind ! qtdemux name=demux demux.audio_00 ! queue max-size-buffers=8000 max-size-time=0 max-size-bytes=0 ! typefind ! TIAuddec1 ! audioconvert ! osssink demux.video_00 ! typefind ! TIViddec2 ! omapfbsink

Play H.264 mpeg4 file without mp3 audio

gst-launch filesrc location=/media/dcim/100andro/sany0014.mp4  ! typefind ! qtdemux name=demux  demux.video_00 ! typefind ! TIViddec2 ! omapfbsink

4.Debug

http://tiexpressdsp.com/wiki/index.php?title=Debugging_DSPLink_using_SET_FAILURE_REASON_prints

http://tiexpressdsp.com/index.php/Enabling_trace_in_DSPLink

一開始有一段時間kernel-2.6.29 DSP_init總是失敗

# ./messagegpp ./message.out 1000
========== Sample Application : Failure [0x8000800b] in [0x401] at line 522
MESSAGE ==========
Entered MESSFailure [0x8000802d] in [0x401] at line 544
AGE_Create ()
Failure [0x8000802d] in [0x401] at line 544
Failure [0x8000802d] in [0x401] at line 544
ISR_Install:445
request_irq 28
request_irq failed with error: -16
Failure [0x80008008] in [0x502] at line 459
Failure [0x80008008] in [0x80a] at line 824
Failure [0x80008008] in [0x80a] at line 1061
Failure [0x80008008] in [0x801] at line 597
Failure [0x80008008] in [0x701] at line 370
 DSP_init status [0x80008008]
Assertion failed ((isrObj!= NULL) && (ISR_InstalledIsrs [isrObj->dspId][isrObj->irq] == isrObj)). File : /home/gigijoe/OMAP3530/dvsdk_3_00_02_44/dsplink_1_61_03/packages/dsplink/gp
p/src/../../gpp/src/osal/Linux/2.6.18/isr.c Line : 507
Failure [0x80008000] in [0x502] at line 515
Failure [0x80008008] in [0x300] at line 476
Failure [0x80008008] in [0x300] at line 563
PROC_attach () failed. Status = [0x80008008]
PROC_setup () failed. Status = [0x80008008]
Leaving MESSAGE_Create ()
Entered MESSAGE_Delete ()
Assertion failed (IS_VALID_MSGQ (msgqQueue)). File : msgq.c Line : 484
MSGQ_release () failed. Status = [0x8000800b]
Assertion failed (IS_VALID_MSGQ (msgqQueue)). File : msgq.c Line : 335
Leaving MESSAGE_Delete ()
====================================================

Trace DSPLINK driver發現request_irq 28 居然失敗了.很明顯IRQ被佔據了.
看看到底是誰
cat /proc/interrupts

           CPU0
 11:          0        INTC  prcm
 12:          1        INTC  DMA
 18:          0        INTC  sr1
 19:          0        INTC  sr2
 24:          0        INTC  omap-iommu.1, Omap 3 Camera ISP
 25:          1        INTC  OMAP DSS
 28:          0        INTC  omap-iommu.2
 56:        347        INTC  i2c_omap
 61:          0        INTC  i2c_omap
 72:          1        INTC  serial idle
 73:          1        INTC  serial idle
 74:         94        INTC  serial idle, serial
 77:          0        INTC  ehci_hcd:usb2
 83:          0        INTC  mmc0
 86:         14        INTC  mmc1
 92:          0        INTC  musb_hdrc
 93:          0        INTC  musb_hdrc
 95:        641        INTC  gp timer
160:          0        GPIO  mmc1
167:          0        GPIO  user
181:          8        GPIO  eth0
378:          0     twl4030  twl4030_usb
379:          0     twl4030  rtc0
384:          0     twl4030  mmc0

原來是iommu啊,OK,調整一下kernel config

Disable
Device Drivers->Multimedia Devices->Video Capture Adapters->OMAP 3 Camera Support
System Type->TI OMAP Implemenation->IOMMU Support

這樣就OK囉

其實還有一些疑慮沒有解決.
IOMMU 以 Shared IRQ 方式 request_irq而DSPLINK Driver request_irq 並不是.
因此造成問題,DSPLINK Driver是否應該以Shared IRQ方式request_irq呢?

Problem :

# gst-launch --gst-debug=TI*:2 v4l2src always_copy=FALSE num-buffers=100 ! video
/x-raw-yuv,width=320,height=240 ! ffmpegcolorspace ! TIVidenc1 codecName=h264enc
 engineName=codecServer contiguousInputFrame=FALSE genTimeStamps=FALSE ! filesin
k location=/tmp/enc.264

(gst-launch-0.10:636): GLib-WARNING **: getpwuid_r(): failed due to unknown user id (0)
Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
0:00:01.011901868   636    0x9ebb0 WARN             TIVidenc1 gsttividenc1.c:1432:gst_tividenc1_codec_start: error: failed to open codec engine "codecServer"

ERROR: from element /GstPipeline:pipeline0/GstTIVidenc1:tividenc10: failed to open codec engine "codecServer"

Additional debug info:
gsttividenc1.c(1432): gst_tividenc1_codec_start (): /GstPipeline:pipeline0/GstTIVidenc1:tividenc10
Execution ended after 382354731 ns.
Setting pipeline to PAUSED ...
Setting pipeline to READY ...
0:00:01.016387951   636    0x9ebb0 WARN             TIVidenc1 gsttividenc1.c:1601:gst_tividenc1_encode_thread: error: failed to start codec

gst-launch-0.10: BufTab.c:440: BufTab_getNumBufs: Assertion `hBufTab' failed.
Aborted

重新compile ti-gstreamer就好了...

Problem:

ERROR: from element /GstPipeline:pipeline0/GstTIViddec2:tividdec20: Failed to determine target board

這個問題是因為所使用的OMAP3530 board不是TI support的.
自己修改來support吧
Get board name first
# cat /proc/cpuinfo
Processor       : ARMv7 Processor rev 3 (v7l)
BogoMIPS        : 499.92
Features        : swp half thumb fastmult vfp edsp thumbee neon vfpv3
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x1
CPU part        : 0xc08
CPU revision    : 3

Hardware        : OMAP3 Thunder Board
Revision        : 0020
Serial          : 0000000000000000

So, the board name is OMAP3 Thunder Board

Edit dmai_2_05_00_04/packages/ti/sdo/dmai/linux/Cpu.c

...

    }
    else if ((strcmp(valBuf,"OMAP3EVM Board") == 0) ||
            (strcmp(valBuf, "OMAP3 EVM") == 0) ||
            (strcmp(valBuf, "OMAP3 Beagle Board") == 0) ||
            (strcmp(valBuf, "OMAP3 Thunder Board") == 0)) {  <<-- Add here
            *device = Cpu_Device_OMAP3530;
    }
    else {
        Dmai_err0("Unknown Cpu Type!\n");
        return Dmai_EFAIL;
    }

    return Dmai_EOK;
}

...

Then rebuild again ...








2009年9月24日 星期四

OMAP3530 DSP Howto

沿襲TI一貫的傳統,Software package & document一堆但都缺乏最基本的Step-by-Step.
在網路上搜尋到一些resource先記下來

GSG: OMAP35x DVEVM Software Setup

BeagleBoard/DSP Howto

BeagleBoard/gst-openmax

http://groups.google.com/group/beagleboard/browse_thread/thread/05557a0d149fb225

gst-openmax demo on the beagleboard

1.Install TI dspbridge libraries

cd ${HOME}/OMAP3530

git clone git://gitorious.org/ti-dspbridge/userspace.git ti_dspbridge

cd ti_dspbridge
cp -a binaries/lib/lib* ../beagle-cupcake/out/target/product/beagleboard/root/lib
cp source/samples/utils/uninstall_bridge ../beagle-cupcake/out/target/product/beagleboard/root/dspbridge/

mkdir ../beagle-cupcake/out/target/product/beagleboard/root/dspbridge
cp source/samples/utils/install_bridge ../beagle-cupcake/out/target/product/beagleboard/root/dspbridge/

cd ..

2.Install TI OpenMAX IL

Download tiopenmax-0.4.1

cd tiopenmax-0.4.1

Append below to Makefile

export OMXROOT=$(shell /bin/pwd)
export CROSS=arm-none-linux-gnueabi-
export PKGDIR=$(shell /bin/pwd)
export PREFIX=$(shell /bin/pwd)
#export TARGETDIR=${PREFIX}/rootfs
export TARGETDIR=${HOME}/OMAP3530/beagle-cupcake/out/target/product/beagleboard/root
export BRIDGEINCLUDEDIR=${HOME}/OMAP3530/ti_dspbridge/source/mpu_api/inc
export BRIDGELIBDIR=${TARGETDIR}/lib

mkdir ../beagle-cupcake/out/target/product/beagleboard/root/omx
make avplay.clobber avplay

cp bin/cexec.out ../beagle-cupcake/out/target/product/beagleboard/root/dspbridge

mkdir ../beagle-cupcake/out/target/product/beagleboard/root/share
cp -a share/* ../beagle-cupcake/out/target/product/beagleboard/root/share/

3.Install DSP Binary

Download Android_DSP_Binaries-1.2-Linux-x86-Install.tar.gz

/**********/

Install DSP Binaries to ${HOME}/OMAP3530/beagle-cupcake/out/target/product/beagleboard/root/lib/dsp

gigijoe@gigijoe-laptop:~/OMAP3530/beagle-cupcake/out/target/product/beagleboard/root/lib/dsp$ ls
baseimage.dof       h264vdec_sn.dll64P  m4venc_sn.dll64P       postprocessor.dll64P          usn.dll64P
conversions.dll64P  jpegdec_sn.dll64P   mp4vdec_sn.dll64P      postprocessor_dualout.dll64P  vpp_sn.dll64P
dctn_dyn.dll64P     jpegenc_sn.dll64P   mpeg4aacdec_sn.dll64P  ringio.dll64P

/**********/




2009年9月23日 星期三

OMAP3530 MINI V3 + 0xdroid

ICETEK OMAP3530 MINI V3號稱硬體跟beagle board相容.
由於mini board有512MB nand flash & DM9000 ethernet所以捨棄了beagle board.
但風險就是萬一硬體有不相容的地方就得自己搞了

http://code.google.com/p/beagleboard/wiki/BeagleSoftCompile

1.OMAP3530 boot
Boot對Embedded System是一件大事,就像生命的起源一般.
OMAP3530可以從nand flash or SD card boot,由x-loader開始.
x-loader負責初始化CUP,包含memory & nand flash,之後會載入並執行u-boot.

預設供電後由nand flash載入x-loader.
按住user button + reset button就會由SD card載入x-loader.

2.Compile x-loader

修改xloader/include/configs/omap3530Mini.h

/* NAND is partitioned:
 * 0x00000000 - 0x0007FFFF  Booting Image
 * 0x00080000 - 0x0025FFFF  U-Boot Image
 * 0x00260000 - 0x0027FFFF  U-Boot Env Data (X-loader doesn't care)
 * 0x00280000 - 0x0067FFFF  Kernel Image
 * 0x00680000 - 0x08000000  depends on application
 */
#define NAND_UBOOT_START    0x0080000 /* Leaving first 4 blocks for x-load */
#define NAND_UBOOT_END        0x0260000 /* Giving a space of 2 blocks = 256KB */
#define NAND_BLOCK_SIZE        0x20000

make
./signGP x-load.bin
mv x-load.bin.ift MLO

Build x-loader for nand boot

http://elinux.org/BeagleBoardNAND

Modify include/configs/omap3530mini.h

Disable CONFIG_MMC
//#define CONFIG_MMC 1

make
./signGP x-load.bin
Copy x-load.bin.ift to nand

3.Format SD Card

http://elinux.org/BeagleBoardBeginners

有一些細節要注意,就不再贅述
將MLO copy 到SD card FAT partition (FAT partition一定要是乾淨的)
將x-load.bin.ift copy到 FAT partition

4.Install pre-built 0xdroid images

複製uImage / 0xkernel-beagle.bin / android-beagle.ubi 到SD card FAT parition
退出SD card
Boot from SD card
進入u-boot command

由SD card更新nand flash上的檔案

Refresh x-load.bin.ift

OMAP3 MiniBoard # mmcinit
OMAP3 MiniBoard # fatload mmc 0 ${loadaddr} x-load.bin.ift
reading x-load.bin.ift

11332 bytes read
OMAP3 MiniBoard # nand unlock
Usage:
nand - NAND sub-system

OMAP3 MiniBoard # nand erase 0 40000

NAND erase: device 0 offset 0x0, size 0x40000
Erasing at 0x20000 -- 100% complete.
OK
OMAP3 MiniBoard # nandecc hw
HW ECC selected
OMAP3 MiniBoard # nand write ${loadaddr} 0 40000

NAND write: device 0 offset 0x0, size 0x40000
 262144 bytes written: OK
OMAP3 MiniBoard # nand lock
Usage:
nand - NAND sub-system

Refresh u-boot

OMAP3 MiniBoard # mmcinit
OMAP3 MiniBoard # fatload mmc 0 ${loadaddr} u-boot.bin
reading u-boot.bin

275904 bytes read
OMAP3 MiniBoard # nand erase 80000 1e0000

NAND erase: device 0 offset 0x80000, size 0x1e0000
Erasing at 0x140000 -- 100% complete.
OK
OMAP3 MiniBoard # nand write ${loadaddr} 80000 1e0000

NAND write: device 0 offset 0x80000, size 0x1e0000
 917504 bytes written: OK
OMAP3 MiniBoard #

Refresh uImage.bin

OMAP3 Miniboard # mmcinit
OMAP3 Miniboard # fatload mmc 0 ${loadaddr} uImage-beagle.bin
reading uImage-beagle.bin

2140524 bytes read
OMAP3 Miniboard # nand erase 280000 400000

NAND erase: device 0 offset 0x280000, size 0x400000
Erasing at 0x660000 -- 100% complete.
OK
OMAP3 Miniboard # nand write ${loadaddr} 280000 400000

NAND write: device 0 offset 0x280000, size 0x400000
 4194304 bytes written: OK

5.取出SD card, reboot to install 0xdroid automaticlly.
完成後reboot

6.u-boot environment variable

setenv ubifsargs 'setenv bootargs console=${console} init=/init omapdss.def_disp=dvi omapfb.mode=dvi:1280x1024MR-24@60 root=ubi0:rootfs ubi.mtd=4 rw rootfstype=ubifs'

setenv nandboot 'echo Booting from nand ...; run ubifsargs; nand read ${loadaddr} 280000 400000; bootm ${loadaddr}'

7.0xdroid works

Texas Instruments X-Loader 1.4.2 (Sep 24 2009 - 17:05:57)
MiniBoard V2.0: Run Xloader from SD card
Loading u-boot.bin from nand


U-Boot 2009.08-00217-g30d7aae-dirty ( 9月 24 2009 - 20:23:31)

OMAP3530-GP ES2.1, CPU-OPP2 L3-165MHz
OMAP3 Beagle board + LPDDR/NAND
DRAM:  256 MB
NAND:  512 MiB
In:    serial
Out:   serial
Err:   serial
Beagle Board rev C
Die ID #4b9a00020000000004031c1307010007
Hit any key to stop autoboot:  0
Unknown command 'mmcinit' - try 'help'
Booting from nand ...

NAND read: device 0 offset 0x280000, size 0x400000
 4194304 bytes read: OK
## Booting kernel from Legacy Image at 80200000 ...
   Image Name:   Linux-2.6.29-omap1-g327a826
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    2165760 Bytes =  2.1 MB
   Load Address: 80008000
   Entry Point:  80008000
   Verifying Checksum ... OK
   Loading Kernel Image ... OK
OK

Starting kernel ...