linux的GPIO應用執行個體

來源:互聯網
上載者:User

需求描述:
主板上的狀態燈應能正確顯示ONU模組的連通狀態,即當光節點模組插到主板插槽之後,狀態燈應亮,移掉之後應滅。

 

硬體介面:
When SFP module is plugged in, the GPIO[2] status will change from high to low automatically.
When SW detect the change, just make the GPIO[18] to generate low signal (default is high), the ONU led will be lighted.

 

以上為接任務時的資訊。於是開始尋找解決問題的資訊。

GPIO的背景資訊?
即通用輸入輸出。把CPU針腳不通過匯流排或控制器直接連到外設上來進行控制的工業標準,比如連一個針腳到LED上,通過置一個bit的0/1就可以控制該LED得亮滅。

 

硬體的結構是怎樣的? 找schematics看一看:
1.右邊是CPU,左邊是pin腳連的東西,“>>”,“<<”表示輸入的方向

 

2.對應第一張圖,左邊是燈,右邊是連到的CPU的GPIO介面

 

3.對應第一張圖,左邊是CPU

 

軟體的方案?
有2種實現方法,一種是對GPIO[2]的電位進行輪詢,一種是讓GPIO[2]的電位變化產生中斷。
找到一個當前主板上的別人使用GPIO的例子,該例子的功能是:按下硬體重啟按鈕後會向CPU的GPIO針腳發使主板重啟。
此例子是用中斷實現的,準備也用中斷的方式來實現。

 

那麼,怎麼讓GPIO的[2]的電位變化產生中斷呢?

在現在的裝置上看看,列出已經被佔用的中斷號:
root:/proc# cat interrupts
           CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6
  0:        526         83         11          4       1423        164        355            MIPS  SMTC_IPI
  2:          0          0          0          0          0          40            MIPS  pmcmsp_tsmac
  3:          0          0          3          0          0          00            MIPS  pmcmsp_tsmac
  4:          0          0          0          0          0          00            MIPS  ehci_hcd:usb1, ehci_hcd:usb2
  5:          0          0          0          0         13          00            MIPS  pmcmsp_tsmac
  6:          0          0          0          0          0          00            MIPS  CIC cascade
  8:          0          0          0          0          0          00         MSP_CIC  Softreset button
 21:          0          0          0          0          0          00         MSP_CIC  PER cascade
 25:    5853436       1664         28          4          0          00         MSP_CIC  timer
 27:       3575          0          0          0          0          00         MSP_CIC  serial
 34:          0          0          0          0    5851128        138         30         MSP_CIC  VPE1 local timer
 46:          1          0          0          0          0          00         MSP_PER  pmcmsptwi

 

ERR:          1

 

現有按鈕的硬體是怎麼連的?

 

現有按鈕的中斷是怎麼實現的?

在中可以看到GPIO21針腳同時連到了按鈕與IRQ0(Interrupt Request 0)。查看代碼

