?? bdm.c
字號:
/*
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 */
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -