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

📄 drv_can.c

📁 picos18的can驱动样例程序
💻 C
📖 第 1 页 / 共 2 页
字号:
 * @return Status     E_OK if tranfer initiated
 *                    E_OS_STATE otherwise
 **********************************************************************/
StatusType CopyFrameBuffer2Hard(pTXBUF_t pTxbuf)
{
  StatusType returned_type;
  unsigned char foo;
  returned_type = E_OS_STATE;
  
  CAN_current_message = CAN_deqMsg();
  
  if (CAN_current_message == NULL)
    return(returned_type);
  
  #ifdef __EXT29BITS__
  pTxbuf->EIDL = CAN_current_message->CANID;
  pTxbuf->EIDH = CAN_current_message->CANID >> 8;
  pTxbuf->SIDL = (CAN_current_message->CANID >> 16) & 0x03;
  foo      = (CAN_current_message->CANID >> 13) & 0xE0;
  foo      = foo | 0x08;
  pTxbuf->SIDL = pTxbuf->SIDL + foo;
  pTxbuf->SIDH = CAN_current_message->CANID >> 21;
  #else
   #ifdef  __STD11BITS__
    pTxbuf->SIDL = CAN_current_message->CANID << 5;
    pTxbuf->SIDH = CAN_current_message->CANID >> 3;
   #else
    #error "you should define 11 or 29 bits for CANID !"
   #endif
  #endif
  pTxbuf->DLC  = CAN_current_message->length & 0x0F;
  pTxbuf->DATA[0]   = CAN_current_message->data[0];
  pTxbuf->DATA[1]   = CAN_current_message->data[1];
  pTxbuf->DATA[2]   = CAN_current_message->data[2];
  pTxbuf->DATA[3]   = CAN_current_message->data[3];
  pTxbuf->DATA[4]   = CAN_current_message->data[4];
  pTxbuf->DATA[5]   = CAN_current_message->data[5];
  pTxbuf->DATA[6]   = CAN_current_message->data[6];
  pTxbuf->DATA[7]   = CAN_current_message->data[7];
  CAN_current_message->state = CAN_MSG_SENT;
  SetEvent(CAN_current_message->CallerID, CAN_QUEUE_EMPTY);
  
  SET_TXREQ(pTxbuf);
  returned_type = E_OK;
  
  return(returned_type);
}

/**********************************************************************
 *	Enqueue a client packet object into the RS task queue.
 *
 *	Once placed in queue, client must not modify the data
 *	otherwise unpredictable results. To safely change the object,
 *	dequeue, modify, re-enqueue.
 *
 *  The code in mainly executed in critical region [SuspendAllInterrupt]
 *  because many tasks can call this function at the same time and break
 *  the FIFO list.
 *
 *	Returns 1 if successfull, 0 if message could not be enqueued
 **********************************************************************/
StatusType CAN_enqMsg(CAN_message_tRef toEnqueue)
{
  CAN_message_tRef CAN_list_itor;

  if (toEnqueue != NULL)
  {
    SuspendOSInterrupts();
    if (CAN_list_head == NULL)
      CAN_list_head = toEnqueue;
    else
    {
      CAN_list_itor = CAN_list_head;
      while (CAN_list_itor->next != NULL)
        CAN_list_itor = CAN_list_itor->next;
      CAN_list_itor->next = toEnqueue;
    }
    toEnqueue->next     = NULL;
    toEnqueue->CallerID = id_tsk_run;
    toEnqueue->state    = CAN_FULL;
    CAN_list_count++;
    ResumeOSInterrupts();
    return E_OK;
  }
  else
    return E_OS_STATE;
}

/**********************************************************************
 *	Dequeue a client message from the RS task queue.
 *
 *
 *********************************************************************/
CAN_message_tRef CAN_deqMsg(void)
{
  CAN_message_tRef CAN_list_itor;

  SuspendOSInterrupts();
  CAN_list_itor = NULL;
  if (CAN_list_head != NULL)
  {
    CAN_list_itor = CAN_list_head;
    CAN_list_head = CAN_list_head->next;
    CAN_list_count--;
  }
  ResumeOSInterrupts();
  return CAN_list_itor;
} 

/**********************************************************************
 * Called by the CAN driver task.
 * Check the RXFUL bit of the both RX CAN hardware buffers.
 * If at least one message is store in hardware then this function
 * tries to tranfer the data from hardware to dedicated structure
 * (structure created by other tasks).
 *
 * @param void        
 * @return Status    Always return E_OK
 **********************************************************************/
StatusType ReadCANBuffer(void)
{
  if (PIR3bits.RXB0IF == 1)
  {
    CANCONbits.WIN2 = 1; 
    CANCONbits.WIN1 = 1; 
    CANCONbits.WIN0 = 0;
    if (CopyHard2FrameBuffer() == E_OK)
    {
      RXB0CONbits.RXFUL = 0;
      PIR3bits.RXB0IF    = 0;
      PIE3bits.RXB0IE   = 1;
    }
  }
  if (PIR3bits.RXB1IF == 1)
  {
    CANCONbits.WIN2 = 1; 
    CANCONbits.WIN1 = 0; 
    CANCONbits.WIN0 = 1;
    if (CopyHard2FrameBuffer() == E_OK)
    {
      RXB0CONbits.RXFUL = 0;
      PIR3bits.RXB1IF    = 0;
      PIE3bits.RXB1IE   = 1;
    }
  }
  
  return(E_OK);
}