subsys_initcall(msp_hwbutton_setup); //註冊子系統

 

 <br />static int __init msp_hwbutton_setup(void)<br />{<br />msp_hwbutton_register(&softreset_sw);<br />...<br />}</p><p>static struct hwbutton_interrupt softreset_sw = {<br />.name = "Softreset button",<br />.irq = MSP_INT_EXT0,<br />.eirq = 0,<br />.initial_state = HWBUTTON_HI,<br />.handle_hi = softreset_release, //按鈕鬆開時調用的函數<br />.handle_lo = softreset_push,//按鈕按下時調用的函數<br />.data = NULL,<br />};</p><p>/*<br /> * This struct describes a hardware button<br /> */<br />struct hwbutton_interrupt {<br />char *name;/* Name of button */<br />int irq;/* Actual LINUX IRQ */  //下面外部中斷所對應的系統中斷,定義在主板系統的lib中<br />int eirq;/* Extended IRQ number (0-7) */ //GPIO2分了一線到IRQ0<br />int initial_state;/* The "normal" state of the switch *///這個從硬體工程師處獲悉<br />void (*handle_hi)(void *);/* Handler: switch input has gone HI */ //handler做什麼從功能需求處獲悉<br />void (*handle_lo)(void *);/* Handler: switch input has gone LO */ //handler做什麼從功能需求處獲悉<br />void *data;/* Optional data to pass to handler */ //傳給handler的參數<br />};<br />

 

</p><p>#define MSP_MSB_BASE(0x18000000) /* MSbus address start */<br />#define MSP_CPUIF_BASE (MSP_MSB_BASE + 0xC00000) /* CPU interface registers */<br />/* Central Interrupt Controller Registers */<br />#define MSP_CIC_BASE (MSP_CPUIF_BASE + 0x8000) /* Central Interrupt registers */<br />#define CIC_EXT_CFG_REG regptr(MSP_CIC_BASE + 0x00) /* External interrupt configuration */<br />#define EXT_INT_EDGE(eirq)(1 << eirq)<br />#define CIC_EXT_SET_TRIGGER_LEVEL(reg, eirq)reg &= ~EXT_INT_EDGE(eirq)</p><p>static int msp_hwbutton_register(struct hwbutton_interrupt *hirq)<br />{<br />unsigned long cic_ext;</p><p>if (hirq->handle_hi == NULL || hirq->handle_lo == NULL)<br />return -EINVAL;</p><p>cic_ext = *CIC_EXT_CFG_REG;<br />CIC_EXT_SET_TRIGGER_LEVEL(cic_ext, hirq->eirq);<br />if (hirq->initial_state == HWBUTTON_HI)<br />CIC_EXT_SET_ACTIVE_LO(cic_ext, hirq->eirq);<br />else<br />CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);<br />*CIC_EXT_CFG_REG = cic_ext;</p><p>return request_irq(hirq->irq, hwbutton_handler, SA_INTERRUPT,<br />hirq->name, (void*)hirq);<br />//相當於 return request_irq( MSP_INT_EXT0, hwbutton_handler, SA_INTERRUPT,  “Softrest Button”, &<br />}</p><p>

 

<br />static irqreturn_t hwbutton_handler(int irq, void *data)<br />{<br />struct hwbutton_interrupt *hirq = (struct hwbutton_interrupt *)data;<br />unsigned long cic_ext = *CIC_EXT_CFG_REG;</p><p>if (irq != hirq->irq)<br />return IRQ_NONE;</p><p>if (CIC_EXT_IS_ACTIVE_HI(cic_ext, hirq->eirq)) {<br />/* Interrupt: pin is now HI */<br />CIC_EXT_SET_ACTIVE_LO(cic_ext, hirq->eirq);<br />hirq->handle_hi(hirq->data);<br />} else {<br />/* Interrupt: pin is now LO */<br />CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);<br />hirq->handle_lo(hirq->data);<br />}</p><p>/*<br /> * Invert the POLARITY of this level interrupt to ack the interrupt<br /> * Thus next state change will invoke the opposite message<br /> */<br />*CIC_EXT_CFG_REG = cic_ext;</p><p>return IRQ_HANDLED;<br />}<br />

 

現在的問題?
在此CPU中,GPIO0-15可以配置產生內部中斷,GPIO16及其以上不能通過配置產生;上面的例子用的是GPIO21,不能通過配置產生中斷,所以才要接到IRQ0
要實現的LED燈的GPIO的腳不像按鈕的例子,是沒有接到外部中斷的,但要求對LED的GPIO2進行電位判斷,在GPIO0-15的範圍內,是可以通過配置CPU來產生中斷的。
但是如何進行配置的文檔CPU廠商不提供,另外CPU的SDK現在也不支援對GPIO中斷進行配置。
小結:以能擷取的硬體與軟體,無法使GPIO2產生中斷。
那麼只能走輪詢的路了。代碼如下:

 static unsigned long e220_sfp_led_update_delay = 0;<br />static struct timer_list e220_sfp_led_update_timer;<br />static msp_gpio_data_t e220_sfp_old_status;</p><p>static void e220_sfp_led_update(unsigned long data)<br />{<br /> msp_gpio_data_t e220_sfp_current_status;</p><p> if (msp_gpio_pin_mode(MSP_GPIO_INPUT, 2) != 0) {<br /> printk(KERN_INFO "GPIO[2] input mode failed/n");<br /> }</p><p> if (msp_gpio_pin_mode(MSP_GPIO_OUTPUT, 18) != 0) {<br /> printk(KERN_INFO "GPIO[18] output mode failed/n");<br /> }</p><p> e220_sfp_current_status = msp_gpio_pin_get(2);</p><p> if (e220_sfp_current_status != e220_sfp_old_status) {</p><p> if(e220_sfp_current_status == MSP_GPIO_LO) {<br /> printk(KERN_INFO "SFP module inserted /n");<br /> msp_gpio_pin_lo(18);<br /> } else if (e220_sfp_current_status == MSP_GPIO_HI) {<br /> printk(KERN_INFO "SFP module removed /n");<br /> msp_gpio_pin_hi(18);<br /> } else {<br /> printk(KERN_INFO "SFP module state unknown /n");<br /> }</p><p> e220_sfp_old_status = e220_sfp_current_status;<br /> }</p><p> mod_timer(&e220_sfp_led_update_timer, jiffies + msecs_to_jiffies(1000));<br />}</p><p>static int e220_sfp_status_watch_start(void)<br />{<br /> e220_sfp_old_status = MSP_GPIO_NONE;<br /> setup_timer(&e220_sfp_led_update_timer, e220_sfp_led_update, NULL);</p><p> //expire timer immediately<br /> return mod_timer(&e220_sfp_led_update_timer, jiffies + 1);<br />}</p><p>

 

ok.

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

Tags Index: