⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcan_sja1000.c

📁 linux下的CAN BUS驱动代码。适合在arm平台使用。
💻 C
📖 第 1 页 / 共 2 页
字号:
  ULCONV localID;  u8 dreg;  int i;  fi = dlc = cf->can_dlc;  id = localID.ul = cf->can_id;  if (id & CAN_RTR_FLAG)    fi |= BUFFER_RTR;  if (id & CAN_EFF_FLAG) {    dreg  = TRANSMIT_FRAME_BASE + 5;    fi   |= BUFFER_EFF;    localID.ul   <<= 3;    #if defined(__LITTLE_ENDIAN)    dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, localID.uc[3]);    dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, localID.uc[2]);    dev->writereg(dev, TRANSMIT_FRAME_BASE + 3, localID.uc[1]);    dev->writereg(dev, TRANSMIT_FRAME_BASE + 4, localID.uc[0]);    #elif defined(__BIG_ENDIAN)    dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, localID.uc[0]);    dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, localID.uc[1]);    dev->writereg(dev, TRANSMIT_FRAME_BASE + 3, localID.uc[2]);    dev->writereg(dev, TRANSMIT_FRAME_BASE + 4, localID.uc[3]);    #else      #error  "Please fix the endianness defines in <asm/byteorder.h>"    #endif    // dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, (id & 0x1fe00000) >> (5 + 16));    // dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, (id & 0x001fe000) >> (5 + 8));    // dev->writereg(dev, TRANSMIT_FRAME_BASE + 3, (id & 0x00001fe0) >> 5);    // dev->writereg(dev, TRANSMIT_FRAME_BASE + 4, (id & 0x0000001f) << 3);  } else {    dreg = TRANSMIT_FRAME_BASE + 3;    localID.ul   <<= 21;    #if defined(__LITTLE_ENDIAN)    dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, localID.uc[3]);    dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, localID.uc[2]);    #elif defined(__BIG_ENDIAN)    dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, localID.uc[0]);    dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, localID.uc[1]);    #else      #error  "Please fix the endianness defines in <asm/byteorder.h>"    #endif    // dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, (id & 0x000007f8) >> 3);    // dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, (id & 0x00000007) << 5);  }  for (i = 0; i < dlc; i++) {    dev->writereg(dev, dreg++, cf->data[i]);  }  dev->writereg(dev, TRANSMIT_FRAME_BASE, fi);  // request a transmission  dev->writereg(dev, COMMAND, TRANSMISSION_REQUEST);  wmb();  // strange hack to get write stall managed  if ((dev->readreg(dev, CHIPSTATUS) & TRANS_COMPLETE_STATUS))  {    DPRINTK(KERN_ERR "%s: Transmission finished early..., minor=%d\n", DEVICE_NAME, dev->nMinor);  }  return 0;}//----------------------------------------------------------------------------// write CAN-data from FIFO to chip int sja1000_write(SJA1000_METHOD_ARGS){  int        result;  TPCANMsg   msg;  struct can_frame cf;  // DPRINTK(KERN_DEBUG "%s: sja1000_write() %d\n", DEVICE_NAME, dev->writeFifo.nStored);  SJA1000_LOCK_IRQSAVE(out_lock);  // get a fifo element and step forward  result = pcan_fifo_get(&dev->writeFifo, &msg);  SJA1000_WAKEUP_EMPTY();  SJA1000_UNLOCK_IRQRESTORE(out_lock);  if (result)    return result;  /* convert from old style FIFO message until FIFO supports new */  /* struct can_frame and error frames */  msg2frame(&cf, &msg);  sja1000_write_frame(dev, &cf);  return 0;}//----------------------------------------------------------------------------// handle a interrupt requestint sja1000_irqhandler_common(SJA1000_METHOD_ARGS){  int ret = SJA1000_IRQ_NONE;  u8 irqstatus;  int err;  u16 rwakeup = 0;  u16 wwakeup = 0;  int j = MAX_INTERRUPTS_PER_ENTRY;  struct can_frame ef;  memset(&ef, 0, sizeof(ef));  // DPRINTK(KERN_DEBUG "%s: sja1000_base_irqhandler|sja1000_irqhandler_rt()\n", DEVICE_NAME);  SJA1000_LOCK_IRQSAVE(sja_lock);  while ((j--) && (irqstatus = dev->readreg(dev, INTERRUPT_STATUS)))  {    // DPRINTK(KERN_DEBUG "%s: sja1000_[base_irqhandler|irqhandler_rt](0x%02x)\n", DEVICE_NAME, irqstatus);    dev->dwInterruptCounter++;    err = 0;    // quick hack to badly workaround write stall    // if ((irqstatus & TRANSMIT_INTERRUPT) || (!atomic_read(&dev->DataSendReady) && !pcan_fifo_empty(&dev->writeFifo) && (dev->readreg(dev, CHIPSTATUS) & TRANS_BUFFER_STATUS)))    if (irqstatus & TRANSMIT_INTERRUPT)     {      // handle transmission      if ((err = SJA1000_FUNCTION_CALL(sja1000_write)))      {        if (err == -ENODATA)          wwakeup++;        else        {          dev->nLastError = err;          dev->dwErrorCounter++;          dev->wCANStatus |= CAN_ERR_QXMTFULL; // fatal error!        }      }      dev->ucActivityState = ACTIVITY_XMIT; // reset to ACTIVITY_IDLE by cyclic timer    }    if (irqstatus & DATA_OVERRUN_INTERRUPT)    {      // handle data overrun      dev->wCANStatus |= CAN_ERR_OVERRUN;      ef.can_id  |= CAN_ERR_CRTL;      ef.data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;      rwakeup++;      dev->dwErrorCounter++;      dev->writereg(dev, COMMAND, CLEAR_DATA_OVERRUN);      wmb();      dev->ucActivityState = ACTIVITY_XMIT; // reset to ACTIVITY_IDLE by cyclic timer    }    if (irqstatus & RECEIVE_INTERRUPT)    {      // handle receiption      if ((err = SJA1000_FUNCTION_CALL(sja1000_read_frames)) < 0) /* put to input queues */      {        dev->nLastError = err;        dev->dwErrorCounter++;        dev->wCANStatus |=  CAN_ERR_QOVERRUN;        // throw away last message which was refused by fifo        dev->writereg(dev, COMMAND, RELEASE_RECEIVE_BUFFER);        wmb();      }      if (err > 0) // successfully enqueued into chardev FIFO        rwakeup++;      dev->ucActivityState = ACTIVITY_XMIT; // reset to ACTIVITY_IDLE by cyclic timer    }    if (irqstatus & (BUS_ERROR_INTERRUPT | ERROR_PASSIV_INTERRUPT | ERROR_WARN_INTERRUPT))    {      // DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(), irqstatus=0x%02x\n", DEVICE_NAME, irqstatus);       if (irqstatus & (ERROR_PASSIV_INTERRUPT | ERROR_WARN_INTERRUPT))      {        u8 chipstatus = dev->readreg(dev, CHIPSTATUS);        		// DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(), chipstatus=0x%02x\n", DEVICE_NAME, chipstatus);        switch (chipstatus & (BUS_STATUS | ERROR_STATUS))        {          case 0x00:                     // error active, clear only local status                    dev->busStatus = CAN_ERROR_ACTIVE;                    DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(), busStatus=CAN_ERROR_ACTIVE (1)\n", DEVICE_NAME);                                       dev->wCANStatus &=  ~(CAN_ERR_BUSOFF | CAN_ERR_BUSHEAVY | CAN_ERR_BUSLIGHT);                     break;          case BUS_STATUS:          case BUS_STATUS | ERROR_STATUS:                    // bus-off                    dev->busStatus = CAN_BUS_OFF;                                        dev->wCANStatus |=  CAN_ERR_BUSOFF;                    ef.can_id |= CAN_ERR_BUSOFF_NETDEV;                    DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(), busStatus=CAN_BUS_OFF\n", DEVICE_NAME);                                       break;          case ERROR_STATUS:                     if (irqstatus & ERROR_PASSIV_INTERRUPT)                    {                      // either enter or leave error passive status                      if (dev->busStatus == CAN_ERROR_PASSIVE)                      {                        // go back to error active                        dev->busStatus = CAN_ERROR_ACTIVE;                        dev->wCANStatus &=  ~(CAN_ERR_BUSOFF | CAN_ERR_BUSHEAVY);                         dev->wCANStatus |=  CAN_ERR_BUSLIGHT;                        DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(), busStatus=CAN_ERROR_ACTIVE (2)\n", DEVICE_NAME);                                         }                      else                      {                        // enter error passive state                        dev->busStatus = CAN_ERROR_PASSIVE;                        dev->wCANStatus &=  ~CAN_ERR_BUSOFF;                         dev->wCANStatus |=  CAN_ERR_BUSHEAVY;                                             ef.can_id  |= CAN_ERR_CRTL;                        ef.data[1] |= (CAN_ERR_CRTL_RX_PASSIVE | CAN_ERR_CRTL_TX_PASSIVE);                        DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(), busStatus=CAN_ERROR_PASSIVE\n", DEVICE_NAME);                                         }                    }                    else                    {                      // it was a warning limit reached event                      dev->busStatus = CAN_ERROR_ACTIVE;                                          dev->wCANStatus |=  CAN_ERR_BUSLIGHT;                                           ef.can_id  |= CAN_ERR_CRTL;                      ef.data[1] |= (CAN_ERR_CRTL_RX_WARNING | CAN_ERR_CRTL_TX_WARNING);                      DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(), busStatus=CAN_ERROR_ACTIVE (3)\n", DEVICE_NAME);                                       }                    break;        }      }      // count each error signal even if it does not change any bus or error state      dev->dwErrorCounter++;              // wake up pending reads or writes      rwakeup++;      wwakeup++;      dev->ucActivityState = ACTIVITY_XMIT; // reset to ACTIVITY_IDLE by cyclic timer    }    /* if an error condition occurred, send an error frame to the userspace */    if (ef.can_id)    {      struct timeval tv;      DO_GETTIMEOFDAY(tv); /* create timestamp */      ef.can_id  |= CAN_ERR_FLAG;      ef.can_dlc  = CAN_ERR_DLC;      SJA1000_LOCK_IRQSAVE(in_lock);      if (pcan_xxxdev_rx(dev, &ef, &tv) > 0) // put into specific data sink        rwakeup++;      SJA1000_UNLOCK_IRQRESTORE(in_lock);      memset(&ef, 0, sizeof(ef)); // clear for next loop    }    ret = SJA1000_IRQ_HANDLED;  }  SJA1000_UNLOCK_IRQRESTORE(sja_lock);  if (wwakeup)  {    atomic_set(&dev->DataSendReady, 1); // signal to write I'm ready    wmb();    SJA1000_WAKEUP_WRITE();    #ifdef NETDEV_SUPPORT    if (dev->netdev)      netif_wake_queue(dev->netdev);    #endif  }  if (rwakeup)    SJA1000_WAKEUP_READ();  return ret;}//----------------------------------------------------------------------------// probe for a sja1000 - use it only in reset mode!int  sja1000_probe(struct pcandev *dev){  u8  tmp;  u8  _clkdivider= clkdivider(dev);  DPRINTK(KERN_DEBUG "%s: sja1000_probe()\n", DEVICE_NAME);  // trace the clockdivider register to test for sja1000 / 82c200  tmp = dev->readreg(dev, CLKDIVIDER);  DPRINTK(KERN_DEBUG "%s: CLKDIVIDER traced (0x%02x)\n", DEVICE_NAME, tmp);  if (tmp & 0x10)    goto fail;  // until here, it's either a 82c200 or a sja1000  if (set_reset_mode(dev))    goto fail;  dev->writereg(dev, CLKDIVIDER, _clkdivider); // switch to PeliCAN mode  sja1000_irq_disable(dev);                    // precautionary disable interrupts  wmb();  DPRINTK(KERN_DEBUG "%s: Hopefully switched to PeliCAN mode\n", DEVICE_NAME);  tmp = dev->readreg(dev, CHIPSTATUS);  DPRINTK(KERN_DEBUG "%s: CHIPSTATUS traced (0x%02x)\n", DEVICE_NAME, tmp);  if ((tmp & 0x30) != 0x30)    goto fail;  tmp = dev->readreg(dev, INTERRUPT_STATUS);  DPRINTK(KERN_DEBUG "%s: INTERRUPT_STATUS traced (0x%02x)\n", DEVICE_NAME, tmp);  if (tmp & 0xfb)    goto fail;  tmp = dev->readreg(dev, RECEIVE_MSG_COUNTER);  DPRINTK(KERN_DEBUG "%s: RECEIVE_MSG_COUNTER traced (0x%02x)\n", DEVICE_NAME, tmp);  if (tmp)    goto fail;  DPRINTK(KERN_DEBUG "%s: sja1000_probe() is OK\n", DEVICE_NAME);  return 0;  fail:  DPRINTK(KERN_DEBUG "%s: sja1000_probe() failed\n", DEVICE_NAME);  return -ENXIO; // no such device or address}//----------------------------------------------------------------------------// calculate BTR0BTR1 for odd bitrates//// most parts of this code is from Arnaud Westenberg email:arnaud@wanadoo.nl// www.home.wanadoo.nl/arnaud//// Set communication parameters.// param rate baud rate in Hz// param clock frequency of sja1000 clock in Hz// param sjw synchronization jump width (0-3) prescaled clock cycles// param sampl_pt sample point in % (0-100) sets (TSEG1+2)/(TSEG1+TSEG2+3) ratio// param flags fields BTR1_SAM, OCMODE, OCPOL, OCTP, OCTN, CLK_OFF, CBP//static int sja1000_baud_rate(int rate, int flags){  int best_error = 1000000000;  int error;  int best_tseg=0, best_brp=0, best_rate=0, brp=0;  int tseg=0, tseg1=0, tseg2=0;  int clock = CLOCK_HZ / 2;  u16 wBTR0BTR1;  int sjw = 0;  int sampl_pt = 90;  // some heuristic specials  if (rate > ((1000000 + 500000) / 2))    sampl_pt = 75;  if (rate < ((12500 + 10000) / 2))    sampl_pt = 75;  if (rate < ((100000 + 125000) / 2))    sjw = 1;  // tseg even = round down, odd = round up  for (tseg = (0 + 0 + 2) * 2; tseg <= (MAX_TSEG2 + MAX_TSEG1 + 2) * 2 + 1; tseg++)   {    brp = clock / ((1 + tseg / 2) * rate) + tseg % 2;    if ((brp == 0) || (brp > 64))      continue;    error = rate - clock / (brp * (1 + tseg / 2));    if (error < 0)      error = -error;    if (error <= best_error)     {      best_error = error;      best_tseg = tseg/2;      best_brp = brp-1;      best_rate = clock/(brp*(1+tseg/2));    }  }  if (best_error && (rate / best_error < 10))   {    DPRINTK(KERN_ERR "%s: bitrate %d is not possible with %d Hz clock\n", DEVICE_NAME, rate, 2 * clock);    return 0;  }  tseg2 = best_tseg - (sampl_pt * (best_tseg + 1)) / 100;  if (tseg2 < 0)    tseg2 = 0;  if (tseg2 > MAX_TSEG2)    tseg2 = MAX_TSEG2;  tseg1 = best_tseg - tseg2 - 2;  if (tseg1 > MAX_TSEG1)   {    tseg1 = MAX_TSEG1;    tseg2 = best_tseg-tseg1-2;  }  wBTR0BTR1 = ((sjw<<6 | best_brp) << 8) | (((flags & BTR1_SAM) != 0)<<7 | tseg2<<4 | tseg1);  return wBTR0BTR1;}//----------------------------------------------------------------------------// get BTR0BTR1 init valuesu16 sja1000_bitrate(u32 dwBitRate){  u16 wBTR0BTR1 = 0;;  // get default const values  switch (dwBitRate)  {    case 1000000: wBTR0BTR1 = CAN_BAUD_1M;   break;    case  500000: wBTR0BTR1 = CAN_BAUD_500K; break;    case  250000: wBTR0BTR1 = CAN_BAUD_250K; break;    case  125000: wBTR0BTR1 = CAN_BAUD_125K; break;    case  100000: wBTR0BTR1 = CAN_BAUD_100K; break;    case   50000: wBTR0BTR1 = CAN_BAUD_50K;  break;    case   20000: wBTR0BTR1 = CAN_BAUD_20K;  break;    case   10000: wBTR0BTR1 = CAN_BAUD_10K;  break;    case    5000: wBTR0BTR1 = CAN_BAUD_5K;   break;    case       0: wBTR0BTR1 = 0;             break;    default:         // calculate for exotic values           wBTR0BTR1 = sja1000_baud_rate(dwBitRate, 0);  }  DPRINTK(KERN_DEBUG "%s: sja1000_bitrate(%d) = 0x%04x\n", DEVICE_NAME, dwBitRate, wBTR0BTR1);  return wBTR0BTR1;}// end

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -