SJA1000 CAN驅動

來源:互聯網
上載者:User
硬體資源    片選,使用了nCS2,根據LPC3250的儲存空間MAP:Four static memory banks, 16 MB each:EMC_CS0    0xE000 0000 ~ 0xE0FF FFFFEMC_CS1    0xE100 0000 ~ 0xE1FF FFFFEMC_CS2    0xE200 0000 ~ 0xE2FF FFFFEMC_CS3    0xE300 0000 ~ 0xE3FF FFFF    電路上ALE和我CLE的位移地址分別是0x02和0x01,但是由於LPC3250比較特殊,物理匯流排被配置為16位還是32位,地址線A0總是有效,因而寫往匯流排的地址需要進行處理。CAN所在匯流排被配置為16位寬度,所以實際地址應該將物理位移地址左移1位,於是得到:    ALE —— 0xE200 0004    CLE —— 0xE200 0002    中斷 —— GPIO_01   中斷處理   GPIO_01可以作為中斷輸入引腳,並且可選擇喚醒CPU。   喚醒CPU的寄存器:START_ER_INT[1],0——禁能,1——使能。     中斷使能寄存器:   SIC2_EN[1],0——禁止,1——使能;    中斷極性寄存器:   SIC2_APR[1],0——低電平或者下降沿,1——高電平或者上升沿;    中斷類型寄存器:   SIC2_ATR[1],0——電平觸發,1——邊沿觸發;    IO方向寄存器:     P2_DIR_SET[26],0——輸入,1——輸出;        輸入狀態寄存器:   P3_INP_STATE[11];    輸出寄存器:         P3_OUTP_SET[26];    SJA1000推薦用電平觸發中斷。 匯流排配置:    如下是在ADS中的測試代碼:     SJA1000使用的是Bank2,匯流排配置如下:    #define WAITWEN2        0x02                                            /* 配置EMCStaticWaitWen2       */   #define WAITOEN2        0x02                                            /* 配置EMCStaticWaitOen2       */    #define WAITRD2         0x1F                                            /* 配置EMCStaticWaitRd2       */   #define WAITPAGE2       0x0F                                            /* 配置EMCStaticWaitPage2     */   #define WAITWR2         0x1F                                            /* 配置EMCStaticWaitWr2       */   #define WAITTURN2       0x0F                                            /* 配置EMCStaticWaitTurn2     */      #define BCFG_16DEF     0x00000001                                      /* 16Bit Bus                 */          /*          *                  | 頁模式    |  片選極性  |位元組定位狀態|  延長等待  |  寫緩衝區  |   防寫保護   |          *                  |   PM      |    PC      |    PB      |     EW     |     B      |     P     |          *                 |0:禁能1:使能| 0:低 1:高  |            |0:禁能1:使能|0:禁能1:使能|0:禁能1:使能|          */     #define BCFG0           ( (0x00 < <03) | (0x00 < <06) | (0x01 < <07) | (0x00 < <8) | (0x00 < <19) | (0x00 < <20) )        #define BCFG1           ( (0x00 < <03) | (0x00 < <06) | (0x01 < <07) | (0x00 < <8) | (0x00 < <19) | (0x00 < <20) )     #define BCFG2           ( (0x00 < <03) | (0x00 < <06) | (0x01 < <07) | (0x00 < <8) | (0x00 < <19) | (0x00 < <20) )     #define BCFG3           ( (0x00 < <03) | (0x00 < <06) | (0x01 < <07) | (0x00 < <8) | (0x00 < <19) | (0x00 < <20) )     #define STATICCFG2     ( BCFG_16DEF | BCFG2 )                      EMCStaticConfig2   = STATICCFG2;     EMCStaticWaitWen2 = WAITWEN2;     EMCStaticWaitOen2 = WAITOEN2;     EMCStaticWaitRd2  = WAITRD2;     EMCStaticWaitPage2= WAITPAGE2;     EMCStaticWaitWr2  = WAITWR2;     EMCStaticWaitTurn2 = WAITTURN2;       Linux中匯流排配置的實現: 229     /* set BANK2's EMC REGs */230     __raw_writel(STATICCFG2, EMCStaticConfig2(LPC32XX_EMC_BASE));231     __raw_writel(WAITWEN2,   EMCStaticWaitWen2(LPC32XX_EMC_BASE));232     __raw_writel(WAITOEN2,   EMCStaticWaitOen2(LPC32XX_EMC_BASE));233     __raw_writel(WAITRD2,   EMCStaticWaitRd2(LPC32XX_EMC_BASE));234     __raw_writel(WAITPAGE2, EMCStaticWaitPage2(LPC32XX_EMC_BASE));235     __raw_writel(WAITWR2,   EMCStaticWaitWr2(LPC32XX_EMC_BASE));236     __raw_writel(WAITTURN2, EMCStaticWaitTurn2(LPC32XX_EMC_BASE));  寄存器訪問    靜態映射   首先需要在系統核心中對CAN所在BANK進行IO映射,因為LPC32XX預設僅僅對片內外設的IO空間進行了IO映射:598 /*599  * By Chenxibing(Abing)600  */601 static struct map_desc smartarm3250_io_desc[] __initdata = {602     {   /* nCS2, CAN SJA1000 */603         .virtual  = io_p2v(EMC_CS2_BASE),604         .pfn      = __phys_to_pfn(EMC_CS2_BASE),605         .length   = SZ_1M,606         .type     = MT_DEVICE607     },608     {   /* nCS1, CF Card */609         .virtual  = io_p2v(EMC_CS1_BASE),610         .pfn      = __phys_to_pfn(EMC_CS1_BASE),611         .length   = SZ_1M,612         .type     = MT_DEVICE613     }614615 };     然後使用io_p2v將CAN的寄存器從物理地址轉換為虛擬位址:106 #define SJA_BASE       EMC_CS2_BASE    //0xE2000000107 #define SJA1000_BASE   io_p2v(SJA_BASE)108 #define SJA1000_DATA   (SJA1000_BASE + 0x02)109 #define SJA1000_ADDR   (SJA1000_BASE + 0x04)    最後使用__raw_read/__raw_write函數組進行訪問:259         __raw_writeb(0x09, SJA1000_ADDR);260         __raw_writeb(1<<i, SJA1000_DATA);261         __raw_writeb(0x09, SJA1000_ADDR);     沒有經過靜態IO映射的空間是不能使用io_p2v進行物理虛擬位址轉換的。   至於寄存器訪問函數iowrite、__raw_writel等,在新版核心已經改到arch/arm/include/asm/io.h函數中定義了,如:  49  #define __raw_writeb(v,a)       (__chk_io_ptr(a), *(volatile unsigned char __force  *)(a) = (v))  50  #define __raw_writew(v,a)       (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))  51  #define __raw_writel(v,a)       (__chk_io_ptr(a), *(volatile unsigned int __force   *)(a) = (v))  52   53  #define __raw_readb(a)          (__chk_io_ptr(a), *(volatile unsigned char __force  *)(a))  54  #define __raw_readw(a)          (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))  55  #define __raw_readl(a)          (__chk_io_ptr(a), *(volatile unsigned int __force   *)(a)) 228  /*229   * io{read,write}{8,16,32} macros230   */231  #ifndef ioread8232  #define ioread8(p)      ({ unsigned int __v = __raw_readb(p); __v; })233  #define ioread16(p)     ({ unsigned int __v = le16_to_cpu((__force __le16)__raw_readw(p)); __v; })234  #define ioread32(p)     ({ unsigned int __v = le32_to_cpu((__force __le32)__raw_readl(p)); __v; })235236  #define iowrite8(v,p)   __raw_writeb(v, p)237  #define iowrite16(v,p)  __raw_writew((__force __u16)cpu_to_le16(v), p)238  #define iowrite32(v,p)  __raw_writel((__force __u32)cpu_to_le32(v), p)    動態IO映射   如果在系統中沒有對CAN所在BANK進行靜態IO映射,就不能使用io_p2v進行虛擬位址轉換,必須使用ioremap進行動態IO映射。當然,經過靜態IO映射的物理空間也可以使用ioremap進行動態IO映射: 98 #define SJA_ALE_PADR 0xE2000004     //SJA1000鎖存器連接埠物理地址99 #define SJA_DAT_PADR 0xE2000002     //SJA1000資料連接埠物理地址100 #define SJA_SRC_LEN  0x02           //SJA1000資料長度,1位元組  45 void *sja1000_ale;46 void *sja1000_dat; 238     //映射IO239   sja1000_dat = ioremap(SJA_DAT_PADR, SJA_SRC_LEN);240   sja1000_ale = ioremap(SJA_ALE_PADR, SJA_SRC_LEN);     然後使用ioread系列函數進行訪問:245         iowrite8(0x09,sja1000_ale);246         iowrite8(1<<i,sja1000_dat);247         iowrite8(0x09,sja1000_ale);  問題和解決   問題   目前驅動能夠進行正確的發送,但是接收程式僅僅能夠響應一次,然後就再也不響應了。很有可能是中斷沒有處理好,是不是中斷標誌沒有清除,無法再次進入中斷?    那LPC3250的IO中斷該如何處理?    解決    解決辦法:在中斷服務程式中清除GPIO_01的中斷標誌後,重新再次使能GPIO_01中斷。340 static irqreturn_t can_interrupt(int irq , void* dev_id, struct pt_regs *regs)341 {342      unsigned int *sic2_rsr;343      unsigned int *sic2_er;344345      sic2_er = io_p2v(SIC2_BASE + INTC_MASK);346      sic2_rsr = io_p2v(SIC2_BASE + INTC_RAW_STAT);347348      IntEntry();349      wake_up_interruptible(&can_wait);350351      __raw_writel((1<<1), sic2_rsr); //clear interrupt flag                       //清除GPIO_01的中斷標誌352      __raw_writel((1<<1), sic2_er);  //re-enable GPIO_01 interrupt        //重新使能GPIO_01的中斷353      return IRQ_HANDLED;354 }     另外,初始化函數中的使能GPIO_01中斷的代碼必不可少:217 int can_init(void)218 {219     int  i,result;220     int bak,tmp;221222      unsigned int *sic2_er;223      sic2_er = io_p2v(SIC2_BASE + INTC_MASK);224      __raw_writel((1<<1), sic2_er);                                                     //使能GPIO_01的中斷         ......       }  簡單測試   在測試CAN接收的時候,上位機幀間隔時間不能為0,否則會丟幀,可以設定一個比較小的時間間隔,如為10m。 2009-05-21   在新的班子上遇到了發送測試程式基本沒有問題,但是發送程式關閉之後CANTest軟體還是會收到資料幀,不知道什麼原因。   另外問題較大的就是接收程式,偶爾能夠接受正確,很多情況下接收到的資料都是錯的,幀ID一直都是錯的。2009-05-22    除ID問題之外的其它問題是硬體問題,換了另外一塊板子沒有問題了。 申請中斷必須使用IRQF_DISABLED|IRQF_TRIGGER_FALLING FLAGS:rc = request_irq(b->irq, (handler_t)interrupt_handler, IRQF_DISABLED|IRQF_TRIGGER_FALLING, b->name, b     );  

聯繫我們

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

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

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.