void CAN_reset_bus(can_t can) { if (CAN_VALID(can)) { CAN_STRUCT_PTR(can)->pCanRegs->MOD = can_mod_reset; #if CAN_TESTING CAN_STRUCT_PTR(can)->pCanRegs->MOD = can_mod_selftest; #else CAN_STRUCT_PTR(can)->pCanRegs->MOD = can_mod_normal_tpm; #endif } }
bool CAN_tx (can_t can, can_msg_t *pCanMsg, uint32_t timeout_ms) { if (!CAN_VALID(can) || !pCanMsg || CAN_is_bus_off(can)) { return false; } bool ok = false; can_struct_t *pStruct = CAN_STRUCT_PTR(can); LPC_CAN_TypeDef *CANx = pStruct->pCanRegs; /* Try transmitting to one of the available buffers */ taskENTER_CRITICAL(); do { ok = CAN_tx_now(pStruct, pCanMsg); } while(0); taskEXIT_CRITICAL(); /* If HW buffer not available, then just queue the message */ if (!ok) { if (taskSCHEDULER_RUNNING == xTaskGetSchedulerState()) { ok = xQueueSend(pStruct->txQ, pCanMsg, OS_MS(timeout_ms)); } else { ok = xQueueSend(pStruct->txQ, pCanMsg, 0); } /* There is possibility that before we queued the message, we got interrupted * and all hw buffers were emptied meanwhile, and our queued message will now * sit in the queue forever until another Tx interrupt takes place. * So we dequeue it here if all are empty and send it over. */ taskENTER_CRITICAL(); do { can_msg_t msg; if (tx_all_avail == (CANx->SR & tx_all_avail) && xQueueReceive(pStruct->txQ, &msg, 0) ) { ok = CAN_tx_now(pStruct, &msg); } } while(0); taskEXIT_CRITICAL(); } return ok; }
/***************************************************************************//** * @brief * Initialize CAN. * * @param[in] can * Pointer to CAN peripheral register block. * * @param[in] init * Pointer to CAN initialization structure. ******************************************************************************/ void CAN_Init(CAN_TypeDef *can, const CAN_Init_TypeDef *init) { EFM_ASSERT(CAN_VALID(can)); CAN_Enable(can, false); can->CTRL = _CAN_CTRL_TEST_MASK; can->TEST = _CAN_TEST_RESETVALUE; if (init->resetMessages) { CAN_ResetMessages(can, 0); } can->CTRL = CAN_CTRL_INIT; CAN_SetBitTiming(can, init->bitrate, init->propagationTimeSegment, init->phaseBufferSegment1, init->phaseBufferSegment2, init->synchronisationJumpWidth); CAN_Enable(can, init->enable); }
bool CAN_rx (can_t can, can_msg_t *pCanMsg, uint32_t timeout_ms) { bool ok = false; if (CAN_VALID(can) && pCanMsg) { if (taskSCHEDULER_RUNNING == xTaskGetSchedulerState()) { ok = xQueueReceive(CAN_STRUCT_PTR(can)->rxQ, pCanMsg, OS_MS(timeout_ms)); } else { uint64_t msg_timeout = sys_get_uptime_ms() + timeout_ms; while (! (ok = xQueueReceive(CAN_STRUCT_PTR(can)->rxQ, pCanMsg, 0))) { if (sys_get_uptime_ms() > msg_timeout) { break; } } } } return ok; }
bool CAN_rx (can_t can, can_msg_t *pCanMsg, uint32_t timeout_ms) { bool ok = false; if (CAN_VALID(can) && pCanMsg) { if (taskSCHEDULER_RUNNING == xTaskGetSchedulerState()) { ok = xQueueReceive(g_can_rx_qs[CAN_INDEX(can)], pCanMsg, OS_MS(timeout_ms)); } else { uint64_t msg_timeout = sys_get_uptime_ms() + timeout_ms; while (! (ok = xQueueReceiveFromISR(g_can_rx_qs[CAN_INDEX(can)], pCanMsg, NULL))) { if (sys_get_uptime_ms() > msg_timeout) { break; } } } } return ok; }
bool CAN_fullcan_add_entry(can_t can, can_std_id_t id1, can_std_id_t id2) { /* Return if invalid CAN given */ if (!CAN_VALID(can)) { return false; } /* Check for enough room for more FullCAN entries * Each entry takes 2-byte entry, and 12-byte message RAM. */ const uint16_t existing_entries = CAN_fullcan_get_num_entries(); const uint16_t size_per_entry = sizeof(can_std_id_t) + sizeof(can_fullcan_msg_t); if ((existing_entries * size_per_entry) >= sizeof(LPC_CANAF_RAM->mask)) { return false; } /* Locate where we should write the next entry */ uint8_t *base = (uint8_t*) &(LPC_CANAF_RAM->mask[0]); uint8_t *next_entry_ptr = base + LPC_CANAF->SFF_sa; /* Copy the new entry into the RAM filter */ LPC_CANAF->AFMR = afmr_disabled; do { const uint32_t entries = ((uint32_t) id2.raw & UINT16_MAX) | ((uint32_t) id1.raw << 16); * (uint32_t*) (next_entry_ptr) = entries; /* The new start of Standard Frame Filter is after the two new entries */ const uint32_t new_sff_sa = LPC_CANAF->SFF_sa + sizeof(id1) + sizeof(id2); LPC_CANAF->SFF_sa = new_sff_sa; /* Next filters start at SFF_sa (they are disabled) */ LPC_CANAF->SFF_GRP_sa = new_sff_sa; LPC_CANAF->EFF_sa = new_sff_sa; LPC_CANAF->EFF_GRP_sa = new_sff_sa; LPC_CANAF->ENDofTable = new_sff_sa; } while(0); LPC_CANAF->AFMR = afmr_fullcan; return true; }
uint16_t CAN_get_rx_dropped_count(can_t can) { return CAN_VALID(can) ? CAN_STRUCT_PTR(can)->droppedRxMsgs : 0; }
uint16_t CAN_get_rx_count(can_t can) { return CAN_VALID(can) ? CAN_STRUCT_PTR(can)->rxMsgCount : 0; }
uint16_t CAN_get_tx_watermark(can_t can) { return CAN_VALID(can) ? CAN_STRUCT_PTR(can)->txQWatermark : 0; }
bool CAN_is_bus_off(can_t can) { const uint32_t bus_off_mask = (1 << 7); return (!CAN_VALID(can)) ? true : !! (CAN_STRUCT_PTR(can)->pCanRegs->GSR & bus_off_mask); }
bool CAN_init(can_t can, uint32_t baudrate_kbps, uint16_t rxq_size, uint16_t txq_size, can_void_func_t bus_off_cb, can_void_func_t data_ovr_cb) { if (!CAN_VALID(can)){ return false; } can_struct_t *pStruct = CAN_STRUCT_PTR(can); LPC_CAN_TypeDef *pCAN = pStruct->pCanRegs; bool failed = true; /* Enable CAN Power, and select the PINS * CAN1 is at P0.0, P0.1 and P0.21, P0.22 * CAN2 is at P0.4, P0.5 and P2.7, P2.8 * On SJ-One board, we have P0.0, P0.1, and P2.7, P2.8 */ if (can1 == can) { LPC_SC->PCONP |= can1_pconp_mask; LPC_PINCON->PINSEL0 &= ~(0xF << 0); LPC_PINCON->PINSEL0 |= (0x5 << 0); } else if (can2 == can){ LPC_SC->PCONP |= can2_pconp_mask; LPC_PINCON->PINSEL4 &= ~(0xF << 14); LPC_PINCON->PINSEL4 |= (0x5 << 14); } /* Create the queues with minimum size of 1 to avoid NULL pointer reference */ if (!pStruct->rxQ) { pStruct->rxQ = xQueueCreate(rxq_size ? rxq_size : 1, sizeof(can_msg_t)); } if (!pStruct->txQ) { pStruct->txQ = xQueueCreate(txq_size ? txq_size : 1, sizeof(can_msg_t)); } /* The CAN dividers must all be the same for both CANs * Set the dividers of CAN1, CAN2, ACF to CLK / 1 */ lpc_pclk(pclk_can1, clkdiv_1); lpc_pclk(pclk_can2, clkdiv_1); lpc_pclk(pclk_can_flt, clkdiv_1); pCAN->MOD = can_mod_reset; pCAN->IER = 0x0; // Disable All CAN Interrupts pCAN->GSR = 0x0; // Clear error counters pCAN->CMR = 0xE; // Abort Tx, release Rx, clear data over-run /** * About the AFMR register : * B0 B1 * Filter Mode | AccOff bit | AccBP bit | CAN Rx interrupt * Off Mode 1 0 No messages accepted * Bypass Mode X 1 All messages accepted * FullCAN 0 0 HW acceptance filtering */ LPC_CANAF->AFMR = afmr_disabled; // Clear pending interrupts and the CAN Filter RAM LPC_CANAF_RAM->mask[0] = pCAN->ICR; memset((void*)&(LPC_CANAF_RAM->mask[0]), 0, sizeof(LPC_CANAF_RAM->mask)); /* Zero out the filtering registers */ LPC_CANAF->SFF_sa = 0; LPC_CANAF->SFF_GRP_sa = 0; LPC_CANAF->EFF_sa = 0; LPC_CANAF->EFF_GRP_sa = 0; LPC_CANAF->ENDofTable = 0; /* Do not accept any messages until CAN filtering is enabled */ LPC_CANAF->AFMR = afmr_disabled; /* Set the baud-rate. You can verify the settings by visiting: * http://www.kvaser.com/en/support/bit-timing-calculator.html */ do { const uint32_t baudDiv = sys_get_cpu_clock() / (1000 * baudrate_kbps); const uint32_t SJW = 3; const uint32_t SAM = 0; uint32_t BRP = 0, TSEG1 = 0, TSEG2 = 0, NT = 0; /* Calculate suitable nominal time value * NT (nominal time) = (TSEG1 + TSEG2 + 3) * NT <= 24 * TSEG1 >= 2*TSEG2 */ failed = true; for(NT=24; NT > 0; NT-=2) { if ((baudDiv % NT)==0) { BRP = baudDiv / NT - 1; NT--; TSEG2 = (NT/3) - 1; TSEG1 = NT -(NT/3) - 1; failed = false; break; } } if (!failed) { pCAN->BTR = (SAM << 23) | (TSEG2<<20) | (TSEG1<<16) | (SJW<<14) | BRP; // CANx->BTR = 0x002B001D; // 48Mhz 100Khz } } while (0); /* If everything okay so far, enable the CAN interrupts */ if (!failed) { /* At minimum, we need Rx/Tx interrupts */ pCAN->IER = (intr_rx | intr_all_tx); /* Enable BUS-off interrupt and callback if given */ if (bus_off_cb) { pStruct->bus_error = bus_off_cb; pCAN->IER |= g_can_bus_err_intr; } /* Enable data-overrun interrupt and callback if given */ if (data_ovr_cb) { pStruct->data_overrun = data_ovr_cb; pCAN->IER |= intr_ovrn; } /* Finally, enable the actual CPU core interrupt */ vTraceSetISRProperties(CAN_IRQn, "CAN", IP_can); NVIC_EnableIRQ(CAN_IRQn); } /* return true if all is well */ return (false == failed); }