www.pudn.com > CAN_Ex1.rar > CAN_Hw.c
/*---------------------------------------------------------------------------- * R T L - C A N D r i v e r *---------------------------------------------------------------------------- * Name: CAN_Hw.c * Purpose: CAN Driver, Hardware specific module for LPC2xxx * Rev.: V3.12 *---------------------------------------------------------------------------- * This code is part of the RealView Run-Time Library. * Copyright (c) 2004-2007 KEIL - An ARM Company. All rights reserved. *---------------------------------------------------------------------------*/ #include/* RTX kernel functions & defines */ #include /* LPC23xx definitions */ #include "RTX_CAN.h" /* CAN Generic functions & defines */ #include "CAN_hw.h" /* CAN hw specific functions & defines */ #include "CAN_reg.h" /* LPC2xxx CAN registers */ #pragma diag_suppress 550 /* Values of bit time register for different baudrates NT = Nominal bit time = TSEG1 + TSEG2 + 3 SP = Sample point = ((TSEG2 +1) / (TSEG1 + TSEG2 + 3)) * 100% SAM, SJW, TSEG1, TSEG2, NT, SP */ const U32 CAN_BIT_TIME[] = { 0, /* not used */ 0, /* not used */ 0, /* not used */ 0, /* not used */ 0x0001C000, /* 0+1, 3+1, 1+1, 0+1, 4, 75% */ 0, /* not used */ 0x0012C000, /* 0+1, 3+1, 2+1, 1+1, 6, 67% */ 0, /* not used */ 0x0023C000, /* 0+1, 3+1, 3+1, 2+1, 8, 63% */ 0, /* not used */ 0x0025C000, /* 0+1, 3+1, 5+1, 2+1, 10, 70% */ 0, /* not used */ 0x0036C000, /* 0+1, 3+1, 6+1, 3+1, 12, 67% */ 0, /* not used */ 0, /* not used */ 0x0048C000, /* 0+1, 3+1, 8+1, 4+1, 15, 67% */ 0x0049C000, /* 0+1, 3+1, 9+1, 4+1, 16, 69% */ }; /*---------------------------------------------------------------------------- * CAN RTX Hardware Specific Driver Functions for LPC2xxx *---------------------------------------------------------------------------- * Functions implemented in this module: * static CAN_ERROR CAN_hw_set_baudrate (U32 ctrl, U32 baudrate) * CAN_ERROR CAN_hw_setup (U32 ctrl) * CAN_ERROR CAN_hw_init (U32 ctrl, U32 baudrate) * CAN_ERROR CAN_hw_start (U32 ctrl) * CAN_ERROR CAN_hw_tx_empty (U32 ctrl) * CAN_ERROR CAN_hw_wr (U32 ctrl, CAN_msg *msg) * static void CAN_hw_rd (U32 ctrl, CAN_msg *msg) * CAN_ERROR CAN_hw_set (U32 ctrl, CAN_msg *msg) * CAN_ERROR CAN_hw_rx_object (U32 ctrl, U32 ch, U32 id, CAN_FORMAT format) * CAN_ERROR CAN_hw_tx_object (U32 ctrl, U32 ch, CAN_FORMAT format) * Interrupt fuctions *---------------------------------------------------------------------------*/ /* Static functions used only in this module */ static void CAN_hw_rd (U32 ctrl, CAN_msg *msg); #if (USE_CAN_CTRL1 == 1) || (USE_CAN_CTRL2 == 1) static void CAN_ISR (void) __irq; #endif /************************* Auxiliary Functions *******************************/ /*------------------------ CAN_hw_set_baudrate ------------------------------ * * Setup the requested baudrate * * Parameter: ctrl: Index of the hardware CAN controller (1 .. x) * baudrate: Baudrate * * Return: CAN_ERROR: Error code *---------------------------------------------------------------------------*/ static CAN_ERROR CAN_hw_set_baudrate (U32 ctrl, U32 baudrate) { U32 ctrl0 = ctrl-1; /* Controller index 0 .. x-1 */ regCAN *ptrcan = (regCAN *) CAN_BASE[ctrl0]; U32 result = 0; U32 nominal_time; /* Determine which nominal time to use for PCLK and baudrate */ if (baudrate <= 500000) { nominal_time = 12; } else if (((PCLK / 1000000) % 15) == 0) { nominal_time = 15; } else if (((PCLK / 1000000) % 16) == 0) { nominal_time = 16; } else { nominal_time = 10; } /* Prepare value appropriate for bit time register */ result = (PCLK / nominal_time) / baudrate - 1; result &= 0x000003FF; result |= CAN_BIT_TIME[nominal_time]; ptrcan->CANBTR = result; /* Set bit timing */ return CAN_OK; } /*************************** Module Functions ********************************/ /*--------------------------- CAN_hw_setup ---------------------------------- * * Setup CAN transmit and receive PINs and interrupt vectors * * Parameter: ctrl: Index of the hardware CAN controller (1 .. x) * * Return: CAN_ERROR: Error code *---------------------------------------------------------------------------*/ CAN_ERROR CAN_hw_setup (U32 ctrl) { switch (ctrl) { case 1: #if USE_CAN_CTRL1 == 1 PCONP |= 1 << 13; /* Enable clock for CAN1 */ PINSEL0 &= 0xFFFFFFF0; /* Reset CAN1 bits */ PINSEL0 |= 0x00000005; /* Set CAN1 bits to b0101 */ /* Set interrupt vector for CAN1 */ *(&VICVectAddr23) = (unsigned long) CAN_ISR; *(&VICVectCntl23) = 1; VICIntEnable = (1 << 23); /* Enable CAN1 Interrupt */ #endif break; case 2: #if USE_CAN_CTRL2 == 1 PCONP |= 1 << 14; /* Enable clock for CAN2 */ PINSEL0 &= 0xFFFFF0FF; /* Reset CAN2 bits */ PINSEL0 |= 0x00000A00; /* Set CAN2 bits to b1010 */ /* Set interrupt vector for CAN2 */ *(&VICVectAddr23) = (unsigned long) CAN_ISR; *(&VICVectCntl23) = 1; VICIntEnable = (1 << 23); /* Enable CAN2 Interrupt */ #endif break; default: return CAN_UNEXIST_CTRL_ERROR; } return CAN_OK; } /*--------------------------- CAN_hw_init ----------------------------------- * * Initialize the CAN hardware * * Parameter: ctrl: Index of the hardware CAN controller (1 .. x) * baudrate: Baudrate * * Return: CAN_ERROR: Error code *---------------------------------------------------------------------------*/ CAN_ERROR CAN_hw_init (U32 ctrl, U32 baudrate) { U32 ctrl0 = ctrl-1; /* Controller index 0 .. x-1 */ regCAN_AF *ptrcan_af = (regCAN_AF *) CAN_AF_BASE; regCAN *ptrcan = (regCAN *) CAN_BASE[ctrl0]; ptrcan_af->AFMR = 2; /* By default filter is not used */ ptrcan->CANMOD = 1; /* Enter reset mode */ ptrcan->CANIER = 0; /* Disable all interrupts */ ptrcan->CANGSR = 0; /* Clear status register */ CAN_hw_set_baudrate(ctrl, baudrate);/* Set bit timing */ ptrcan->CANIER = 0x0003; /* Enable Tx and Rx interrupt */ return CAN_OK; } /*--------------------------- CAN_hw_start ---------------------------------- * * Enable the CAN interrupts (recive or/and transmit) * * Parameter: ctrl: Index of the hardware CAN controller (1 .. x) * * Return: CAN_ERROR: Error code *---------------------------------------------------------------------------*/ CAN_ERROR CAN_hw_start (U32 ctrl) { U32 ctrl0 = ctrl-1; /* Controller index 0 .. x-1 */ regCAN *ptrcan = (regCAN *) CAN_BASE[ctrl0]; ptrcan->CANMOD = 0; /* Enter normal operating mode */ return CAN_OK; } /*--------------------------- CAN_hw_tx_empty ------------------------------- * * Check if controller is available for transmission * * Parameter: ctrl: Index of the hardware CAN controller (1 .. x) * * Return: CAN_ERROR: Error code *---------------------------------------------------------------------------*/ CAN_ERROR CAN_hw_tx_empty (U32 ctrl) { U32 ctrl0 = ctrl-1; /* Controller index 0 .. x-1 */ regCAN *ptrcan = (regCAN *) CAN_BASE[ctrl0]; if ((os_sem_wait (wr_sem[ctrl-1], 0) != OS_R_TMO)){ /* If semaphore is free*/ if (ptrcan->CANSR & 0x00000004) /* Transmitter ready for */ /* transmission */ return CAN_OK; else os_sem_send(wr_sem[ctrl-1]); /* Return a token back to semaphore */ } return CAN_TX_BUSY_ERROR; } /*--------------------------- CAN_hw_wr ------------------------------------- * * Write CAN_msg to the hardware registers of the requested controller * * Parameter: ctrl: Index of the hardware CAN controller (1 .. x) * msg: Pointer to CAN message to be written to hardware * * Return: CAN_ERROR: Error code *---------------------------------------------------------------------------*/ CAN_ERROR CAN_hw_wr (U32 ctrl, CAN_msg *msg) { U32 ctrl0 = ctrl-1; /* Controller index 0 .. x-1 */ U32 CANData; regCAN *ptrcan = (regCAN *) CAN_BASE[ctrl0]; CANData = (((U32) msg->len) << 16) & 0x000F0000 | (msg->format == EXTENDED_FORMAT ) * 0x80000000 | (msg->type == REMOTE_FRAME) * 0x40000000; if (ptrcan->CANSR & 0x00000004) { /* Transmit buffer 1 free */ ptrcan->CANTF1 = CANData; /* Write frame informations */ ptrcan->CANTID1 = msg->id; /* Write CAN message identifier */ ptrcan->CANTDA1 = *(U32 *) &msg->data[0]; /* Write first 4 data bytes */ ptrcan->CANTDB1 = *(U32 *) &msg->data[4]; /* Write second 4 data bytes */ //ptrcan->CANCMR = 0x31; /* Select Tx1 for Self Tx/Rx */ ptrcan->CANCMR = 0x21; /* Start transmission without loop-back*/ } else return CAN_TX_BUSY_ERROR; return CAN_OK; } /*--------------------------- CAN_hw_rd ------------------------------------- * * Read CAN_msg from the hardware registers of the requested controller * * Parameter: ctrl: Index of the hardware CAN controller (1 .. x) * msg: Pointer where CAN message will be read * * Return: CAN_ERROR: Error code *---------------------------------------------------------------------------*/ static void CAN_hw_rd (U32 ctrl, CAN_msg *msg) { U32 ctrl0 = ctrl-1; /* Controller index 0 .. x-1 */ U32 CANData; U32 *CANAddr; regCAN *ptrcan = (regCAN *) CAN_BASE[ctrl0]; /* Read frame informations */ CANData = ptrcan->CANRFS; msg->format = (CANData & 0x80000000) == 0x80000000; msg->type = (CANData & 0x40000000) == 0x40000000; msg->len = ((U8)(CANData >> 16)) & 0x0F; /* Read CAN message identifier */ msg->id = ptrcan->CANRID; /* Read the data if received message was DATA FRAME */ if (msg->type == DATA_FRAME) { /* Read first 4 data bytes */ CANAddr = (U32 *) &msg->data[0]; *CANAddr++ = ptrcan->CANRDA; /* Read second 4 data bytes */ *CANAddr = ptrcan->CANRDB; } } /*--------------------------- CAN_hw_set ------------------------------------ * Set a message that will automatically be sent as an answer to the REMOTE * FRAME message, as this functionality is not enabled by hardware this * function is not implemented * * Parameter: ctrl: Ignored * msg: Pointer to CAN message to be set * * Return: CAN_ERROR: Error code *---------------------------------------------------------------------------*/ CAN_ERROR CAN_hw_set (U32 ctrl, CAN_msg *msg) { return CAN_NOT_IMPLEMENTED_ERROR; } /*--------------------------- CAN_hw_rx_object ------------------------------ * * Enable reception of messages, on specified controller with specified * identifier, by setting acceptance filter * * Parameter: ctrl: Index of the hardware CAN controller (1 .. x) * ch: Ignored for LPC2xxx * id: CAN message identifier * CAN_FORMAT: Format of CAN identifier (standard or extended) * * Return: CAN_ERROR: Error code *---------------------------------------------------------------------------*/ CAN_ERROR CAN_hw_rx_object (U32 ctrl, U32 ch, U32 id, CAN_FORMAT format) { U32 ctrl0 = ctrl-1; /* Controller index 0 .. x-1 */ static S16 CAN_std_cnt = 0; static S16 CAN_ext_cnt = 0; regCAN_AF *ptrcan_af = (regCAN_AF *) CAN_AF_BASE; regCAN_AFRAM *ptrcan_afram = (regCAN_AFRAM *) CAN_AFRAM_BASE; U32 buf0, buf1; S16 cnt1, cnt2, bound1; /* Acceptance Filter Memory full */ if ((((CAN_std_cnt + 1) >> 1) + CAN_ext_cnt) >= 512) return CAN_OBJECTS_FULL_ERROR; /* Setup Acceptance Filter Configuration Acceptance Filter Mode Register = Off */ ptrcan_af->AFMR = 0x00000001; if (format == STANDARD_FORMAT) { /* Add mask for standard identifiers */ id |= ctrl0 << 13; /* Add controller number */ id &= 0x0000F7FF; /* Mask out 16-bits of ID */ /* Move all remaining extended mask entries one place up if new entry will increase standard ID filters list */ if ((CAN_std_cnt & 0x0001) == 0 && CAN_ext_cnt != 0) { cnt1 = (CAN_std_cnt >> 1); bound1 = CAN_ext_cnt; buf0 = ptrcan_afram->mask[cnt1]; while (bound1--) { cnt1++; buf1 = ptrcan_afram->mask[cnt1]; ptrcan_afram->mask[cnt1] = buf0; buf0 = buf1; } } if (CAN_std_cnt == 0) { /* For entering first ID */ ptrcan_afram->mask[0] = 0x0000FFFF | (id << 16); } else if (CAN_std_cnt == 1) { /* For entering second ID */ if ((ptrcan_afram->mask[0] >> 16) > id) ptrcan_afram->mask[0] = (ptrcan_afram->mask[0] >> 16) | (id << 16); else ptrcan_afram->mask[0] = (ptrcan_afram->mask[0] & 0xFFFF0000) | id; } else { /* Find where to insert new ID */ cnt1 = 0; cnt2 = CAN_std_cnt; bound1 = (CAN_std_cnt - 1) >> 1; while (cnt1 <= bound1) { /* Loop through standard existing IDs */ if ((ptrcan_afram->mask[cnt1] >> 16) > id) { cnt2 = cnt1 * 2; break; } if ((ptrcan_afram->mask[cnt1] & 0x0000FFFF) > id) { cnt2 = cnt1 * 2 + 1; break; } cnt1++; /* cnt1 = U32 where to insert new ID */ } /* cnt2 = U16 where to insert new ID */ if (cnt1 > bound1) { /* Adding ID as last entry */ if ((CAN_std_cnt & 0x0001) == 0)/* Even number of IDs exists */ ptrcan_afram->mask[cnt1] = 0x0000FFFF | (id << 16); else /* Odd number of IDs exists */ ptrcan_afram->mask[cnt1] = (ptrcan_afram->mask[cnt1] & 0xFFFF0000) | id; } else { buf0 = ptrcan_afram->mask[cnt1];/* Remember current entry */ if ((cnt2 & 0x0001) == 0) /* Insert new mask to even address */ buf1 = (id << 16) | (buf0 >> 16); else /* Insert new mask to odd address */ buf1 = (buf0 & 0xFFFF0000) | id; ptrcan_afram->mask[cnt1] = buf1;/* Insert mask */ bound1 = CAN_std_cnt >> 1; /* Move all remaining standard mask entries one place up */ while (cnt1 < bound1) { cnt1++; buf1 = ptrcan_afram->mask[cnt1]; ptrcan_afram->mask[cnt1] = (buf1 >> 16) | (buf0 << 16); buf0 = buf1; } if ((CAN_std_cnt & 0x0001) == 0)/* Even number of IDs exists */ ptrcan_afram->mask[cnt1] = (ptrcan_afram->mask[cnt1] & 0xFFFF0000) | (0x0000FFFF); } } CAN_std_cnt++; } else { /* Add mask for extended identifiers */ id |= (ctrl0) << 29; /* Add controller number */ cnt1 = ((CAN_std_cnt + 1) >> 1); cnt2 = 0; while (cnt2 < CAN_ext_cnt) { /* Loop through extended existing masks*/ if (ptrcan_afram->mask[cnt1] > id) break; cnt1++; /* cnt1 = U32 where to insert new mask */ cnt2++; } buf0 = ptrcan_afram->mask[cnt1]; /* Remember current entry */ ptrcan_afram->mask[cnt1] = id; /* Insert mask */ CAN_ext_cnt++; bound1 = CAN_ext_cnt - 1; /* Move all remaining extended mask entries one place up */ while (cnt2 < bound1) { cnt1++; cnt2++; buf1 = ptrcan_afram->mask[cnt1]; ptrcan_afram->mask[cnt1] = buf0; buf0 = buf1; } } /* Calculate std ID start address (buf0) and ext ID start address (buf1) */ buf0 = ((CAN_std_cnt + 1) >> 1) << 2; buf1 = buf0 + (CAN_ext_cnt << 2); /* Setup acceptance filter pointers */ ptrcan_af->SFF_sa = 0; ptrcan_af->SFF_GRP_sa = buf0; ptrcan_af->EFF_sa = buf0; ptrcan_af->EFF_GRP_sa = buf1; ptrcan_af->ENDofTable = buf1; ptrcan_af->AFMR = 0x00000000; /* Use acceptance filter */ return CAN_OK; } /*--------------------------- CAN_hw_tx_object ------------------------------ * * This function has no usage on LPC2xxx, and so it does nothing * * Parameter: ctrl: Index of the hardware CAN controller (1 .. x) * ch: Ignored for LPC2xxx * id: CAN message identifier * CAN_FORMAT: Format of CAN identifier (standard or extended) * * Return: CAN_ERROR: Error code *---------------------------------------------------------------------------*/ CAN_ERROR CAN_hw_tx_object (U32 ctrl, U32 ch, CAN_FORMAT format) { return CAN_OK; } /************************* Interrupt Functions *******************************/ /*--------------------------- CAN_ISR --------------------------------------- * * CAN receive and transmit interrupt function for all controllers * Reads message from hardware registers and puts it into receive mailboxes * If there are messages in mailbox for transmit it writes it to hardware * and starts the transmission * * Parameter: none * * Return: none *---------------------------------------------------------------------------*/ static void CAN_ISR (void) __irq { CAN_msg *ptrmsg; U32 temp; /* If message is received and if mailbox isn't full read message from hardware and send it to message queue */ #if USE_CAN_CTRL1 == 1 if (CAN1GSR & 0x01) { if (os_mbx_check (MBX_rx_ctrl[0]) > 0) { ptrmsg = _alloc_box (CAN_mpool); CAN_hw_rd (1, ptrmsg); CAN1CMR = 0x04; /* Release receive buffer */ isr_mbx_send (MBX_rx_ctrl[0], ptrmsg); } } #endif #if USE_CAN_CTRL2 == 1 if (CAN2GSR & 0x01) { if (os_mbx_check (MBX_rx_ctrl[1]) > 0) { ptrmsg = _alloc_box (CAN_mpool); CAN_hw_rd (2, ptrmsg); CAN2CMR = 0x04; /* Release receive buffer */ isr_mbx_send (MBX_rx_ctrl[1], ptrmsg); } } #endif /* If there is message in mailbox ready for send, and if transmission hardware is ready, read the message from mailbox and send it */ #if USE_CAN_CTRL1 == 1 if (CAN1GSR & (1 << 3)) { if (isr_mbx_receive (MBX_tx_ctrl[0], (void **)&ptrmsg) != OS_R_OK) { CAN_hw_wr (1, ptrmsg); _free_box(CAN_mpool, ptrmsg); } else { isr_sem_send(wr_sem[0]); /* Return a token back to semaphore */ } } #endif #if USE_CAN_CTRL2 == 1 if (CAN2GSR & (1 << 3)) { if (isr_mbx_receive (MBX_tx_ctrl[1], (void **)&ptrmsg) != OS_R_OK) { CAN_hw_wr (2, ptrmsg); _free_box(CAN_mpool, ptrmsg); } else { isr_sem_send(wr_sem[1]); /* Return a token back to semaphore */ } } #endif /* Read from interrupt register to acknowledge interrupt */ #if USE_CAN_CTRL1 == 1 temp = ptrCAN1->CANICR; #endif #if USE_CAN_CTRL2 == 1 temp = ptrCAN2->CANICR; #endif VICVectAddr = 0xFFFFFFFF; /* Acknowledge Interrupt */ } /*---------------------------------------------------------------------------- * end of file *---------------------------------------------------------------------------*/