⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bdm.c

📁 freecale单片机基于bdm接口的一些源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
    Turbo BDM Light - BDM communication
    Copyright (C) 2005  Daniel Malik

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 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
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "MC68HC908JB8.h"
#include "hidef.h"							
#include "bdm.h"
#include "commands.h"
#include "usb.h"

/* i, j & k are used as timing and general purpose variables in the Tx & Rx routines */
/* must be placed into the direct segment */
static unsigned char i;
static unsigned char j;
static unsigned char k;

/* pointers to Rx & Tx routines, tables for selection */
unsigned char (*bdm_rx_ptr)(void) = bdm_empty_rx_tx;
void (*bdm_tx_ptr)(unsigned char) = bdm_empty_rx_tx;

/* when SYNC length expressed in 60MHz ticks is ABOVE OR EQUAL to the value in the table, the correspnding pointer is selected */
/* if SYNC is shother than the first entry, the target runs too fast */
/* if SYNC is longer or equal to the last entry, the target runs too slow */

/*
const unsigned int bdm_tx_sel_tresholds[]=
  {914,     1129,    1335,    1541,    1747,    1952,    2157,    2465,    2877,    3288,
   3800,    4418,    5136,    6059,    7189,    8524,    10066,   11814,   13867,   16988};
*/
//new values for tics as the JB16 CPU is 2 times faster
const unsigned int bdm_tx_sel_tresholds[]=
  {914/2,     1129/2,    1335/2,    1541/2,    1747/2,    1952/2,    2157/2,    2465/2,    2877/2,    3288/2,
   3800/2,    4418/2,    5136/2,    6059/2,    7189/2,    8524/2,    10066/2,   11814/2,   13867/2,   16988/2};
void (* const bdm_tx_sel_ptrs[])(unsigned char)=
  {bdm_tx1, bdm_tx2, bdm_tx3, bdm_tx4, bdm_tx5, bdm_tx6, bdm_tx7, bdm_tx8, bdm_tx9, bdm_tx10,
   bdm_tx11,bdm_tx12,bdm_tx13,bdm_tx14,bdm_tx15,bdm_tx16,bdm_tx17,bdm_tx18,bdm_tx19,bdm_empty_rx_tx};
/*
const unsigned int bdm_rx_sel_tresholds[]=
  {853,     1101,    1347,    1592,    1837,    2202,    2694,    3303,    4042,    4897,
   5998,    7346,    9055,    11257,   13952,   17919};
*/
//new values for tics as the JB16 CPU is 2 times faster
const unsigned int bdm_rx_sel_tresholds[]=
  {853/2,     1101/2,    1347/2,    1592/2,    1837/2,    2202/2,    2694/2,    3303/2,    4042/2,    4897/2,
   5998/2,    7346/2,    9055/2,    11257/2,   13952/2,   17919/2};
unsigned char (* const bdm_rx_sel_ptrs[])(void)=
  {bdm_rx1, bdm_rx2, bdm_rx3, bdm_rx4, bdm_rx5, bdm_rx6, bdm_rx7, bdm_rx8, bdm_rx9, bdm_rx10,
   bdm_rx11,bdm_rx12,bdm_rx13,bdm_rx14,bdm_rx15,bdm_empty_rx_tx};

/* status of the BDM communication */


bdm_status_t bdm_status;

/* private macros */

#define ACKN_CLR   asm (BCLR TSC0_CH0F_BITNUM,TSC0); /* clear timer capture flag, in assembly to make sure the compiler does not mess it up... */

/* functions */

