www.mikrocontroller.net

Forum: PC-Programmierung Openwrt: SPI über GPIOs


Important announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: ALrK3uMW (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hi,

wie kriege ich den SPI-Bus unter dem aktuellen Openwrt (backfire) mit 
GPIOs zum Laufen? Wo finde ich Einstellungen zu den verwendeten GPIOs, 
oder eine zugehörige Doku?

Openwrt kompiliert, kmod-spi-bitbang, kmod-spi-dev, kmod-spi-gpio und 
spidev-test sind fest eingebaut, scheinen aber kein device zu erzeugen.

Hardware: Edimax BR-6104KP

VG

Autor: MBS (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Weiß nicht, ob es noch aktuell ist. Die Infos findet man im Quellcode 
(spi_gpio.c). Gibt also 2 Möglichkeiten:
1.: entsprechende platform_data in deiner 
arch/mips/adm5120/edimax/br-6104kp.c definieren. Näheres dazu beschreibt 
auch die Datei include/linux/spi/spi_gpio.h. Komplettes Image neu bauen.
2.: in spi_gpio.c gleich folgende Sachen auskommentieren und auf deine 
GPIO-Nummern ändern:
 *    #define DRIVER_NAME  "myboard_spi2"
 *    #define  SPI_MISO_GPIO  119
 *    #define  SPI_MOSI_GPIO  120
 *    #define  SPI_SCK_GPIO  121
 *    #define  SPI_N_CHIPSEL  4
 *    #include "spi_gpio.c"
Also das abschließende */ entsprechend vor die erste Zeile hier 
verschieben und die Zeichen vor der Raute entfernen. Dann müsste man 
eigentlich nur noch diese Datei kompilieren.

Autor: Alex E. (alex_0xff)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hallo ALrK3uMW,
  bist du schon weiter... ich versuche nun seit ein paar Tagen SPI am 
WGT634 zum laufen zu bringen. Und habe zur Zeit die "selbe" Frage / bin 
auf dem selben Stand wie du.

-alex

Autor: Mountain (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hallo,

ich habe ein CAN-Bus Controller mit einem BR-6104K (SoC ADM5120)
verbunden. Über SPI kann ich den Controller initialisieren:
BusyBox v1.19.3 (2012-04-05 12:15:53 CEST) built-in shell (ash)
Enter 'help' for a list of built-in commands.

  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
 ATTITUDE ADJUSTMENT (bleeding edge, r30857) ----------

root@OpenWrt:/# uname -a
Linux OpenWrt 3.1.10 #6 Thu Apr 5 16:39:22 CEST 2012 mips GNU/Linux

root@OpenWrt:/# insmod mcp251x
root@OpenWrt:/# cat /sys/kernel/debug/gpio 
GPIOs 0-3, adm5120 gpio0:
 gpio-2   (MCP251x CAN INT     ) in  hi

GPIOs 8-22, adm5120 gpio1:
 gpio-17  (spi_gpio.1          ) in  lo
 gpio-18  (spi_gpio.1          ) out lo
 gpio-20  (spi_gpio.1          ) out lo
 gpio-21  (spi1.0              ) out hi
root@OpenWrt:/# insmod mcp251x
[  368.736000] mcp251x spi1.0: probed

root@OpenWrt:/# ip link set can0 type can bitrate 125000 loopback on

root@OpenWrt:/# ifconfig can0 up
[  402.324000] mcp251x spi1.0: CNF: 0x03 0xb5 0x01

root@OpenWrt:/# ip -details link show can0
10: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN qlen 10
    link/can 
    can <LOOPBACK> state ERROR-ACTIVE restart-ms 0 
    bitrate 125000 sample-point 0.875 
    tq 500 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1
    mcp251x: tseg1 3..16 tseg2 2..8 sjw 1..4 brp 1..64 brp-inc 1
    clock 8000000

root@OpenWrt:/# cat /sys/kernel/debug/gpio 
GPIOs 0-3, adm5120 gpio0:
 gpio-2   (MCP251x CAN INT     ) in  hi

GPIOs 8-22, adm5120 gpio1:
 gpio-17  (spi_gpio.1          ) in  lo
 gpio-18  (spi_gpio.1          ) out lo
 gpio-20  (spi_gpio.1          ) out lo
 gpio-21  (spi1.0              ) out hi

root@OpenWrt:/# cat /proc/interrupts 
           CPU0       
  2:          0      MIPS  cascade [INTC]
  7:      33933      MIPS  timer
  9:       2477      INTC  uart-pl010
 12:          0      INTC  mcp251x
 17:        614      INTC  eth0, eth1
ERR:          0

root@OpenWrt:/# dmesg | tail -5
[  368.732000] mcp251x spi1.0: CANSTAT 0x80 CANCTRL 0x07
[  368.736000] mcp251x spi1.0: probed
[  402.308000] mcp251x spi1.0:  INTC_REG_IRQ_ENABLE = 0x212
[  402.308000] mcp251x spi1.0:  GPIO2 IRQ initialized
[  402.324000] mcp251x spi1.0: CNF: 0x03 0xb5 0x01
Sieht soweit gut aus, aber es wird kein IRQ ausgelöst, wenn ich eine CAN
Nachricht sende:
root@OpenWrt:/# cansend can0 123#DEADBEEF
root@OpenWrt:/# cat /proc/interrupts 
           CPU0       
  2:          0      MIPS  cascade [INTC]
  7:      34334      MIPS  timer
  9:       2845      INTC  uart-pl010
 12:          0      INTC  mcp251x
 17:        669      INTC  eth0, eth1
ERR:          0

root@OpenWrt:/# cat /sys/kernel/debug/gpio 
GPIOs 0-3, adm5120 gpio0:
 gpio-2   (MCP251x CAN INT     ) in  lo

GPIOs 8-22, adm5120 gpio1:
 gpio-17  (spi_gpio.1          ) in  lo
 gpio-18  (spi_gpio.1          ) out lo
 gpio-20  (spi_gpio.1          ) out lo
 gpio-21  (spi1.0              ) out hi
GPIO2 ist im Status "in lo" und sollte einen IRQ auslösen.

Ich habe zuerst versucht, den IRQ Initialisierung in der Board
Definition unterzubringen - ohne Erfolg. Daher habe ich
versuchsweise dies nun in den CAN Controller Treiber
eingebaut (mcp251x.c):
 static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
{
        struct mcp251x_priv *priv = dev_id;
        struct spi_device *spi = priv->spi;
        struct net_device *net = priv->net;
        unsigned long flags;
        unsigned int intc_reg_int_level;

        mutex_lock(&priv->mcp_lock);
        dev_dbg(&spi->dev, " in mcp251x_can_ist ...\n");

        // ADM5120 IRQs can only be level, not edge so we are going
        //   switch level and only use high to low trigger
        spin_lock_irqsave(&level_register_lock, flags);
        {
                intc_reg_int_level = BIT(4) ^ intc_read_reg(INTC_REG_INT_LEVEL);
                intc_write_reg(INTC_REG_INT_LEVEL, intc_reg_int_level);
        }
        spin_unlock_irqrestore(&level_register_lock, flags);
        // we only need falling edge
        if (BIT(4) & intc_reg_int_level)
                return(IRQ_HANDLED);
        while (!priv->force_quit) {
        ...
        }
}

...
static int mcp251x_open(struct net_device *net)
{
        struct mcp251x_priv *priv = netdev_priv(net);
        struct spi_device *spi = priv->spi;
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
        int ret;
        unsigned int ire;
        unsigned long flags;

        ret = open_candev(net);
        if (ret) {
                dev_err(&spi->dev, "unable to set initial baudrate!\n");
                return ret;
        }

        mutex_lock(&priv->mcp_lock);
        if (pdata->transceiver_enable)
                pdata->transceiver_enable(1);

        priv->force_quit = 0;
        priv->tx_skb = NULL;
        priv->tx_len = 0;

        ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,
                  pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING,
                  DEVICE_NAME, priv);
        if (ret) {
                dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
                if (pdata->transceiver_enable)
                        pdata->transceiver_enable(0);
                close_candev(net);
                goto open_unlock;
        } else {
                spin_lock_irqsave(&level_register_lock, flags);
                // enable interrupt on GPIO 2
                // pp37 ADM5120 manual
                ire = intc_read_reg(INTC_REG_IRQ_ENABLE);
                ire |= BIT(4) | BIT(9); // II0E | SWIE
                intc_write_reg(INTC_REG_IRQ_ENABLE, ire);
                dev_dbg(&spi->dev, " INTC_REG_IRQ_ENABLE = 0x%x\n", ire);

                // Enable CSX0/INTX0 processing as described on pp131 of ADM5120 manual
                SW_WRITE_REG(SWITCH_REG_GPIO_CONF2, BIT(4));
                // sets GPIO4 and 2 as active low
                // pp41/42 of ADM5120 manual.
                intc_write_reg(INTC_REG_INT_LEVEL, BIT(4) | intc_read_reg(INTC_REG_INT_LEVEL));
                spin_unlock_irqrestore(&level_register_lock, flags);
                dev_dbg(&spi->dev, " GPIO2 IRQ initialized\n");
        }
...
}
Ein simples GPIO2 Modul hingegen funktioniert:
http://www.omnima.co.uk/forums/lofiversion/index.p...
root@OpenWrt:/# insmod gpio2
[  130.380000] INTC_REG_IRQ_ENABLE = 0x212
[  130.384000] GPIO_RESET: requesting IRQ -> fine
root@OpenWrt:/# [  133.820000] pressed
[  134.040000] released
[  135.196000] pressed
[  135.412000] released
[  136.076000] pressed
[  136.220000] released

root@OpenWrt:/# cat /proc/interrupts 
           CPU0       
  2:          0      MIPS  cascade [INTC]
  7:      28970      MIPS  timer
  9:        180      INTC  uart-pl010
 12:          6      INTC  gpio_reset
 17:        334      INTC  eth0, eth1
ERR:          0

Hier die Board Initialisierung:
nizza ~/projekte/openwrt/trunk_3.1 (svn)-[trunk:30857] % cat build_dir/linux-adm5120_router_le/linux-3.1.10/arch/mips/adm5120/edimax/br-61xx.c
/*
 *  Edimax BR-61xx support
 *
 *  Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
 *
 *  This program is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License version 2 as published
 *  by the Free Software Foundation.
 *
 */

#include "br-61xx.h"

#include <prom/admboot.h>
#include <linux/spi/spi_gpio.h>
#include <linux/can/platform/mcp251x.h>

#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>

Hat jemand eine Idee, warum der IRQ im MCP251x Modul nicht ausgelöst
wird ?

Autor: Mountain (Gast)
Datum:
Angehängte Dateien:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hoppla,

die Board Definitions-Datei wurde abgeschnitten

Autor: Mountain (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
:-) habs zum Fliegen bekommen:
root@OpenWrt:~# cansend can0 666#DEADBEEF

root@OpenWrt:~# candump any,0:0,#FFFFFFFF
  can0  666  [4] DE AD BE EF
  can0  666  [4] DE AD BE EF

root@OpenWrt:~# ip -s -details link show can0
9: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN
qlen 10
    link/can
    can <LOOPBACK> state ERROR-ACTIVE restart-ms 0
    bitrate 125000 sample-point 0.875
    tq 500 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1
    mcp251x: tseg1 3..16 tseg2 2..8 sjw 1..4 brp 1..64 brp-inc 1
    clock 8000000
    re-started bus-errors arbit-lost error-warn error-pass bus-off
    0          0          0          0          0          0
    RX: bytes  packets  errors  dropped overrun mcast
    48         10       0       0       0       0
    TX: bytes  packets  errors  dropped carrier collsns
    48         10       0       0       0       0

root@OpenWrt:~# cat /sys/kernel/debug/gpio
GPIOs 0-3, adm5120 gpio0:
 gpio-2   (MCP251x /INT        ) in  hi

GPIOs 8-22, adm5120 gpio1:
 gpio-17  (spi_gpio.1          ) in  lo
 gpio-18  (spi_gpio.1          ) out lo
 gpio-20  (spi_gpio.1          ) out lo
 gpio-21  (spi1.0              ) out hi

root@OpenWrt:~# cat /proc/interrupts
           CPU0
  2:          0      MIPS  cascade [INTC]
  7:     553160      MIPS  timer
  9:       1482      INTC  uart-pl010
 12:         20      INTC  mcp251x
 17:     119245      INTC  eth0, eth1
ERR:          0
--- mcp251x.c   2012-01-18 16:33:18.000000000 +0100
+++ mcp251x_funkt2.c    2012-04-18 15:33:49.926203717 +0200
@@ -76,6 +76,15 @@
 #include <linux/spi/spi.h>
 #include <linux/uaccess.h>

+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <adm5120_defs.h>
+#include <asm/mipsregs.h>
+#include <asm/mach-adm5120/adm5120_info.h>
+#include <asm/mach-adm5120/adm5120_defs.h>
+#include <asm/mach-adm5120/adm5120_switch.h>
+
 /* SPI interface instruction set */
 #define INSTRUCTION_WRITE      0x02
 #define INSTRUCTION_READ       0x03
@@ -210,6 +219,21 @@

 #define DEVICE_NAME "mcp251x"

+static inline void intc_write_reg(unsigned int reg, u32 val)
+{
+        void __iomem *base = (void __iomem *)KSEG1ADDR(ADM5120_INTC_BASE);
+
+        __raw_writel(val, base + reg);
+}
+
+static inline u32 intc_read_reg(unsigned int reg)
+{
+        void __iomem *base = (void __iomem *)KSEG1ADDR(ADM5120_INTC_BASE);
+
+        return __raw_readl(base + reg);
+}
+
+
 static int mcp251x_enable_dma; /* Enable SPI DMA. Default: 0 (Off) */
 module_param(mcp251x_enable_dma, int, S_IRUGO);
 MODULE_PARM_DESC(mcp251x_enable_dma, "Enable SPI DMA. Default: 0 (Off)");
@@ -779,6 +803,39 @@
        mutex_unlock(&priv->mcp_lock);
 }

+static DEFINE_SPINLOCK(level_register_lock);
+
+
+static irqreturn_t mcp251x_can_hardirq(int irq, void *dev_id)
+{
+       struct mcp251x_priv *priv = dev_id;
+       struct spi_device *spi = priv->spi;
+       unsigned long flags;
+       unsigned int intc_reg_int_level;
+
+        // ADM5120 IRQs can only be level, not edge so we are going
+        //   switch level and only use high to low trigger
+        spin_lock_irqsave(&level_register_lock, flags);
+        intc_reg_int_level = intc_read_reg(INTC_REG_INT_LEVEL) ^ BIT(4);
+        intc_write_reg(INTC_REG_INT_LEVEL, intc_reg_int_level);
+       dev_info(&spi->dev, " mcp251x INT level 0x%X \n",intc_reg_int_level);
+
+        // we ignore raising edge - we have already xored
+        // if (intc_reg_int_level && BIT(4))
+       if (intc_reg_int_level &= 0x10)
+       {
+               dev_info(&spi->dev, "  mcp251x INT high -> IRQ_HANDLED\n");
+               spin_unlock_irqrestore(&level_register_lock, flags);
+               return IRQ_HANDLED;
+       } else {
+               dev_info(&spi->dev, "  mcp251x INT low  -> IRQ_WAKE_THREAD\n");
+               spin_unlock_irqrestore(&level_register_lock, flags);
+               return IRQ_WAKE_THREAD;
+       }
+}
+
+
+
 static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
 {
        struct mcp251x_priv *priv = dev_id;
@@ -786,6 +843,8 @@
        struct net_device *net = priv->net;

        mutex_lock(&priv->mcp_lock);
+       dev_info(&spi->dev, " in mcp251x_can_ist ...\n");
+
        while (!priv->force_quit) {
                enum can_state new_state;
                u8 intf, eflag;
@@ -909,12 +968,15 @@
        return IRQ_HANDLED;
 }

+
 static int mcp251x_open(struct net_device *net)
 {
        struct mcp251x_priv *priv = netdev_priv(net);
        struct spi_device *spi = priv->spi;
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
        int ret;
+       unsigned int ire;
+       unsigned long flags;

        ret = open_candev(net);
        if (ret) {
@@ -930,8 +992,9 @@
        priv->tx_skb = NULL;
        priv->tx_len = 0;

-       ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,
-                 pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING,
+       ret = request_threaded_irq(spi->irq, mcp251x_can_hardirq, mcp251x_can_ist,
+                 // pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING,
+                 pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_NONE,
                  DEVICE_NAME, priv);
        if (ret) {
                dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
@@ -939,6 +1002,24 @@
                        pdata->transceiver_enable(0);
                close_candev(net);
                goto open_unlock;
+       } else {
+               spin_lock_irqsave(&level_register_lock, flags);
+               // enable interrupt on GPIO 2
+               // pp37 ADM5120 manual
+              ire = intc_read_reg(INTC_REG_IRQ_ENABLE);
+              dev_info(&spi->dev, " INTC_REG_IRQ_ENABLE was = 0x%x\n", ire);
+              ire |= BIT(4) | BIT(9); // II0E | SWIE
+              // ire |= BIT(4); // II0E
+              intc_write_reg(INTC_REG_IRQ_ENABLE, ire);
+               dev_info(&spi->dev, " INTC_REG_IRQ_ENABLE now = 0x%x\n", ire);
+
+               // Enable CSX0/INTX0 processing as described on pp131 of ADM5120 manual
+               SW_WRITE_REG(SWITCH_REG_GPIO_CONF2, BIT(4));
+               // sets GPIO4 and 2 as active low
+                // pp41/42 of ADM5120 manual.
+               intc_write_reg(INTC_REG_INT_LEVEL, BIT(4) | intc_read_reg(INTC_REG_INT_LEVEL));
+               spin_unlock_irqrestore(&level_register_lock, flags);
+               dev_info(&spi->dev, " GPIO2 IRQ initialized: IRQ %d\n",spi->irq);
        }

        priv->wq = create_freezable_workqueue("mcp251x_wq");
Boardefintionsdatei br-61xx.c:
static struct mcp251x_platform_data mcp251x_info = {
        .oscillator_frequency    = 16000000,
        .board_specific_setup    = NULL,
        .irq_flags               = IRQF_TRIGGER_NONE,
        .power_enable            = NULL,
        .transceiver_enable      = NULL,
};

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel




Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder GIF-Format hochladen.
Siehe Bildformate
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net