#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,
+};
+
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
// 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]);
// 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;
}
// 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++<MAX_TRANSMIT_WAIT_LOOPS)
continue;
uint8_t SAM = 0; // 0 = the bus is sampled once
- brp--;
- sjw--;
- tseg1--;
- tseg2--;
+ //debug print
+ printf("BRP: %d, SJW: %d, TSEG1: %d, TSEG2: %d \n", brp+1, sjw+1, tseg1+1, tseg2+1);
can_disable_irq(chip->chip_irq);
// enter reset mode
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){
uint32_t pclksel0;
uint32_t val;
uint32_t i;
-
- printf("CAN INIT, baudrate: %d\n", (int) chip->baudrate);
// configure CAN1 pins
CAN_configPin();
// 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);