/* connect to HC12 or HCS12 target */
/* returns 0 on succes or 1 on failure */
unsigned char bdm12_connect(void) {
  unsigned char bdm_sts;															
  bdm_status.ackn = WAIT;															/* clear the ACKN feature */
  bdm_status.reset = NO_RESET_ACTIVITY;               /* clear the reset flag */
  /* first wait until both RESET and BDM are high */
  TMOD = RESET_WAIT * BUS_FREQUENCY * 16;             /* this is by 2.4% longer than (RESET_WAIT * BUS_FREQUENCY * 1000)/64, but cannot do that in 16-bit math */
  TSC = TSC_TRST_MASK | TSC_PS1_MASK | TSC_PS2_MASK;  /* reset the timer and start counting @ bus clock divided by 64 */
  TSC_TOF = 0;
  while(((RESET_IN==0)||(BDM_IN==0))&&(TSC_TOF==0));  /* wait for reset and bdm to rise or timeout */
  if (TSC_TOF) return(1);                             /* timeout */  
  if (bdm_sync_meas()) {
    /* trying to measure SYNC was not successful */
      return(1);  
  }
	if (bdm_rx_tx_select()) return(1); /* if at least one of the two methods succeeded, we can select the right Rx and Tx routines */
	bdm_ackn_init();    /* try the ACKN feature */
	BDM12_CMD_BDREADB(BDM12_STS_ADDR,&bdm_sts);
	if ((bdm_sts&0x80)==0) BDM12_CMD_BDWRITEB(BDM12_STS_ADDR,0x80|bdm_sts);	/* if BDM not enabled yet, enable it so it can be made active */
  return(0);          /* connection established */
}

/* resets the target */
/* mode == 0 -> reset to special mode, mode == 1 -> reset to normal mode */
/* returns zero on success and non-zero if reset signal stuck to ground */
unsigned char bdm_reset(unsigned char mode) {
  BDM_DIR1 = 1;                                       /* stop driving the BDM */
  KBSCR_IMASKK = 1;                                   /* mask KBD interrupts */
  TMOD = RESET_WAIT * BUS_FREQUENCY * 16;             /* this is by 2.4% longer than (RESET_WAIT * BUS_FREQUENCY * 1000)/64, but cannot do that in 16-bit math */
  TSC = TSC_TRST_MASK | TSC_PS1_MASK | TSC_PS2_MASK;  /* reset the timer and start counting @ bus clock divided by 64 */
  TSC_TOF = 0;
  while((RESET_IN==0)&&(TSC_TOF==0));                 /* wait for reset to rise or timeout */
  if (TSC_TOF) return(1);
  if (mode==0) {
    BDM_OUT = 0;                                      /* drive BDM low */
    BDM_DIR1 = 0;
    TMOD = RESET_SETTLE * BUS_FREQUENCY;              /* time to wait for signals to settle */
    TSC = TSC_TRST_MASK;                              /* reset the timer and start counting @ bus clock */
    TSC_TOF = 0;
    while(TSC_TOF==0);                                /* wait for timeout */
  }
  RESET_OUT = 0;                                      /* start driving RESET */
  RESET_OUT_DDR |= RESET_OUT_MASK;
  TMOD = RESET_LENGTH * BUS_FREQUENCY * 16;           /* time of the RESET pulse */
  TSC = TSC_TRST_MASK | TSC_PS1_MASK | TSC_PS2_MASK;  /* reset the timer and start counting @ bus clock divided by 64 */
  TSC_TOF = 0;
  while(TSC_TOF==0);                                  /* wait for timeout */
  RESET_OUT = 1;																			/* stop driving the RESET */
  RESET_OUT_DDR &= ~RESET_OUT_MASK;                   /* and make the pin input again so nothing interferes with it */
  TMOD = RESET_WAIT * BUS_FREQUENCY * 16;             /* time to wait for reset to rise */
  TSC = TSC_TRST_MASK | TSC_PS1_MASK | TSC_PS2_MASK;  /* reset the timer and start counting @ bus clock divided by 64 */
  TSC_TOF = 0;
  while((RESET_IN==0)&&(TSC_TOF==0));                 /* wait for reset to rise or timeout */
  if (TSC_TOF) return(1);
  if (mode==0) {
    TMOD = RESET_SETTLE * BUS_FREQUENCY;              /* time to wait for signals to settle */
    TSC = TSC_TRST_MASK;                              /* reset the timer and start counting @ bus clock */
    TSC_TOF = 0;
    while(TSC_TOF==0);                                /* wait for timeout */
    asm {
      CLRX   						                              /* point to PTA */
      CLRH
      LDA   #BDM_OUT_MASK + RESET_OUT_MASK  
      STA   ,X                                        /* bring BDM high */
      ORA   #BDM_DIR1_MASK
      STA   ,X                                        /* stop driving the BDM */
      /* it took 4 cycles from bringing BDM high to stop driving it and that is fast enough up to 16*3/4 = 12 MHz of BDM frequency on JB8 */
    }
  }
  /* wait one more settling time before allowing anythig else to happen on the BDM */
  TMOD = RESET_SETTLE * BUS_FREQUENCY;                /* time to wait for signals to settle */
  TSC = TSC_TRST_MASK;                                /* reset the timer and start counting @ bus clock */
  TSC_TOF = 0;
  while(TSC_TOF==0);                                  /* wait for timeout */
  KBSCR_ACKK=1;                                       /* acknowledge KBD interrupt */
  KBSCR_IMASKK = 0;                                   /* enable KBD interrupts again */
  return(0);
}

