| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060 |
- /*
- * Copyright : (C) 2022 Phytium Information Technology, Inc.
- * All Rights Reserved.
- *
- * This program is OPEN SOURCE software: you can redistribute it and/or modify it
- * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
- * either version 1.0 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the Phytium Public License for more details.
- *
- *
- * FilePath: fcan.c
- * Date: 2021-04-29 10:21:53
- * LastEditTime: 2022-02-18 08:29:20
- * Description: This files is for
- *
- * Modify History:
- * Ver Who Date Changes
- * ----- ------ -------- --------------------------------------
- */
- #include "string.h"
- #include <limits.h>
- #include <stdlib.h>
- #include "fkernel.h"
- #include "fcan.h"
- #include "fcan_hw.h"
- #include "fassert.h"
- #include "fdebug.h"
- #include "fswap.h"
- #include "fparameters.h"
- #include "fsleep.h"
- #define FT_CAN_DEBUG_TAG "FT_CAN"
- #define FCAN_DEBUG(format, ...) FT_DEBUG_PRINT_D(FT_CAN_DEBUG_TAG, format, ##__VA_ARGS__)
- #define FCAN_INFO(format, ...) FT_DEBUG_PRINT_I(FT_CAN_DEBUG_TAG, format, ##__VA_ARGS__)
- #define FCAN_WARN(format, ...) FT_DEBUG_PRINT_W(FT_CAN_DEBUG_TAG, format, ##__VA_ARGS__)
- #define FCAN_ERROR(format, ...) FT_DEBUG_PRINT_E(FT_CAN_DEBUG_TAG, format, ##__VA_ARGS__)
- typedef struct
- {
- u32 tseg1_min; /* Time segement 1 = prop_seg + phase_seg1 */
- u32 tseg1_max;
- u32 tseg2_min; /* Time segement 2 = phase_seg2 */
- u32 tseg2_max;
- u32 sjw_max; /* Synchronisation jump width */
- u32 brp_min; /* Bit-rate prescaler */
- u32 brp_max;
- u32 brp_inc;
- } FCanBittimingConst;
- /* 仲裁段速率默认值 */
- static const FCanBittimingConst FCanArbBitConst =
- {
- .tseg1_min = FCAN_ARB_TSEG1_MIN, /* Time segement 1 = prop_seg + phase_seg1 */
- .tseg1_max = FCAN_ARB_TSEG1_MAX,
- .tseg2_min = FCAN_ARB_TSEG2_MIN, /* Time segement 2 = phase_seg2 */
- .tseg2_max = FCAN_ARB_TSEG2_MAX,
- .sjw_max = FCAN_ARB_SJW_MAX, /* Synchronisation jump width */
- .brp_min = FCAN_ARB_BRP_MIN, /* Bit-rate prescaler */
- .brp_max = FCAN_ARB_BRP_MAX,
- .brp_inc = FCAN_ARB_BRP_INC,
- };
- /* 数据段速率默认值 */
- static const FCanBittimingConst FCanDataBitConst =
- {
- .tseg1_min = FCAN_DATA_TSEG1_MIN, /* Time segement 1 = prop_seg + phase_seg1 */
- .tseg1_max = FCAN_DATA_TSEG1_MAX,
- .tseg2_min = FCAN_DATA_TSEG2_MIN, /* Time segement 2 = phase_seg2 */
- .tseg2_max = FCAN_DATA_TSEG2_MAX,
- .sjw_max = FCAN_DATA_SJW_MAX, /* Synchronisation jump width */
- .brp_min = FCAN_DATA_BRP_MIN, /* Bit-rate prescaler */
- .brp_max = FCAN_DATA_BRP_MAX,
- .brp_inc = FCAN_DATA_BRP_INC,
- };
- /* calculate the can sample point */
- static s32 FCanUpdateSamplePoint(const FCanBittimingConst *btc,
- u32 sample_point_nominal, u32 tseg,
- u32 *tseg1_ptr, u32 *tseg2_ptr,
- u32 *sample_point_error_ptr)
- {
- u32 sample_point_error, best_sample_point_error = UINT_MAX;
- u32 sample_point, best_sample_point = 0;
- u32 tseg1, tseg2;
- s32 i;
- for (i = 0; i <= 1; i++)
- {
- tseg2 = tseg + CAN_CALC_SYNC_SEG - (sample_point_nominal * (tseg + CAN_CALC_SYNC_SEG)) / 1000 - i;
- tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
- tseg1 = tseg - tseg2;
- if (tseg1 > btc->tseg1_max)
- {
- tseg1 = btc->tseg1_max;
- tseg2 = tseg - tseg1;
- }
- sample_point = 1000 * (tseg + CAN_CALC_SYNC_SEG - tseg2) / (tseg + CAN_CALC_SYNC_SEG);
- sample_point_error = abs(sample_point_nominal - sample_point);
- if ((sample_point <= sample_point_nominal) && (sample_point_error < best_sample_point_error))
- {
- best_sample_point = sample_point;
- best_sample_point_error = sample_point_error;
- *tseg1_ptr = tseg1;
- *tseg2_ptr = tseg2;
- }
- }
- if (sample_point_error_ptr)
- *sample_point_error_ptr = best_sample_point_error;
- return best_sample_point;
- }
- /**
- * @name: FCanCalcBittiming
- * @msg: This routine calculate Bit timing
- * @param {structFCanBittiming} *bt_p is is a structure that contains the CAN baud rate configuration parameter , The user needs to fill in the baudrate first
- * @param {u32} target_baudrate, parameters of target baudrate
- * @param {u32} target_sample_point, parameters of target sample point, 0 means the general configuration is used
- * @param {FCanSegmentType} target_segment, specifies which target is to be selected. followed by FCAN_ARB_SEGMENT or FCAN_DATA_SEGMENT
- * @return err code information, FCAN_SUCCESS indicates success,others indicates failed
- */
- static FError FCanCalcBittiming(FCanBaudrateConfig *bt_p, u32 target_baudrate, u32 target_sample_point, FCanSegmentType target_segment)
- {
- u32 baudrate; /* current baudrate */
- u32 baudrate_error; /* difference between current and nominal value */
- u32 best_baudrate_error = UINT_MAX;
- u32 sample_point_error; /* difference between current and nominal value */
- u32 best_sample_point_error = UINT_MAX;
- u32 sample_point_nominal; /* nominal sample point */
- u32 best_tseg = 0; /* current best value for tseg */
- u32 best_brp = 0; /* current best value for brp */
- u32 brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
- u64 v64;
- u32 reg_val;
- const FCanBittimingConst *btc;
- FCanBaudrateConfig *bt = bt_p;
- FASSERT(bt_p != NULL);
- FASSERT(target_segment < FCAN_SEGMENT_TYPE_NUM);
- if (target_segment == FCAN_DATA_SEGMENT)
- {
- btc = &FCanDataBitConst;
- }
- else
- {
- btc = &FCanArbBitConst;
- }
- if (target_sample_point)
- {
- sample_point_nominal = target_sample_point;
- }
- else
- {
- if (target_baudrate > 1000000)
- sample_point_nominal = 650;
- else if (target_baudrate > 800000)
- sample_point_nominal = 750;
- else if (target_baudrate > 500000)
- sample_point_nominal = 800;
- else
- sample_point_nominal = 875;
- }
- for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
- tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--)
- {
- tsegall = CAN_CALC_SYNC_SEG + tseg / 2;
- /* Compute all possible tseg choices (tseg=tseg1+tseg2) */
- brp = FCAN_REF_CLOCK / (tsegall * target_baudrate) + tseg % 2;
- /* choose brp step which is possible in system */
- brp = (brp / btc->brp_inc) * btc->brp_inc;
- if ((brp < btc->brp_min) || (brp > btc->brp_max))
- continue;
- baudrate = FCAN_REF_CLOCK / (brp * tsegall);
- baudrate_error = abs(target_baudrate - baudrate);
- /* tseg brp biterror */
- if (baudrate_error > best_baudrate_error)
- continue;
- /* reset sample point error if we have a better baudrate */
- if (baudrate_error < best_baudrate_error)
- best_sample_point_error = UINT_MAX;
- FCanUpdateSamplePoint(btc, sample_point_nominal, tseg / 2, &tseg1, &tseg2, &sample_point_error);
- FCAN_DEBUG("target_segment=%d, brp=%d, tseg=%d, tseg1=%d, tseg2=%d, sample_point_nominal=%d",
- target_segment, brp, tseg, tseg1, tseg2, sample_point_nominal);
- u32 prop_seg = tseg1 / 2;
- u32 phase_seg1 = tseg1 - prop_seg;
- u32 phase_seg2 = tseg2;
- u32 sjw = 1;
- /* Setting Baud Rate prescalar value in BRPR Register */
- reg_val = (brp - 1) << 16;
- reg_val |= (prop_seg - 1) << 2;
- reg_val |= (phase_seg1 - 1) << 5;
- reg_val |= (phase_seg2 - 1) << 8;
- reg_val |= (sjw - 1);
- FCAN_DEBUG("reg_val=%#x\n", reg_val);
- if (sample_point_error > best_sample_point_error)
- continue;
- best_sample_point_error = sample_point_error;
- best_baudrate_error = baudrate_error;
- best_tseg = tseg / 2;
- best_brp = brp;
- if (baudrate_error == 0 && sample_point_error == 0)
- break;
- }
- if (best_baudrate_error)
- {
- /* Error in one-tenth of a percent */
- v64 = (u64)best_baudrate_error * 1000;
- do_div(v64, target_baudrate);
- baudrate_error = (u32)v64;
- if (baudrate_error > CAN_CALC_MAX_ERROR)
- {
- FCAN_ERROR("baudrate error");
- return FCAN_FAILURE;
- }
- }
- /* real sample point */
- FCanUpdateSamplePoint(btc, sample_point_nominal, best_tseg,
- &tseg1, &tseg2, NULL);
- FCAN_DEBUG("tseg1=%d, tseg2=%d, sample_point_nominal=%d", tseg1, tseg2, sample_point_nominal);
- bt->prop_seg = tseg1 / 2;
- bt->phase_seg1 = tseg1 - bt->prop_seg;
- bt->phase_seg2 = tseg2;
- /* check for sjw user settings */
- if (!bt->sjw || !btc->sjw_max)
- {
- bt->sjw = 1;
- }
- else
- {
- /* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
- if (bt->sjw > btc->sjw_max)
- bt->sjw = btc->sjw_max;
- /* bt->sjw must not be higher than tseg2 */
- if (tseg2 < bt->sjw)
- bt->sjw = tseg2;
- }
- bt->brp = best_brp;
- /* real baudrate */
- if (target_baudrate != FCAN_REF_CLOCK / (bt->brp * (CAN_CALC_SYNC_SEG + tseg1 + tseg2)))
- {
- FCAN_ERROR("target baudrate calculate timing failed");
- return FCAN_FAILURE;
- }
- FCAN_DEBUG("bt->prop_seg=%d, bt->phase_seg1=%d, bt->phase_seg2=%d, bt->sjw=%d, bt->brp=%d",
- bt->prop_seg, bt->phase_seg1, bt->phase_seg2, bt->sjw, bt->brp);
- return FCAN_SUCCESS;
- }
- static u32 FCanGetDlcLen(u32 dlc)
- {
- u32 dlc_len = 0;
- if (dlc == 0)
- {
- dlc_len = 8;
- }
- switch (dlc)
- {
- case 1:
- dlc_len = 1;
- break;
- case 2:
- dlc_len = 2;
- break;
- case 3:
- dlc_len = 3;
- break;
- case 4:
- dlc_len = 4;
- break;
- case 5:
- dlc_len = 5;
- break;
- case 6:
- dlc_len = 6;
- break;
- case 7:
- dlc_len = 7;
- break;
- case 8:
- dlc_len = 8;
- break;
- case 9:
- dlc_len = 12;
- break;
- case 10:
- dlc_len = 16;
- break;
- case 11:
- dlc_len = 20;
- break;
- case 12:
- dlc_len = 24;
- break;
- case 13:
- dlc_len = 32;
- break;
- case 14:
- dlc_len = 48;
- break;
- case 15:
- dlc_len = 64;
- break;
- default :
- dlc_len = 0;
- break;
- }
- return dlc_len;
- }
- static u32 FCanSetDlcLen(u32 len)
- {
- if (len <= 8)
- {
- return len;
- }
- else if (len <= 12)
- {
- return 9;
- }
- else if (len <= 16)
- {
- return 10;
- }
- else if (len <= 20)
- {
- return 11;
- }
- else if (len <= 24)
- {
- return 12;
- }
- else if (len <= 32)
- {
- return 13;
- }
- else if (len <= 48)
- {
- return 14;
- }
- else if (len <= 64)
- {
- return 15;
- }
- else
- {
- return 0;
- }
- }
- /**
- * @name: FCanReset
- * @msg: reset a specific can instance
- * @param {FCanCtrl} *pctrl, instance of FCan controller
- * @return {*}
- */
- void FCanReset(FCanCtrl *instance_p)
- {
- u32 reg_value;
- FCanConfig *config_p;
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- config_p = &instance_p->config;
- FCAN_WRITE_REG32(config_p->base_address, FCAN_CTRL_OFFSET, 0);
- reg_value = FCAN_READ_REG32(config_p->base_address, FCAN_CTRL_OFFSET);
- if (reg_value & FCAN_CTRL_XFER_MASK)
- {
- FCAN_ERROR("FT can is not in configration mode\n");
- return;
- }
- /* reset can */
- FCAN_WRITE_REG32(config_p->base_address, FCAN_CTRL_OFFSET, FCAN_CTRL_RST_MASK);
- }
- /**
- * @name: FCanDeInitialize
- * @msg: Deinitializes a specific can instance
- * @param {FCanCtrl} *pctrl, instance of FCan controller
- * @return {*}
- */
- void FCanDeInitialize(FCanCtrl *instance_p)
- {
- FASSERT(instance_p);
- instance_p->is_ready = 0;
- memset(instance_p, 0, sizeof(*instance_p));
- return;
- }
- /**
- * @name: FCanCfgInitialize
- * @msg: Initializes a specific instance such that it is ready to be used.
- * @param {FCanCtrl} *instance_p, instance of FCanCtrl controller
- * @param {FCanConfig} *input_config_p, configuration parameters of FCanCtrl
- * @return err code information, FCAN_SUCCESS indicates success,others indicates failed
- */
- FError FCanCfgInitialize(FCanCtrl *instance_p, const FCanConfig *input_config_p)
- {
- FASSERT(instance_p != NULL);
- FASSERT(input_config_p != NULL);
- FError ret = FCAN_SUCCESS;
- /*
- * If the device is started, disallow the initialize and return a Status
- * indicating it is started. This allows the user to de-initialize the device
- * and reinitialize, but prevents a user from inadvertently
- * initializing.
- */
- if (FT_COMPONENT_IS_READY == instance_p->is_ready)
- {
- FCAN_WARN("device is already initialized!!!");
- }
- /*Set default values and configuration data */
- FCanDeInitialize(instance_p);
- instance_p->config = *input_config_p;
- instance_p->is_ready = FT_COMPONENT_IS_READY;
- FCanReset(instance_p);
- return ret;
- }
- /**
- * @name: FCanStatusGet
- * @msg: read can status, include transfer status, error and fifo count.
- * @param {FCanCtrl} *instance_p, pointer to a FCanCtrl structure that contains
- * the configuration information for the specified can module.
- * @param {FCanStatus} *status_p, pointer to can status, include send and receive, error and fifo count .
- * @return err code information, FCAN_SUCCESS indicates success,others indicates failed.
- */
- FError FCanStatusGet(FCanCtrl *instance_p, FCanStatus *status_p)
- {
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- FASSERT(status_p != NULL);
- uintptr base_address = instance_p->config.base_address;
- u32 reg_val = 0;
- reg_val = FCAN_READ_REG32(base_address, FCAN_XFER_STS_OFFSET);
- status_p->xfer_status.xfers = FCAN_XFER_STS_XFERS_GET(reg_val);
- status_p->xfer_status.rs = FCAN_XFER_STS_RS_GET(reg_val);
- status_p->xfer_status.ts = FCAN_XFER_STS_TS_GET(reg_val);
- status_p->xfer_status.fies = FCAN_XFER_STS_FIES_GET(reg_val);
- status_p->xfer_status.fras = FCAN_XFER_STS_FRAS_GET(reg_val);
- reg_val = FCAN_READ_REG32(base_address, FCAN_ERR_CNT_OFFSET);
- status_p->rx_err_cnt = FCAN_ERR_CNT_RFN_GET(reg_val);
- status_p->tx_err_cnt = FCAN_ERR_CNT_TFN_GET(reg_val);
- reg_val = FCAN_READ_REG32(base_address, FCAN_FIFO_CNT_OFFSET);
- status_p->tx_fifo_cnt = FCAN_FIFO_CNT_TFN_GET(reg_val);
- status_p->rx_fifo_cnt = FCAN_FIFO_CNT_RFN_GET(reg_val);
- return FCAN_SUCCESS;
- }
- /**
- * @name: FCanRecv
- * @msg: receive can message by specific can instance.
- * @param {FCanCtrl} *instance_p, pointer to a FCanCtrl structure that contains
- * the configuration information for the specific can module.
- * @param {FCanFrame} *frame_p, can message receive struct.
- * @return err code information, FCAN_SUCCESS indicates success,others indicates failed.
- */
- FError FCanRecv(FCanCtrl *instance_p, FCanFrame *frame_p)
- {
- u32 canid;
- u32 dlc;
- int i = 0, j = 0;
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- FASSERT(frame_p != NULL);
- uintptr base_address = instance_p->config.base_address;
- memset(frame_p, 0, sizeof(FCanFrame));
- /* Read a frame from Phytium CAN */
- canid = FCAN_READ_REG32(base_address, FCAN_RX_FIFO_OFFSET);
- /* if canid is big-endian ,use swap change to little-endian */
- canid = be32_to_cpu(canid);
- FCAN_DEBUG("FCanRecv canid = %#x\n", canid);
- /* identifier extension */
- if (canid & FCAN_IDR_IDE_MASK)
- {
- dlc = FCAN_READ_REG32(base_address, FCAN_RX_FIFO_OFFSET);
- dlc = be32_to_cpu(dlc);
- FCAN_DEBUG("FCanRecv dlc = %#x\n", dlc);
- if (dlc & FTCANFD_ID2_FDL_MASK)
- {
- if (dlc & FTCANFD_ID2_BRS_MASK)
- {
- frame_p->flags |= CANFD_BRS;
- }
- if (dlc & FTCANFD_ID2_ESI_MASK)
- {
- frame_p->flags |= CANFD_ESI;
- }
- dlc = FTCANFD_ID2_EDLC_GET(dlc);
- }
- else
- {
- dlc = FCAN_IDR_EDLC_GET(dlc);
- }
- frame_p->canid = FCAN_IDR_ID1_GET(canid) << FCAN_ACC_IDN_SHIFT;
- frame_p->canid |= FCAN_IDR_ID2_GET(canid);
- frame_p->canid |= CAN_EFF_FLAG;
- if (canid & FCAN_IDR_RTR_MASK)
- {
- frame_p->canid |= CAN_RTR_FLAG;
- }
- }
- else
- {
- if (canid & FTCANFD_ID1_FDL_MASK)
- {
- if (canid & FTCANFD_ID1_BRS_MASK)
- {
- frame_p->flags |= CANFD_BRS;
- }
- if (canid & FTCANFD_ID1_ESI_MASK)
- {
- frame_p->flags |= CANFD_ESI;
- }
- dlc = FTCANFD_ID1_SDLC_GET(canid);
- }
- else
- {
- dlc = FCAN_IDR_DLC_GET(canid);
- }
- /* The received frame is a standard format frame */
- frame_p->canid = FCAN_IDR_ID1_GET(canid);
- if (canid & FCAN_IDR_SRR_MASK)
- {
- frame_p->canid |= CAN_RTR_FLAG;
- }
- }
- frame_p->candlc = FCanGetDlcLen(dlc);
- FCAN_DEBUG("FCanRecv frame_p->candlc = %d\n", frame_p->candlc);
- if (!(frame_p->canid & CAN_RTR_FLAG))
- {
- j = 0;
- for (i = frame_p->candlc; i > 0; i -= 4)
- {
- *(u32 *)(frame_p->data + j) = FCAN_READ_REG32(base_address, FCAN_RX_FIFO_OFFSET);
- j += 4;
- }
- if (i > 0)
- {
- *(u32 *)(frame_p->data + j) = FCAN_READ_REG32(base_address, FCAN_RX_FIFO_OFFSET);
- }
- }
- return FCAN_SUCCESS;
- }
- /**
- * @name: FCanSend
- * @msg: send can message by specific can instance.
- * @param {FCanCtrl} *instance_p, pointer to a FCanCtrl structure that contains
- * the configuration information for the specific can module.
- * @param {FCanFrame} *frame_p, can message send struct.
- * @return err code information, FCAN_SUCCESS indicates success,others indicates failed.
- */
- FError FCanSend(FCanCtrl *instance_p, FCanFrame *frame_p)
- {
- u32 id, dlc;
- int i = 0, j = 0;
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- uintptr base_address = instance_p->config.base_address;
- while (FCAN_TX_FIFO_FULL(instance_p));
- u32 can_send_dlc = FCanSetDlcLen(frame_p->candlc);
- if (frame_p->canid & CAN_EFF_FLAG)
- {
- /* Extended CAN id format */
- id = FCAN_IDR_ID2_GET(frame_p->canid & CAN_EFF_MASK);
- id |= FCAN_IDR_ID1_GET((frame_p->canid & CAN_EFF_MASK) >>
- (CAN_EFF_ID_BITS - CAN_SFF_ID_BITS));
- /* The substibute remote TX request bit should be "1"
- * for extended frames as in the Phytium CAN datasheet
- */
- id |= FCAN_IDR_IDE_MASK | FCAN_IDR_SRR_MASK;
- if (frame_p->canid & CAN_RTR_FLAG)
- {
- id |= FCAN_IDR_RTR_MASK;
- }
- if (instance_p->use_canfd == TRUE)
- {
- dlc = can_send_dlc << FCANFD_IDR_EDLC_SHIFT;
- dlc |= FTCANFD_ID2_FDL_MASK;
- /* enable brs-Bit Rate Switch */
- frame_p->flags |= CANFD_BRS;
- if (frame_p->flags & CANFD_BRS)
- {
- dlc |= FTCANFD_ID2_BRS_MASK;
- }
- if (frame_p->flags & CANFD_ESI)
- {
- dlc |= FTCANFD_ID2_ESI_MASK;
- }
- }
- else
- {
- dlc = can_send_dlc << FCAN_IDR_EDLC_SHIFT;
- }
- FCAN_DEBUG("FCanSend id = %#x\n", id);
- FCAN_DEBUG("FCanSend dlc = %#x\n", dlc);
- FCAN_WRITE_REG32(base_address, FCAN_TX_FIFO_OFFSET, be32_to_cpu(id));
- FCAN_WRITE_REG32(base_address, FCAN_TX_FIFO_OFFSET, be32_to_cpu(dlc));
- }
- else
- {
- /* Standard CAN id format */
- id = FCAN_IDR_ID1_GET(frame_p->canid & CAN_SFF_MASK);
- if (frame_p->canid & CAN_RTR_FLAG)
- id |= FCAN_IDR_SRR_MASK;
- FCAN_DEBUG("instance_p->use_canfd = %d, can_send_dlc = %d \n",
- instance_p->use_canfd, can_send_dlc);
- if (instance_p->use_canfd == TRUE)
- {
- dlc = ((can_send_dlc << FCANFD_IDR1_SDLC_SHIFT) | FTCANFD_IDR_PAD_MASK);
- dlc |= FTCANFD_ID1_FDL_MASK;
- /* enable brs-Bit Rate Switch */
- frame_p->flags |= CANFD_BRS;
- if (frame_p->flags & CANFD_BRS)
- {
- dlc |= FTCANFD_ID1_BRS_MASK;
- }
- if (frame_p->flags & CANFD_ESI)
- {
- dlc |= FTCANFD_ID1_ESI_MASK;
- }
- }
- else
- {
- dlc = ((can_send_dlc << FCAN_IDR_SDLC_SHIFT) | FCAN_IDR_PAD_MASK);
- }
- id |= dlc;
- FCAN_DEBUG("can_send id = %#x\n", id);
- FCAN_WRITE_REG32(base_address, FCAN_TX_FIFO_OFFSET, be32_to_cpu(id));
- }
- if (!(frame_p->canid & CAN_RTR_FLAG))
- {
- j = 0;
- FCAN_DEBUG("frame_p->canid=%#x, frame_p->candlc = %d\n", frame_p->canid, frame_p->candlc);
- for (i = frame_p->candlc; i > 0; i -= 4)
- {
- FCAN_WRITE_REG32(base_address, FCAN_TX_FIFO_OFFSET, *(u32 *)(frame_p->data + j));
- j += 4;
- }
- if (i > 0)
- {
- FCAN_WRITE_REG32(base_address, FCAN_TX_FIFO_OFFSET, *(u32 *)(frame_p->data + j));
- }
- }
- /* triggers tranmission */
- FCAN_CLEARBIT(base_address, FCAN_CTRL_OFFSET, FCAN_CTRL_XFER_MASK);
- FCAN_SETBIT(base_address, FCAN_CTRL_OFFSET, FCAN_CTRL_TXREQ_MASK | FCAN_CTRL_XFER_MASK);
- return FCAN_SUCCESS;
- }
- /**
- * @name: FCan_SetTiming
- * @msg: This routine sets Bit time
- * @param {FCanCtrl} *instance_p is a pointer to the FCanCtrl instance.
- * @param {FCanBaudrateConfig} *bittiming_p, parameters of arbitration or data segment baudrate
- * @param {FCanSegmentType} target_segment, specifies which target is to be selected. followed by FCAN_ARB_SEGMENT or FCAN_DATA_SEGMENT
- * @out param:
- * @return {*}
- */
- static FError FCanSetTiming(FCanCtrl *instance_p, FCanBaudrateConfig *bittiming_p, FCanSegmentType target_segment)
- {
- u32 reg_val = 0;
- u32 transfer_enable;
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- FASSERT(target_segment < FCAN_SEGMENT_TYPE_NUM);
- uintptr base_address = instance_p->config.base_address;
- FASSERT(bittiming_p->brp != 0);
- FASSERT(bittiming_p->prop_seg != 0);
- FASSERT(bittiming_p->phase_seg1 != 0);
- FASSERT(bittiming_p->phase_seg2 != 0);
- FCAN_DEBUG("brp=%d, prop_seg=%d, phase_seg1=%d, phase_seg2=%d, sjw=%d",
- bittiming_p->brp, bittiming_p->prop_seg, bittiming_p->phase_seg1,
- bittiming_p->phase_seg2, bittiming_p->sjw);
- /* Setting Baud Rate prescalar value in BRPR Register */
- reg_val = (bittiming_p->brp - 1) << 16;
- reg_val |= (bittiming_p->prop_seg - 1) << 2;
- reg_val |= (bittiming_p->phase_seg1 - 1) << 5;
- reg_val |= (bittiming_p->phase_seg2 - 1) << 8;
- reg_val |= (bittiming_p->sjw - 1);
- transfer_enable = (FCAN_READ_REG32(base_address, FCAN_CTRL_OFFSET) & FCAN_CTRL_XFER_MASK);
- if (transfer_enable)
- {
- FCAN_CLEARBIT(base_address, FCAN_CTRL_OFFSET, FCAN_CTRL_XFER_MASK);
- }
- if (reg_val)
- {
- if (target_segment == FCAN_DATA_SEGMENT)
- FCAN_WRITE_REG32(base_address, FCAN_DAT_RATE_CTRL_OFFSET, reg_val);
- else
- FCAN_WRITE_REG32(base_address, FCAN_ARB_RATE_CTRL_OFFSET, reg_val);
- }
- else
- {
- FCAN_ERROR("FCanSetTiming reg_val failed");
- return FCAN_FAILURE;
- }
- return FCAN_SUCCESS;
- }
- /**
- * @name: FCanBaudrateSet
- * @msg: Set the fcan baudrate by FCanBaudrateConfig parameters.
- * @param {FCanCtrl} *instance_p, instance of FCanCtrl controller
- * @param {FCanBaudrateConfig} *baudrate_p, parameters of arbitration or data segment baudrate
- * include baudrate, parameters of target baudrate
- * include sample_point, parameters of target sample point, 0 means the general configuration is used.
- * The value is the percentage of sampling points multiplied by 1000.
- * For example, if sample point is 0.75, set target_sample_point = 750.
- * Or manual config baudrate parameters.
- * @param {FCanSegmentType} segment, specifies data segment or arbitration segment is selected. followed by FCAN_ARB_SEGMENT or FCAN_DATA_SEGMENT
- * @return err code information, FQSPI_SUCCESS indicates success,others indicates failed
- * @note this function is to set arb and data segment baudrate, according to the prop_seg,
- * phase_seg1, phase_seg2 ,brp and sjw parameters, users can use this function to set can baudrate.
- * A formula to calculate baudrate is:
- * baudrate = FCAN_REF_CLOCK/(brp*(sjw+prop_seg+phase_seg1++phase_seg2))
- * sample point = (sjw+prop_seg+phase_seg1)/(sjw+prop_seg+phase_seg1++phase_seg2)
- * Recommended sample point :
- * 75.0% : baudrate > 800000
- * 80.0% : baudrate > 500000
- * 87.5% : baudrate <= 500000
- */
- FError FCanBaudrateSet(FCanCtrl *instance_p, FCanBaudrateConfig *baudrate_p)
- {
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- FCanSegmentType segment = baudrate_p->segment;
- FASSERT(segment < FCAN_SEGMENT_TYPE_NUM);
- u32 baudrate = baudrate_p->baudrate;
- u32 sample_point = baudrate_p->sample_point;
- if (baudrate_p->auto_calc == TRUE)
- {
- #if defined(CONFIG_TARGET_F2000_4) || defined(CONFIG_TARGET_D2000)
- if ((segment == FCAN_ARB_SEGMENT) && ((baudrate > FCAN_BAUDRATE_1000K) || (baudrate < FCAN_BAUDRATE_50K)))
- {
- FCAN_ERROR("FCanBaudrateSet FCAN_ARB_SEGMENT baudrate = %d invalid", baudrate);
- return FCAN_INVAL_PARAM;
- }
- if ((segment == FCAN_DATA_SEGMENT) && ((baudrate > FCAN_BAUDRATE_1000K) || (baudrate < FCAN_BAUDRATE_50K)))
- {
- FCAN_ERROR("FCanBaudrateSet FCAN_DATA_SEGMENT baudrate = %d invalid", baudrate);
- return FCAN_INVAL_PARAM;
- }
- #elif defined(CONFIG_TARGET_E2000)
- if ((segment == FCAN_ARB_SEGMENT) && ((baudrate > FCAN_BAUDRATE_1000K) || (baudrate < FCAN_BAUDRATE_10K)))
- {
- FCAN_ERROR("FCanBaudrateSet FCAN_ARB_SEGMENT baudrate = %d invalid", baudrate);
- return FCAN_INVAL_PARAM;
- }
- if ((segment == FCAN_DATA_SEGMENT) && ((baudrate > FCAN_BAUDRATE_5000K) || (baudrate < FCAN_BAUDRATE_10K)))
- {
- FCAN_ERROR("FCanBaudrateSet FCAN_DATA_SEGMENT baudrate = %d invalid", baudrate);
- return FCAN_INVAL_PARAM;
- }
- #endif
- }
- FError ret = FCAN_SUCCESS;
- FCanBaudrateConfig timing_config;
- memset(&timing_config, 0, sizeof(timing_config));
- /* Automatically calculate parameters based on baudrate and sample point */
- if (baudrate_p->auto_calc == TRUE)
- {
- ret = FCanCalcBittiming(&timing_config, baudrate, sample_point, segment);
- if (ret != FCAN_SUCCESS)
- {
- FCAN_ERROR("FCanCalcBittiming %d failed", segment);
- return FCAN_FAILURE;
- }
- ret = FCanSetTiming(instance_p, &timing_config, segment);
- if (ret != FCAN_SUCCESS)
- {
- FCAN_ERROR("FCanSetTiming %d failed", segment);
- return FCAN_FAILURE;
- }
- }
- else
- {
- ret = FCanSetTiming(instance_p, baudrate_p, segment);
- if (ret != FCAN_SUCCESS)
- {
- FCAN_ERROR("FCanSetTiming failed");
- return FCAN_FAILURE;
- }
- }
- return ret;
- }
- /**
- * @name: FCanFdEnable
- * @msg: Enable or disable can.
- * @param {FCanCtrl} *instance_p, instance of FCanCtrl controller
- * @param {boolean} enable, TRUE-enable canfd, FALSE-disable canfd.
- * @return err code information, FCAN_SUCCESS indicates success,others indicates failed
- */
- FError FCanEnable(FCanCtrl *instance_p, boolean enable)
- {
- FASSERT(instance_p);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- uintptr base_addr = instance_p->config.base_address;
- if (enable == TRUE)
- {
- FCAN_SETBIT(base_addr, FCAN_CTRL_OFFSET, FCAN_CTRL_XFER_MASK);
- }
- else
- {
- FCAN_CLEARBIT(base_addr, FCAN_CTRL_OFFSET, FCAN_CTRL_XFER_MASK);
- }
- return FCAN_SUCCESS;
- }
- /**
- * @name: FCanIdMaskFilterSet
- * @msg: Set the can mask and umask id.
- * @param {FCanCtrl} *instance_p, instance of FCanCtrl controller
- * @param {FCanIdMaskConfig} *id_mask_p, include filter register index, umask id and mask id
- * id indicates a specific ID can receive
- * mask indicates mask the corresponding bit of the id
- * @return err code information, FCAN_SUCCESS indicates success,others indicates failed
- */
- FError FCanIdMaskFilterSet(FCanCtrl *instance_p, FCanIdMaskConfig *id_mask_p)
- {
- FASSERT(instance_p);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- FASSERT(id_mask_p);
- u32 filter_index = id_mask_p->filter_index;
- FASSERT(filter_index < FCAN_ACC_ID_REG_NUM);
- uintptr base_address = instance_p->config.base_address;
- u32 id_reg_offset = 0;
- u32 mask_reg_offset = 0;
- u32 id = 0;
- u32 mask = 0;
- switch (filter_index)
- {
- case 0:
- id_reg_offset = FCAN_ACC_ID0_OFFSET;
- mask_reg_offset = FCAN_ACC_ID0_MASK_OFFSET;
- break;
- case 1:
- id_reg_offset = FCAN_ACC_ID1_OFFSET;
- mask_reg_offset = FCAN_ACC_ID1_MASK_OFFSET;
- break;
- case 2:
- id_reg_offset = FCAN_ACC_ID2_OFFSET;
- mask_reg_offset = FCAN_ACC_ID2_MASK_OFFSET;
- break;
- case 3:
- id_reg_offset = FCAN_ACC_ID3_OFFSET;
- mask_reg_offset = FCAN_ACC_ID3_MASK_OFFSET;
- break;
- default:
- return FCAN_FAILURE;
- }
- if (id_mask_p->type == FCAN_STANDARD_FRAME)
- {
- id = id_mask_p->id << FCAN_ACC_IDN_SHIFT;
- mask = id_mask_p->mask << FCAN_ACC_IDN_SHIFT;
- }
- FCAN_WRITE_REG32(base_address, id_reg_offset, id);
- FCAN_WRITE_REG32(base_address, mask_reg_offset, mask);
- return FCAN_SUCCESS;
- }
- /**
- * @name: FCanIdMaskFilterEnable
- * @msg: Set the can id mask filter enable.
- * @param {FCanCtrl} *instance_p, instance of FCanCtrl controller
- * @return {*}
- */
- void FCanIdMaskFilterEnable(FCanCtrl *instance_p)
- {
- FCanConfig *config_p;
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- config_p = &instance_p->config;
- FCAN_SETBIT(config_p->base_address, FCAN_CTRL_OFFSET, FCAN_CTRL_AIME_MASK);
- }
- /**
- * @name: FCanIdMaskFilterDisable
- * @msg: Set the can id mask filter disable.
- * @param {FCanCtrl} *instance_p, instance of FCanCtrl controller
- * @return {*}
- */
- void FCanIdMaskFilterDisable(FCanCtrl *instance_p)
- {
- FCanConfig *config_p;
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- config_p = &instance_p->config;
- FCAN_CLEARBIT(config_p->base_address, FCAN_CTRL_OFFSET, FCAN_CTRL_AIME_MASK);
- }
- /**
- * @name: FCanInterruptEnable
- * @msg: Enable can interrupt.
- * @param {FCanCtrl} *instance_p, instance of FCanCtrl controller
- * @param {FCanIntrEventType} event_type, interrupt event type
- * @return err code information, FCAN_SUCCESS indicates success,others indicates failed
- */
- FError FCanInterruptEnable(FCanCtrl *instance_p, FCanIntrEventType event_type)
- {
- FASSERT(instance_p != NULL);
- FASSERT(FT_COMPONENT_IS_READY == instance_p->is_ready);
- uintptr base_addr = instance_p->config.base_address;
- u32 reg_val = 0;
- reg_val = FCAN_READ_REG32(base_addr, FCAN_INTR_OFFSET);
- switch (event_type)
- {
- case FCAN_INTR_EVENT_SEND:
- reg_val |= FCAN_INTR_TEIE_MASK;
- break;
- case FCAN_INTR_EVENT_RECV:
- reg_val |= FCAN_INTR_REIE_MASK;
- break;
- case FCAN_INTR_EVENT_ERROR:
- reg_val |= FCAN_INTR_EIE_MASK;
- break;
- default:
- break;
- }
- FCAN_WRITE_REG32(base_addr, FCAN_INTR_OFFSET, reg_val);
- return FCAN_SUCCESS;
- }
- /**
- * @name: FCanFdEnable
- * @msg: Enable or disable can fd.
- * @param {FCanCtrl} *instance_p, instance of FCanCtrl controller
- * @param {boolean} enable, TRUE-enable canfd, FALSE-disable canfd.
- * @return err code information, FCAN_SUCCESS indicates success,others indicates failed
- */
- FError FCanFdEnable(FCanCtrl *instance_p, boolean enable)
- {
- FASSERT(instance_p != NULL);
- FASSERT(FT_COMPONENT_IS_READY == instance_p->is_ready);
- uintptr base_addr = instance_p->config.base_address;
- if (enable == TRUE)
- {
- instance_p->use_canfd = TRUE;
- FCAN_SETBIT(base_addr, FCAN_CTRL_OFFSET, FCAN_CTRL_FDCRC_MASK | FCAN_CTRL_IOF_MASK);
- }
- else
- {
- instance_p->use_canfd = FALSE;
- FCAN_SETBIT(base_addr, FCAN_CTRL_OFFSET, FCAN_CTRL_IOF_MASK);
- FCAN_CLEARBIT(base_addr, FCAN_CTRL_OFFSET, FCAN_CTRL_FDCRC_MASK);
- }
- return FCAN_SUCCESS;
- }
|