硬件资源

    片选,使用了nCS2,根据LPC3250的存储器MAP:
Four static memory banks, 16 MB each:
EMC_CS0    0xE000 0000 ~ 0xE0FF FFFF
EMC_CS1    0xE100 0000 ~ 0xE1FF FFFF
EMC_CS2    0xE200 0000 ~ 0xE2FF FFFF
EMC_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_DEVICE
607     },
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_DEVICE
613     }
614
615 };
 
    然后使用io_p2v将CAN的寄存器从物理地址转换为虚拟地址:
106 #define SJA_BASE       EMC_CS2_BASE    //0xE2000000
107 #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} macros
230   */
231  #ifndef ioread8
232  #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; })
235
236  #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     //映射IO
239   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;
344
345      sic2_er = io_p2v(SIC2_BASE + INTC_MASK);
346      sic2_rsr = io_p2v(SIC2_BASE + INTC_RAW_STAT);
347
348      IntEntry();
349      wake_up_interruptible(&can_wait);
350
351      __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;
221
222      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     );
 
 
posted on 2012-04-28 15:12  风行雪舞  阅读(704)  评论(0编辑  收藏  举报
无觅相关文章插件,快速提升流量