/* interrupt function servicing the KBD interrupt from RESET_IN assertion */
void interrupt bdm_reset_sense(void) {
  KBSCR_ACKK=1;                    /* acknowledge the interrupt */
  bdm_status.reset=RESET_DETECTED; /* record the fact that reset was asserted */  
}

/* measures the SYNC length and writes the result into bdm_status structure */
/* returns 0 on succes and non-zero on timeout */
unsigned char bdm_sync_meas(void) {
  unsigned int time;
  bdm_status.speed = NO_INFO; /* indicate that we do not have a clue about target speed at the moment... */
  TMOD = BDM_SYNC_REQ * BUS_FREQUENCY;  /* load TMOD with the longest SYNC REQUEST possible */
  BDM_DIR1 = 1;         /* stop driving the BDM */
  TSC = TSC_TRST_MASK;  /* restart the timer */
  TSC_TOF = 0;          /* clear TOF */
  while((TSC_TOF==0)&&(BDM_IN==0)); /* wait for the BDM to come high or timeout */
  if (TSC_TOF) return(1);           /* timeout ! */
  BDM_OUT = 0;
  BDM_DIR1 = 0;         /* bring BDM low */
  TSC = TSC_TRST_MASK;  /* restart the timer */
  TSC_TOF = 0;          /* clear TOF */
  while(TSC_TOF==0);    /* wait for timeout */
  TSC_TOF = 0;          /* clear the TOF flag */
  TSC0 = TSC0_ELS0B_MASK; /* capture falling edges */
  TSC0_CH0F=0;          /* clear capture flag */
  //this is not fast enough, the target will start driving 16 BDM cycles after the pin comes high
  //BDM_OUT_PORT = BDM_OUT_MASK;  /* bring BDM high */
  //BDM_DIR1_PORT = BDM_OUT_MASK | BDM_DIR1_MASK; /* stop driving it */
  asm {
    CLRX   						  /* point to PTA */
    CLRH
    LDA   #BDM_OUT_MASK + RESET_OUT_MASK  
    STA   ,X            /* bring BDM high */
    ORA   #BDM_DIR1_MASK
    STA   ,X            /* stop driving the BDM */
    /* it took 4 cycles from bringing BDM high to stop driving it and that is fast enough up to 16*3/4 = 12 MHz of BDM frequency on JB8 */
  }
  while ((TSC0_CH0F==0)&&(TSC_TOF==0));     /* wait for capture or timeout */  
  time=TCH0;                                /* capture start of the SYNC */
  TSC0 = TSC0_ELS0A_MASK;                   /* capture rising edge, clear capture flag */
  /* it takes 32 cycles to reenable capture (worst case) which is good enough up to 128*3/32 = 12 MHz again on JB8 */ 
  while ((TSC0_CH0F==0)&&(TSC_TOF==0));     /* wait for capture or timeout */  
  time=TCH0-time;                           /* calculate length of the SYNC */
  if (TSC_TOF) return(2);                   /* timeout ! */
  #if (BUS_FREQUENCY==3)
    bdm_status.sync_length=(time<<2)+(time<<4);   /* multiply by 20 to get the time in 60MHz ticks */
  #elif (BUS_FREQUENCY==6)
    bdm_status.sync_length=(time<<1)+(time<<3);   /* multiply by 10 to get the time in 60MHz ticks */
  #else
    bdm_status.sync_length=time*(60/BUS_FREQUENCY); /* if not 3 or 6 then do it the stupid way... */
  #endif
  bdm_status.speed = SYNC_SUPPORTED; /* SYNC feature is supported by the target */
  return(0);
}

