예제 #1
0
파일: can.c 프로젝트: kammce/SJSU-DEV-Linux
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
    }
}
예제 #2
0
파일: can.c 프로젝트: kammce/SJSU-DEV-Linux
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;
}
예제 #3
0
파일: em_can.c 프로젝트: sg-/mbed-os
/***************************************************************************//**
 * @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);
}
예제 #4
0
파일: can.c 프로젝트: kammce/SJSU-DEV-Linux
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;
}
예제 #5
0
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;
}
예제 #6
0
파일: can.c 프로젝트: kammce/SJSU-DEV-Linux
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;
}
예제 #7
0
파일: can.c 프로젝트: kammce/SJSU-DEV-Linux
uint16_t CAN_get_rx_dropped_count(can_t can)
{
    return CAN_VALID(can) ? CAN_STRUCT_PTR(can)->droppedRxMsgs : 0;
}
예제 #8
0
파일: can.c 프로젝트: kammce/SJSU-DEV-Linux
uint16_t CAN_get_rx_count(can_t can)
{
    return CAN_VALID(can) ? CAN_STRUCT_PTR(can)->rxMsgCount : 0;
}
예제 #9
0
파일: can.c 프로젝트: kammce/SJSU-DEV-Linux
uint16_t CAN_get_tx_watermark(can_t can)
{
    return CAN_VALID(can) ? CAN_STRUCT_PTR(can)->txQWatermark : 0;
}
예제 #10
0
파일: can.c 프로젝트: kammce/SJSU-DEV-Linux
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);
}
예제 #11
0
파일: can.c 프로젝트: kammce/SJSU-DEV-Linux
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);
}