/**********************************************************************
 *	Enqueue a client packet object into the RS task queue.
 *
 *	Once placed in queue, client must not modify the data
 *	otherwise unpredictable results. To safely change the object,
 *	dequeue, modify, re-enqueue.
 *
 *  The code in mainly executed in critical region [SuspendAllInterrupt]
 *  because many tasks can call this function at the same time and break
 *  the FIFO list.
 *
 *	Returns 1 if successfull, 0 if message could not be enqueued
 **********************************************************************/
StatusType CAN_RCV_Register(CAN_message_tRef toEnqueue)
{
  CAN_message_tRef CAN_list_itor;

  if (toEnqueue != NULL)
  {
    SuspendOSInterrupts();
    if (CAN_list_head_rcv == NULL)
      CAN_list_head_rcv = toEnqueue;
    else
    {
      CAN_list_itor = CAN_list_head_rcv;
      while (CAN_list_itor->next != NULL)
        CAN_list_itor = CAN_list_itor->next;
      CAN_list_itor->next = toEnqueue;
    }
    toEnqueue->next     = NULL;
    toEnqueue->CallerID = id_tsk_run;
    CAN_list_count_rcv++;
    ResumeOSInterrupts();
    return E_OK;
  }
  else
    return E_OS_STATE;
}

/**********************************************************************
 * Parse the entier RX message list to find any task waiting for the 
 * received message ID.
 * Once a such taks is found we post an event to the waiting task
 * to tell its software buffer is full and we break.
 * The event is used if the task want to wait for a particular message
 * ID without overloading the CPU by a pooling method.
 *
 * @param  type    IN Number of the hardware buffer      
 * @return Status     E_OK if tranfer initiated
 *                    E_OS_STATE otherwise
 **********************************************************************/
StatusType CopyHard2FrameBuffer(void)
{
  StatusType returned_type;
  unsigned long ID_received;
  CAN_message_tRef CAN_list_itor;

  returned_type = E_OK;

  if (CAN_list_head_rcv != NULL)
  {
    CAN_list_itor = CAN_list_head_rcv;
    do
    {
      #ifdef __NOFILTER__
      if (1)
      #else
      #ifdef __EXT29BITS__
      ID_received  = 0;
      ID_received += (unsigned long)(RXB0EIDL);
      ID_received += (unsigned long)(RXB0EIDH) << 8;
      ID_received += (unsigned long)(RXB0SIDL & 0x03) << 16;
      ID_received += (unsigned long)(RXB0SIDL & 0xE0) << 13;
      ID_received += (unsigned long)(RXB0SIDH & 0xFF) << 21;
      #else
       #ifdef  __STD11BITS__
        ID_received  = 0;
        ID_received += (unsigned long)(RXB0SIDL) >> 5;
        ID_received += (unsigned long)(RXB0SIDH) << 3;
       #else
        #error "you should define 11 or 29 bits for CANID !"
       #endif
      #endif
      if (CAN_list_itor->CANID == ID_received)
      #endif
      {
        if (CAN_list_itor->state == CAN_FREE)
        {
          CAN_list_itor->data[0] = RXB0D0;
          CAN_list_itor->data[1] = RXB0D1;
          CAN_list_itor->data[2] = RXB0D2;
          CAN_list_itor->data[3] = RXB0D3;
          CAN_list_itor->data[4] = RXB0D4;
          CAN_list_itor->data[5] = RXB0D5;
          CAN_list_itor->data[6] = RXB0D6;
          CAN_list_itor->data[7] = RXB0D7;
          CAN_list_itor->length  = RXB0DLC & 0x0F;
          CAN_list_itor->state   = CAN_FULL;
          SetEvent(CAN_list_itor->CallerID, CAN_QUEUE_FULL);  
        }
        else
          returned_type = E_OS_STATE; 
      }
      CAN_list_itor = CAN_list_itor->next;
    }
    while (CAN_list_itor != NULL);
  }

  return(returned_type);
}

/**********************************************************************
 * ISR of the CAN driver.
 * 
 * For each interrupt we disable the IE first to avoid any infinite loop
 * and we clear the IF in the dedicated function (Read or Write CAN mess).
 * Indeed we have to clear the IT when the message has been properly 
 * accessed and is no more used. The IF lets the peripheral accept a new 
 * message.  
 * If 3 frames arrive at the same time, the two first are stored in the 
 * RCV buffers and the third is discarded (temporary overload bus).
 *
 * @return void 
 **********************************************************************/
void CAN_INT(void)
{
  if (PIR3 & 0x03)
  { 
    if (PIR3bits.RXB0IF)
      PIE3bits.RXB0IE = 0;
    if (PIR3bits.RXB1IF)
      PIE3bits.RXB1IE = 0;
    SetEvent(CAN_DRV_ID, CAN_RCV_MSG);
  };
  
  if (PIR3 & 0x1C)
  {
    if (PIR3bits.TXB0IF)
      PIE3bits.TXB0IE = 0;
    if (PIR3bits.TXB1IF)
      PIE3bits.TXB1IE = 0;
    if (PIR3bits.TXB2IF)
      PIE3bits.TXB2IE = 0;
    SetEvent(CAN_DRV_ID, CAN_NEW_MSG);
  }
    
  if (PIR3 & 0xE0)
  {
    if (PIR3bits.WAKIF)
      PIR3bits.WAKIF = 0;
    if (PIR3bits.ERRIF)
    {
      COMSTATbits.RXB0OVFL = 0;
      COMSTATbits.RXB1OVFL = 0;
      PIR3bits.ERRIF = 0;
    }
    if (PIR3bits.IRXIF)
      PIR3bits.IRXIF = 0;
    SetEvent(CAN_DRV_ID, CAN_ERR_MSG);
  }
}

/* End of File : drv_can.c */

⌨️ 快捷键说明

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