/* waits 64 BDM cycles of the target MCU */
void bdm_wait64(void) {
  asm {
    LDA  bdm_status.wait64_cnt  /* number of loop iterations to wait */
  loop:  
    DBNZA loop                  /* 3 cycles per iteration */
  }
}

/* waits 150 BDM cycles of the target MCU */
void bdm_wait150(void) {
  asm {
    LDA  bdm_status.wait150_cnt  /* number of loop iterations to wait */
  loop:  
    DBNZA loop                  /* 3 cycles per iteration */
  }
}

/* enables ACKN and prepares the timer for easy ACKN timeout use */
void bdm_ackn_init(void) {
  TMOD = ACKN_TIMEOUT * BUS_FREQUENCY;  /* the timer will set the TOF flag as soon as the timeout time is reached */
  TSC = TSC_TRST_MASK;    /* start the timer, prescaler = 1 */
  TSC0 = TSC0_ELS0A_MASK;	/* capture rising edges */
  bdm_status.ackn = ACKN; /* switch ACKN on */
  BDM_CMD_ACK_ENABLE();   /* send the enable command to the target */
}

/* waits for ACKN pulse from the target */
void bdm_ackn(void) {
  TSC = TSC_TRST_MASK;                      /* clear the TOF flag if set and restart the timer */
  TSC_TOF = 0;                              /* clear TOF */
  while ((TSC0_CH0F==0)&&(TSC_TOF==0));     /* wait for capture or timeout */  
  TSC0 = TSC0_ELS0A_MASK;                   /* capture rising edge, clear capture flag */
  if (TSC_TOF) {
    /* timeout */
    bdm_status.ackn = WAIT;                 /* switch the ackn feature off */
  }
}

/* selects Rx and Tx routine to be used according to SYNC length in bdm_status structure */
/* returns 0 on success and 1 when no appropriate function can be found */
unsigned char bdm_rx_tx_select(void) {
  signed char i;
  bdm_rx_ptr = bdm_empty_rx_tx;                         /* clear the pointers */
  bdm_tx_ptr = bdm_empty_rx_tx;
  for (i=(sizeof(bdm_tx_sel_tresholds)/2)-1;i>=0;i--) { /* search through the table */
    if (bdm_status.sync_length>=bdm_tx_sel_tresholds[i]) {
      bdm_tx_ptr = bdm_tx_sel_ptrs[i];                  /* is SYNC is >=, select this routine */
      break;                                            /* and finish the search */
    }
  }
  if (bdm_tx_ptr==bdm_empty_rx_tx) return(1);           /* check if valid routine has been found */
  for (i=(sizeof(bdm_rx_sel_tresholds)/2)-1;i>=0;i--) { /* do the same for Rx as well */
    if (bdm_status.sync_length>=bdm_rx_sel_tresholds[i]) {
      bdm_rx_ptr = bdm_rx_sel_ptrs[i];
      break;
    }
  }
  if (bdm_rx_ptr==bdm_empty_rx_tx) return(1);
  /* there is plenty of overhead: JSR, LDA and RTS of the WAIT, RTS from the previous routine, JSR to the next routine: at least 21 cycles */
  /* cannot subtract more than the smallest possible result -1 as the number must be > 0 */
  bdm_status.wait64_cnt = bdm_status.sync_length/(3*(60/BUS_FREQUENCY)*128/64)-6; 
  bdm_status.wait150_cnt = bdm_status.sync_length/(3*(60/BUS_FREQUENCY)*128/150)-7; 
  return(0);
}

/* when no function appropriate for the target speed can be found the following routine is selected */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -