Setting of initial bit timing has been done.
authorJiri Vanek <vanekjir@fel.cvut.cz>
Thu, 12 Apr 2012 10:31:43 +0000 (12:31 +0200)
committerJiri Vanek <vanekjir@fel.cvut.cz>
Thu, 12 Apr 2012 10:31:43 +0000 (12:31 +0200)
embedded/app/usbcan/can/lpc17xx_can.h
embedded/app/usbcan/lpc17xx_can.c
embedded/app/usbcan/usb_vend.c

index d920ffd..202ed2a 100644 (file)
@@ -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)
index 7cd0f56..e8ca58e 100644 (file)
@@ -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++<MAX_TRANSMIT_WAIT_LOOPS)
                        continue;
 
@@ -431,10 +537,8 @@ void CAN_set_bittiming(struct canchip_t *chip, uint32_t brp, uint32_t sjw, uint3
 
        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
@@ -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);
 
index 3f0afc9..1f5d41f 100644 (file)
@@ -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;