From: Jiri Vanek Date: Thu, 12 Apr 2012 10:31:43 +0000 (+0200) Subject: Setting of initial bit timing has been done. X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/commitdiff_plain/a73d6ffea8948a9abc9bfb32728bb255cec18317 Setting of initial bit timing has been done. --- diff --git a/embedded/app/usbcan/can/lpc17xx_can.h b/embedded/app/usbcan/can/lpc17xx_can.h index d920ffd..202ed2a 100644 --- a/embedded/app/usbcan/can/lpc17xx_can.h +++ b/embedded/app/usbcan/can/lpc17xx_can.h @@ -106,7 +106,8 @@ extern "C" //CAN Status Register bits #define CAN_SR_RBS (1<<0) #define CAN_SR_DOS (1<<1) -#define CAN_SR_TBS1 (1<<2) +#define CAN_SR_TBS1 (1<<2) +#define CAN_SR_TCS1 (1<<3) //CAN Command Register bits #define CAN_CMR_TR (1<<0) diff --git a/embedded/app/usbcan/lpc17xx_can.c b/embedded/app/usbcan/lpc17xx_can.c index 7cd0f56..e8ca58e 100644 --- a/embedded/app/usbcan/lpc17xx_can.c +++ b/embedded/app/usbcan/lpc17xx_can.c @@ -5,6 +5,36 @@ static void CAN_setBusTiming(struct canchip_t *chip); #define MAX_TRANSMIT_WAIT_LOOPS 20 +/* + * CAN harware-dependent bit-timing constant + * + * Used for calculating and checking bit-timing parameters + */ + +struct can_bittiming_const { + char name[16]; /* Name of the CAN controller hardware */ + uint32_t tseg1_min; /* Time segement 1 = prop_seg + phase_seg1 */ + uint32_t tseg1_max; + uint32_t tseg2_min; /* Time segement 2 = phase_seg2 */ + uint32_t tseg2_max; + uint32_t sjw_max; /* Synchronisation jump width */ + uint32_t brp_min; /* Bit-rate prescaler */ + uint32_t brp_max; + uint32_t brp_inc; +}; + +static struct can_bittiming_const lpc17xx_can_bittiming_const = { + .name = "lpc17xx_can", + .tseg1_min = 1, + .tseg1_max = 16, + .tseg2_min = 1, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 1024, + .brp_inc = 1, +}; + //--------------------------------------------------------------------------------- //--------------------------------------------------------------------------------- @@ -40,6 +70,7 @@ int can_lmc1_init_chip_data(struct candevice_t *candev, int chipnr){ // used CAN1 peripherial -> CAN1 registers base candev->chip[chipnr]->chip_base_addr = CAN1_REGS_BASE; + candev->chip[chipnr]->clock = system_frequency / 4; lpc17xx_fill_chipspecops(candev->chip[chipnr]); @@ -84,11 +115,85 @@ int can_lmc1_program_irq(struct candevice_t *candev) // lpc17xx can chip specific functions: +/* + * lpc17xx_baud_rate: - set communication parameters. + * @chip: pointer to chip state structure + * @rate: baud rate in Hz + * @clock: frequency of CAN clock in Hz + * @sjw: synchronization jump width (0-3) prescaled clock cycles + * @sampl_pt: sample point in % (0-100) sets (TSEG1+1)/(TSEG1+TSEG2+2) ratio + */ +int lpc17xx_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, + int sampl_pt, int 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; + + struct can_bittiming_const *btc = &lpc17xx_can_bittiming_const; + + // right ? + //clock /=2; + + /* tseg even = round down, odd = round up */ + for (tseg=(0+0+2)*2; tseg<=(btc->tseg2_max+btc->tseg1_max+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\n", + rate, clock); + CANMSG("%d bps. brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d\n", + 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 > btc->tseg2_max) + tseg2 = btc->tseg2_max; + tseg1 = best_tseg-tseg2-2; + if (tseg1>btc->tseg1_max) { + tseg1 = btc->tseg1_max; + 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\n", + best_brp, best_tseg, tseg1, tseg2, + (100*(best_tseg-tseg2)/(best_tseg+1))); + + + CAN_set_bittiming(chip, best_brp, sjw, tseg1, tseg2); + + + return 0; +} + + int lpc17xx_chip_config(struct canchip_t *chip){ CAN_init(chip); + if (!chip->baudrate) + chip->baudrate=1000000; + + printf("CAN CHIP INIT, baudrate: %d\n", (int) chip->baudrate); + + if (lpc17xx_baud_rate(chip,chip->baudrate,chip->clock,0,75,0)) + return -ENODEV; + return 0; } @@ -109,7 +214,8 @@ int lpc17xx_send_msg(struct canchip_t *chip, struct msgobj_t *obj, // write transmission request can_write_reg(chip, (CAN_CMR_TR | CAN_CMR_STB1), CAN_CMR_o); - while (!(can_read_reg(chip, CAN_SR_o) & (1<<3))){ + // check transmission complete status + while (!(can_read_reg(chip, CAN_SR_o) & CAN_SR_TCS1)){ if(i++chip_irq); // enter reset mode @@ -450,76 +554,6 @@ void CAN_set_bittiming(struct canchip_t *chip, uint32_t brp, uint32_t sjw, uint3 can_enable_irq(chip->chip_irq); } -void CAN_setBusTiming(struct canchip_t *chip){ - - uint32_t PCLK_CAN; - uint32_t res; - - uint8_t tq_numb; // number of time quantum - uint8_t TSEG1, TSEG2; - uint8_t BRP; - uint8_t SJW; - uint8_t SAM; - uint8_t div; - - TSEG1 = TSEG2 = BRP = 0; - - // 0 = the bus is sampled once - SAM = 0; - - // the Synchronization Jump Width (this value plus one) - SJW = 3; - - // get clock divide for CAN1 - div = __mfld2val(PCLK_CAN1_MASK, SC->PCLKSEL0); - switch(div){ - case 0: - div = 4; - break; - case 1: - div = 1; - break; - case 2: - div = 2; - break; - case 3: - // only for CAN, for other peripherials '11' value means div=8 - div = 6; - break; - } - - - PCLK_CAN = system_frequency / div; - - res = PCLK_CAN / (chip->baudrate); - - - // calculation of tq_numb - number of time quantum (must be in <8,25>) - // tq_numb = TSEG1 + TSEG2 + 3 - - for(tq_numb=25; tq_numb>=8; tq_numb--){ - - if ((res%tq_numb)==0){ - - // Baud Rate Prescaler. The PCLK clock is divided by (this value plus one) to produce the CAN clock. - BRP = (res / tq_numb) - 1; - - // sync. segment allways 1 tq - tq_numb--; - - // number of tq from the sample point to the next nominal Sync. point (this value plus one) - TSEG2 = (tq_numb/3) - 1; - - // number of tq from Sync. point to the sample point (this value plus one) - TSEG1 = tq_numb - (tq_numb/3) - 1; - - break; - } - } - - can_write_reg(chip, ((SAM<<23)|(TSEG2<<20)|(TSEG1<<16)|(SJW<<14)|(BRP<<0)), CAN_BTR_o); - -} void CAN_init(struct canchip_t *chip){ @@ -527,8 +561,6 @@ void CAN_init(struct canchip_t *chip){ uint32_t pclksel0; uint32_t val; uint32_t i; - - printf("CAN INIT, baudrate: %d\n", (int) chip->baudrate); // configure CAN1 pins CAN_configPin(); @@ -563,9 +595,6 @@ void CAN_init(struct canchip_t *chip){ // read to clear interrupt pending in Interrupt Capture Register tmp = can_read_reg(chip, CAN_ICR_o); - // set bus timing - CAN_setBusTiming(chip); - // return to normal operating can_write_reg(chip, 0, CAN_MOD_o); diff --git a/embedded/app/usbcan/usb_vend.c b/embedded/app/usbcan/usb_vend.c index 3f0afc9..1f5d41f 100644 --- a/embedded/app/usbcan/usb_vend.c +++ b/embedded/app/usbcan/usb_vend.c @@ -104,7 +104,6 @@ nodata: int set_canbtr_complete_fnc(struct usb_ep_t *ep, int status){ int dest_chip; -// int32_t rate,sjw,sampl_pt,flags; uint32_t brp, sjw, tseg1, tseg2; struct can_lmc1_chip_data *chip_data=NULL; @@ -134,7 +133,7 @@ int set_canbtr_complete_fnc(struct usb_ep_t *ep, int status){ printf("BRP: %d, SJW: %d, TSEG1: %d, TSEG2: %d \n", brp, sjw, tseg1, tseg2); - CAN_set_bittiming(chips_p[dest_chip], brp, sjw, tseg1, tseg2); + CAN_set_bittiming(chips_p[dest_chip], brp--, sjw--, tseg1--, tseg2--); // if (chips_p[dest_chip]->chipspecops->baud_rate(chips_p[dest_chip], rate, chips_p[dest_chip]->clock, sjw, sampl_pt, flags)<0) // goto error;