📄 atcan.c
字号:
/*! * AtCan interrupt service routine */static void AtCanInterrupt(void *arg){ uint8_t savedCanPage; CANINFO *ci = (CANINFO *) (((NUTDEVICE *) arg)->dev_dcb); savedCanPage = CANPAGE; // Save the current CAN page ci->can_interrupts++; // // Check for MOB interrupt // if ((CANHPMOB & 0xF0) != 0xF0) { CANPAGE = CANHPMOB; // Switch page // RX interrupt ? if (bit_is_set(CANSTMOB, RXOK)) { // Space in buffer ? if (canRxBuf.datalength < canRxBuf.size) { int8_t j; CANFRAME * bufPtr = &canRxBuf.dataptr[(canRxBuf.dataindex + canRxBuf.datalength) % canRxBuf.size]; // Extended or standard ID? bufPtr->ext = bit_is_set(CANCDMOB, IDE); if (bufPtr->ext) { ((uint8_t *) &(bufPtr->id))[3] = CANIDT1 >> 3; ((uint8_t *) &(bufPtr->id))[2] = (CANIDT2 >> 3) | (CANIDT1 << 5); ((uint8_t *) &(bufPtr->id))[1] = (CANIDT3 >> 3) | (CANIDT2 << 5); ((uint8_t *) &(bufPtr->id))[0] = (CANIDT4 >> 3) | (CANIDT3 << 5); } else { ((uint8_t *) &(bufPtr->id))[3] = 0; ((uint8_t *) &(bufPtr->id))[2] = 0; ((uint8_t *) &(bufPtr->id))[1] = CANIDT1 >> 5; ((uint8_t *) &(bufPtr->id))[0] = (CANIDT1 << 3) | (CANIDT2 >> 5); } bufPtr->len = CANCDMOB & (_BV(DLC0) | _BV(DLC1) | _BV(DLC2) | _BV(DLC3)); bufPtr->rtr = bit_is_set(CANIDT4, RTRTAG); for (j = 0; j < 8; j++) bufPtr->byte[j] = CANMSG; // Increment buffer length canRxBuf.datalength++; NutEventPostFromIrq(&ci->can_rx_rdy); CANSTMOB = CANSTMOB & ~_BV(RXOK); // Data sheet requires r/m/w cycle on whole register // Re-enable MOB for reception CANCDMOB |= _BV(CONMOB1); // Stat houskeeping ci->can_rx_frames++; } else { CANSTMOB = CANSTMOB & ~_BV(RXOK); // Data sheet requires r/m/w cycle on whole register // Re-enable MOB for reception CANCDMOB |= _BV(CONMOB1); // Stat houskeeping ci->can_overruns++; } } // TX interrupt ? else if (bit_is_set(CANSTMOB, TXOK)) { NutEventPostFromIrq(&ci->can_tx_rdy); CANSTMOB = CANSTMOB & ~_BV(TXOK); // Data sheet requires r/m/w cycle on whole register // Re-claim MOB CANCDMOB &= ~(_BV(CONMOB1) | _BV(CONMOB0)); } else { CANSTMOB = CANSTMOB & 0x80; // Data sheet requires r/m/w cycle on whole register } } else { // General CAN interrupt // //ttt TODO: Implement it! //ci->can_errors++; //ci->can_overruns++; } CANPAGE = savedCanPage; // Restore CAN page register}/***************************************************************************** * Function definitions *****************************************************************************//*! * Checks if data is available in input buffer * * \param dev Pointer to the device structure * \return Number of frames available */u_char AtCanRxAvail(NUTDEVICE * dev){ return canRxBuf.datalength;}/*! * Checks if there's still space in output buffer * * \param dev Pointer to the device structure * \return 1 if space is available */u_char AtCanTxFree(NUTDEVICE * dev){ return (AtCanGetFreeMob() >= 0);}/*! * Write a frame from to output buffer * * This function writes a frame to the output buffer. If the output buffer * is full the function will block until frames are send. * * \param dev Pointer to the device structure * \param frame Pointer to the receive frame */void AtCanOutput(NUTDEVICE * dev, CANFRAME * frame){ CANINFO * ci = (CANINFO *) dev->dev_dcb; while (AtCanSendMsg(frame) == CAN_TXBUF_FULL) { NutEventWait(&ci->can_tx_rdy, NUT_WAIT_INFINITE); }; // Increment counter ci->can_tx_frames++;}/*! * Reads a frame from input buffer * * This function reads a frame from the input buffer. If the input buffer * is empty the function will block unitl new frames are received. * * \param dev Pointer to the device structure * \param frame Pointer to the receive frame */void AtCanInput(NUTDEVICE * dev, CANFRAME * frame){ CANINFO * ci = (CANINFO *) dev->dev_dcb; while (canRxBuf.datalength == 0) { NutEventWait(&ci->can_rx_rdy, NUT_WAIT_INFINITE); } NutEnterCritical(); // Get the first frame from buffer *frame = canRxBuf.dataptr[canRxBuf.dataindex]; // Move index down and decrement length canRxBuf.dataindex++; if (canRxBuf.dataindex >= canRxBuf.size) canRxBuf.dataindex %= canRxBuf.size; canRxBuf.datalength--; NutExitCritical();}/*! * Sets the acceptance code * * \param dev Pointer to the device structure * \param ac 4 byte char array with the acceptance code */void AtCanSetAccCode(NUTDEVICE * dev, u_char * ac){ memcpy(((IFCAN *) (dev->dev_icb))->can_acc_code, ac, 4); AtCanEnableRx(RX_MOB, 0, 0, 0, 0, 0, 0); //ttt TODO: Implement it!}/*! * Sets the acceptance mask * * \param dev Pointer to the device structure * \param am 4 byte char array with the acceptance mask */void AtCanSetAccMask(NUTDEVICE * dev, u_char * am){ memcpy(((IFCAN *) (dev->dev_icb))->can_acc_mask, am, 4); AtCanEnableRx(RX_MOB, 0, 0, 0, 0, 0, 0); //ttt TODO: Implement it!}/*! * Sets the CAN baudrate * * \param dev Pointer to the device structure * \param baudrate Baudrate (One of the defined baudrates. See AtCan.h) * \return 0 for success */u_char AtCanSetBaudrate(NUTDEVICE * dev, u_long baudrate){ switch (baudrate) { case CAN_SPEED_10K: CANBT1 = CAN_BT1_10K; CANBT2 = CAN_BT2_10K; CANBT3 = CAN_BT3_10K; break; case CAN_SPEED_20K: CANBT1 = CAN_BT1_20K; CANBT2 = CAN_BT2_20K; CANBT3 = CAN_BT3_20K; break; case CAN_SPEED_50K: CANBT1 = CAN_BT1_50K; CANBT2 = CAN_BT2_50K; CANBT3 = CAN_BT3_50K; break; case CAN_SPEED_100K: CANBT1 = CAN_BT1_100K; CANBT2 = CAN_BT2_100K; CANBT3 = CAN_BT3_100K; break; case CAN_SPEED_125K: CANBT1 = CAN_BT1_125K; CANBT2 = CAN_BT2_125K; CANBT3 = CAN_BT3_125K; break; case CAN_SPEED_250K: CANBT1 = CAN_BT1_250K; CANBT2 = CAN_BT2_250K; CANBT3 = CAN_BT3_250K; break; case CAN_SPEED_500K: CANBT1 = CAN_BT1_500K; CANBT2 = CAN_BT2_500K; CANBT3 = CAN_BT3_500K; break; case CAN_SPEED_800K: CANBT1 = CAN_BT1_800K; CANBT2 = CAN_BT2_800K; CANBT3 = CAN_BT3_800K; break; case CAN_SPEED_1M: CANBT1 = CAN_BT1_1M; CANBT2 = CAN_BT2_1M; CANBT3 = CAN_BT3_1M; break; case CAN_SPEED_CUSTOM: // Do nothing, user sets baudrate directly but don't report an error break; default: return 1; } ((IFCAN *) (dev->dev_icb))->can_baudrate = baudrate; return 0;}/*! * Initialize CAN interface. * * Applications typically do not use this function, but * call NutRegisterDevice(). * * \param dev Identifies the device to initialize. The * structure must be properly set. * \return 0 for successful initialisation or -1 in case init failed */int AtCanInit(NUTDEVICE * dev){ int8_t mob, i; memset(dev->dev_dcb, 0, sizeof(CANINFO)); // Init receive buffer canRxBuf.dataptr = NutHeapAlloc(CAN_BUF_SIZE * sizeof(CANFRAME)); canRxBuf.size = CAN_BUF_SIZE; canRxBuf.dataindex = 0; canRxBuf.datalength = 0; // Disable AT90CAN128 CAN system CANGCON &= ~_BV(ENASTB); loop_until_bit_is_clear(CANGSTA, ENFG); // Clear all MOBs for (mob = 0; mob < MAX_NO_MOB; mob++) { CANPAGE = mob << 4; CANSTMOB = 0; // Clear status register CANCDMOB = 0; // Clear control register CANHPMOB = 0; // Clear HP flags // Clear identifier tag CANIDT1 = 0; CANIDT2 = 0; CANIDT3 = 0; CANIDT4 = 0; // Clear identifier mask CANIDM1 = 0; CANIDM2 = 0; CANIDM3 = 0; CANIDM4 = 0; for (i = 0; i < 8; i++) { CANMSG = 0; } } // Set baudrate AtCanSetBaudrate(dev, ifc_atcan.can_baudrate); // Errors silently ingnored here // Install IRQ handler if (NutRegisterIrqHandler(&sig_CAN_TRANSFER, AtCanInterrupt, dev)) return -1; // Enable all MOB interrupts and RX, TX etc CANIE1 = 0x7F; CANIE2 = 0xFF; CANGIE = _BV(ENIT)| _BV(ENRX) | _BV(ENTX) ; // Enable receiving MOBs AtCanEnableRx(RX_MOB, 0, 0, 0, 0, 0, 0); // Enable AT90CAN128 CAN system CANGCON |= _BV(ENASTB); loop_until_bit_is_set(CANGSTA, ENFG); return 0;}/*! * Interface information structure. * * This structure stores some interface parameters like bit rate, * acceptance mask, acceptance code and callback handlers. */IFCAN ifc_atcan = { CAN_IF_2B, /*!< \brief Interface type. */ CAN_SPEED_125K, /*!< \brief Baudrate of device. */ {0xFF, 0xFF, 0xFF, 0xFF}, /*!< \brief Acceptance mask */ {0x00, 0x00, 0x00, 0x00}, /*!< \brief Acceptance code */ AtCanRxAvail, /*!< \brief Data in RxBuffer available? */ AtCanTxFree, /*!< \brief TxBuffer free? */ AtCanInput, /*!< \brief CAN Input routine */ AtCanOutput, /*!< \brief CAN Output routine */ AtCanSetAccCode, /*!< \brief Set acceptance code */ AtCanSetAccMask, /*!< \brief Set acceptance mask */ AtCanSetBaudrate /*!< \brief Set baudrate */};/*! * Device information structure. * * Applications must pass this structure to NutRegisterDevice() * to bind this CAN device driver to the Nut/OS kernel. */NUTDEVICE devAtCan = { 0, /*!< Pointer to next device. */ {'a', 't', 'c', 'a', 'n', '0', 0, 0, 0}, /*!< Unique device name. */ IFTYP_CAN, /*!< Type of device. */ 0, /*!< Base address. */ 0, /*!< First interrupt number. */ &ifc_atcan, /*!< Interface control block. */ &dcb_atcan, /*!< Driver control block. */ AtCanInit, /*!< Driver initialization routine. */ 0, /*!< Driver specific control function. */ 0, /*!< Read from device. */ 0, /*!< Write to device. */ 0, /*!< Write from program space data to device. */ 0, /*!< Open a device or file. */ 0, /*!< Close a device or file. */ 0 /*!< Request file size. */};#elsestatic void keep_icc_happy(void){}#endif/*@}*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -