📄 c_can.c
字号:
/** * c_can.c * Linux CAN-bus device driver. * * This file holds the methods which access the C_CAN module. * * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de * Version 1.0 04 Feb 2003 */#define __NO_VERSION__#include <linux/delay.h>#include "../include/candrv.h"#include "../include/c_can.h"#include "../include/hms30c7202_can.h"extern int stdmask;extern int extmask;////////////////////////////////////////////////////////////////////////** * This function sets the C_CAN module in the configuration mode */int c_can_enable_configuration(struct chip_t *pchip){ int i=0; u16 flags; DEBUGMSG("(c%d)calling c_can_enable_configuration(...)", pchip->chip_nr); //read Control Register flags=pchip->read_register(pchip, CCCR); //set Init-Bit in the Control Register (10 tries) while ((!(flags & CR_INIT)) && (i<=10)) { pchip->write_register(flags|CR_INIT, pchip, CCCR); udelay(1000); i++; flags=pchip->read_register(pchip, CCCR); } if (i>=10) { CANMSG("Reset error"); //enable_irq(chip->chip_irq); return -ENODEV; } DEBUGMSG(" -> ok"); return 0;}////////////////////////////////////////////////////////////////////////** * This function stops the configuration mode of the C_CAN module */int c_can_disable_configuration(struct chip_t *pchip){ int i=0; u16 flags; DEBUGMSG("(c%d)calling c_can_disable_configuration(...)", pchip->chip_nr); //read Control Register flags=pchip->read_register(pchip, CCCR); //reset Init-Bit in the Control Register (10 tries) while ( (flags & CR_INIT) && (i<=10) ) { pchip->write_register(flags & ~CR_INIT, pchip, CCCR); udelay(1000); //1000 microseconds i++; flags=pchip->read_register(pchip, CCCR); } if (i>=10) { CANMSG("Error leaving reset status"); return -ENODEV; } DEBUGMSG(" -> ok"); return 0;}////////////////////////////////////////////////////////////////////////** * Configures baudrate, IRQs and message objects of a C_CAN chip */int c_can_chip_config(struct chip_t *pchip){ DEBUGMSG("(c%d)calling c_can_chip_config(...)", pchip->chip_nr); // Validate pointer if ( NULL == pchip ) return -1; if (pchip->baudrate == 0) pchip->baudrate=1000; if (c_can_baud_rate(pchip,pchip->baudrate*1000,pchip->clock,0,75,0)) { CANMSG("Error configuring baud rate"); return -ENODEV; } if (c_can_clear_objects(pchip)) { CANMSG("Error clearing message objects"); return -ENODEV; } if ( ! pchip->time_triggered ) { if (c_can_config_irqs(pchip, CR_MIE | CR_SIE | CR_EIE)) { CANMSG("Error configuring interrupts"); return -ENODEV; } } else { if (c_can_config_irqs(pchip, CR_SIE | CR_EIE)) { CANMSG("Error configuring interrupts"); return -ENODEV; } } DEBUGMSG(" -> Configured successfully");#ifdef REGDUMP c_can_registerdump(pchip);#endif return 0;}////////////////////////////////////////////////////////////////////////** * Checks if the Busy-Bit in the IF1-Command-Request Register is set */int c_can_if1_busycheck(struct chip_t *pchip){ int i=0; while ( ( pchip->read_register( pchip, CCIF1CR) & IFXCR_BUSY) && (i++ <= 10) ) ; if (i>=10) { CANMSG("Error Busy-Bit stays set"); return -ENODEV; } return 0;}////////////////////////////////////////////////////////////////////////** * Checks if the Busy-Bit in the IF2-Command-Request Register is set */int c_can_if2_busycheck(struct chip_t *pchip){ int i=0; while ( (pchip->read_register( pchip, CCIF2CR) & IFXCR_BUSY) && (i++ <= 10) ) ; if (i>=10) { CANMSG("Error Busy-Bit stays set"); return -ENODEV; } return 0;}////////////////////////////////////////////////////////////////////////** * Set communication parameters. * param rate baud rate in Hz * param clock frequency of C-CAN clock in Hz * param sjw synchronization jump width (0-3) prescaled clock cycles * param sampl_pt sample point in % (0-100) sets (TSEG1+2)/(TSEG1+TSEG2+3) ratio * param flags fields BTR1_SAM, OCMODE, OCPOL, OCTP, OCTN, CLK_OFF, CBP */int c_can_baud_rate(struct chip_t *pchip, u32 rate, u32 clock, u32 sjw, u32 sampl_pt, u32 flags){ int best_error = 1000000000, error; int best_tseg=0, best_brp=0, best_rate=0, brp=0; int tseg=0, tseg1=0, tseg2=0; unsigned short tempCR = 0; DEBUGMSG("(c%d)calling c_can_baud_rate(...)", pchip->chip_nr); if (c_can_enable_configuration(pchip)) return -ENODEV; clock /=2; /* tseg even = round down, odd = round up */ for (tseg=(0+0+2)*2; tseg<=(MAX_TSEG2+MAX_TSEG1+2)*2+1; tseg++) { brp = clock/((1+tseg/2)*rate)+tseg%2; if (brp == 0 || brp > 64) continue; error = rate - clock/(brp*(1+tseg/2)); if (error < 0) error = -error; if (error <= best_error) { best_error = error; best_tseg = tseg/2; best_brp = brp-1; best_rate = clock/(brp*(1+tseg/2)); } } if (best_error && (rate/best_error < 10)) { CANMSG("baud rate %d is not possible with %d Hz clock", rate, 2*clock); CANMSG("%d bps. brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d", best_rate, best_brp, best_tseg, tseg1, tseg2); return -EINVAL; } tseg2 = best_tseg-(sampl_pt*(best_tseg+1))/100; if (tseg2 < 0) tseg2 = 0; if (tseg2 > MAX_TSEG2) tseg2 = MAX_TSEG2; tseg1 = best_tseg-tseg2-2; if (tseg1 > MAX_TSEG1) { tseg1 = MAX_TSEG1; tseg2 = best_tseg-tseg1-2; } DEBUGMSG(" -> Setting %d bps.\n", best_rate); DEBUGMSG(" -> brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d, sampl_pt=%d", best_brp, best_tseg, tseg1, tseg2, (100*(best_tseg-tseg2)/(best_tseg+1))); //read Control Register tempCR = pchip->read_register( pchip, CCCR); //Configuration Change Enable pchip->write_register(tempCR | CR_CCE, pchip, CCCR); pchip->write_register(((unsigned short)tseg2)<<12 | ((unsigned short)tseg1)<<8 | (unsigned short)sjw<<6 | (unsigned short) best_brp, pchip, CCBT); if (c_can_disable_configuration(pchip)) return -ENODEV; return 0;}////////////////////////////////////////////////////////////////////////** * Configures the mask bits of the specified message object */int c_can_mask(struct msgobj_t *pmsgobj, u32 mask, u16 usedirbit){ unsigned short tempreg = 0; unsigned short readMaskCM; unsigned short writeMaskCM; DEBUGMSG("(c%dm%d)calling c_can_mask(...)", pmsgobj->hostchip->chip_nr, pmsgobj->object); readMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_MASK; writeMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_MASK | IFXCM_WRRD; spin_lock( &pmsgobj->hostchip->if1lock ); /* load Message Object in IF1 */ if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV; pmsgobj->hostchip->write_register(readMaskCM, pmsgobj->hostchip, CCIF1CM); pmsgobj->hostchip->write_register(pmsgobj->object+1, pmsgobj->hostchip, CCIF1CR); /* setting Message Valid Bit to zero */ if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV; tempreg = pmsgobj->hostchip->read_register(pmsgobj->hostchip, CCIF1A2); pmsgobj->hostchip->write_register(tempreg & ~(IFXARB2_MVAL), pmsgobj->hostchip, CCIF1A2); pmsgobj->hostchip->write_register(writeMaskCM, pmsgobj->hostchip, CCIF1CM); pmsgobj->hostchip->write_register(pmsgobj->object+1, pmsgobj->hostchip, CCIF1CR); /* setting UMask, MsgVal and Mask Register */ if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV; /* writing acceptance mask for extended or standart mode */ if (pmsgobj->msg_mode & 1) { if (usedirbit) pmsgobj->hostchip->write_register((mask>>16 & 0x1FFF) | IFXMSK2_MXTD | IFXMSK2_MDIR, pmsgobj->hostchip, CCIF1M2); else pmsgobj->hostchip->write_register((mask>>16 & 0x1FFF) | IFXMSK2_MXTD, pmsgobj->hostchip, CCIF1M2); pmsgobj->hostchip->write_register((mask & 0xFFFF), pmsgobj->hostchip, CCIF1M1); } else { if (usedirbit) pmsgobj->hostchip->write_register(((mask<<2) & 0x1FFC) | IFXMSK2_MDIR,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -