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

📄 pcan_sja1000.c

📁 CAN 驱动编程
💻 C
📖 第 1 页 / 共 2 页
字号:
  
        local.dwID   >>= 21;

        while (ucLen--)
        {
          m->Msg.DATA[j] = dev->readreg(dev, RECEIVE_FRAME_BASE + 3 + j);
	        j++;
	      }
      }

      m->Msg.ID = local.dwID;

      if (rxfi & BUFFER_RTR)
        m->Msg.MSGTYPE |= MSGTYPE_RTR;
    
      // step forward in fifo
      result = pcan_fifo_put(&dev->readFifo);
      if (result)
        goto fail;  
	  }
	  else
	  {
	    // filtered out extended messages in non extended mode, reject claim
      result = pcan_fifo_put_reject(&dev->readFifo);
      if (result)
        goto fail; 
	  }    
	   
    // release the receive buffer
    dev->writereg(dev, COMMAND, RELEASE_RECEIVE_BUFFER);  
    wmb();
    
    // give time to settle
    udelay(1);
	}	while (dev->readreg(dev, CHIPSTATUS) & RECEIVE_BUFFER_STATUS && (i--));	
      
  fail:
  return result ;
}

//----------------------------------------------------------------------------
// write CAN-data to chip, 
int sja1000_write(struct pcandev *dev) 
{
  int        result;
  int        j;
  TPCANMsg   *m;
  u8         txfi;
  ID         local;
  u8         ucLen;
  
  DPRINTK(KERN_DEBUG "%s: sja1000_write() %d\n", DEVICE_NAME, dev->writeFifo.nStored);
  
  // aquire a fifo element
  result = pcan_fifo_claim_for_get(&dev->writeFifo, (void *)&m);
  if (result)
    goto fail;
  
  txfi = ucLen = m->LEN;    
  
  j = 0;
  local.dwID = m->ID;
  if (m->MSGTYPE & MSGTYPE_EXTENDED)
  {
    local.dwID   <<= 3;

    #ifdef __LITTLE_ENDIAN
    dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, local.ucID[3]);
    dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, local.ucID[2]);
    dev->writereg(dev, TRANSMIT_FRAME_BASE + 3, local.ucID[1]);
    dev->writereg(dev, TRANSMIT_FRAME_BASE + 4, local.ucID[0]);
    #else
    dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, local.ucID[0]);
    dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, local.ucID[1]);
    dev->writereg(dev, TRANSMIT_FRAME_BASE + 3, local.ucID[2]);
    dev->writereg(dev, TRANSMIT_FRAME_BASE + 4, local.ucID[3]);
    #endif
  
    while (ucLen--)
    {
      dev->writereg(dev, TRANSMIT_FRAME_BASE + 5 + j, m->DATA[j]);
	    j++;
	  }
	
    txfi |= BUFFER_EFF;
  }
  else
  {
    local.dwID   <<= 21;
  
    #ifdef __LITTLE_ENDIAN
    dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, local.ucID[3]);
    dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, local.ucID[2]);
    #else
    dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, local.ucID[0]);
    dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, local.ucID[1]);
    #endif
  

    while (ucLen--)
    {
      dev->writereg(dev, TRANSMIT_FRAME_BASE + 3 + j, m->DATA[j]);
	    j++;
	  }
  }

  if (m->MSGTYPE & MSGTYPE_RTR)
    txfi |= BUFFER_RTR;
  
  // release fifo buffer and step forward in fifo
  result = pcan_fifo_get(&dev->writeFifo);
  if (result)
    goto fail;
 
  // finish message construction
  dev->writereg(dev, TRANSMIT_FRAME_BASE, txfi); 

  // request a transmission
 	dev->writereg(dev, COMMAND, TRANSMISSION_REQUEST); 
	wmb(); 
	
  fail:
  return result;
}

//----------------------------------------------------------------------------
// handle a interrupt request
void sja1000_irqhandler(int irq, void *dev_id, struct pt_regs *regs)
{
  register struct pcandev *dev = (struct pcandev *)dev_id;
  u8 status;
  int err;
  u16 rwakeup = 0;
  u16 wwakeup = 0;
  int j = MAX_INTERRUPTS_PER_ENTRY;
  
   
  while ((j--) && (status = dev->readreg(dev, INTERRUPT_STATUS)))
  {    
    // DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(0x%02x)\n", DEVICE_NAME, status);
  
    dev->dwInterruptCounter++;

    if (status & TRANSMIT_INTERRUPT)
    {
      // handle transmission
	    if ((err = sja1000_write(dev)))
	    {
	      if (err == -ENODATA)
		      wwakeup++;
		    else
		    {
	        dev->nLastError = err;
		      dev->dwErrorCounter++; 
		      dev->wCANStatus |= CAN_ERR_QXMTFULL; // fatal error!
		    }
		  }
    }
  
    if (status & DATA_OVERRUN_INTERRUPT)
    {
      // handle data overrun
	    dev->wCANStatus |= CAN_ERR_QOVERRUN;
      rwakeup++;
		  dev->dwErrorCounter++;

	    dev->writereg(dev, COMMAND, CLEAR_DATA_OVERRUN);  
      wmb();
    }   
    
    if (status & RECEIVE_INTERRUPT)
    {
      // handle receiption
	    if ((err = sja1000_read(dev)))
	    {
	      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();
		  }
		  rwakeup++;
    }
  
    if (status & (BUS_ERROR_INTERRUPT | ERROR_PASSIV_INTERRUPT))
    {
		  if (status & ERROR_PASSIV_INTERRUPT)
		  {
		    dev->wCANStatus |=  CAN_ERR_BUSHEAVY;
		    dev->dwErrorCounter++;		    
      }
		   
			// don't restart sja1000 after Bus Off
			if (status & BUS_ERROR_INTERRUPT)
			{
			  dev->wCANStatus |=  CAN_ERR_BUSOFF;
		    dev->dwErrorCounter++;		    
			}
    } 
  }
  
  if (wwakeup)
  {
    atomic_set(&dev->DataSendReady, 1); // signal to write I'm ready
    wake_up_interruptible(&dev->write_queue);
  }
  
  if (rwakeup)
    wake_up_interruptible(&dev->read_queue);
}

//----------------------------------------------------------------------------
// probe for a sja1000 - use it only in reset mode!
int  sja1000_probe(struct pcandev *dev)
{
  u8  tmp;
  u8  clkdivider;
  
  DPRINTK(KERN_DEBUG "%s: sja1000_probe()\n", DEVICE_NAME);
  
  // clkdivider is depended of of type
  switch (dev->wType)
  {
    case HW_PCI:           
      clkdivider = (dev->port.pci.ucMasterDevice == CHANNEL_MASTER) ? PELICAN_MASTER : PELICAN_SINGLE;
      break;
      
    default:
      clkdivider = PELICAN_DEFAULT;
      
      // make a hardware reset
      dev->writereg(dev, CLKDIVIDER, CHIP_RESET); 
      break;
  }
  
  // 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 
  dev->writereg(dev, INTERRUPT_ENABLE, 0);    // prospective clear all 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 values
u16 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 + -