?? bdmcf.c
字號:
/*
Turbo BDM Light ColdFire - bdm routines
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 "MC68HC908JB16.h"
#include "options.h"
#include "bdmcf.h"
#include "timer.h"
#include "commands.h"
#include "cmd_processing.h"
#ifdef MULTIPLE_SPEEDS
/* until more than one set of rx/tx functions is needed the speed of operation can be improved by not using the pointers */
#pragma DATA_SEG Z_RAM
/* pointers to Rx & Tx routines */
unsigned char near (*bdmcf_rx8_ptr)(void) = bdmcf_rx8_1;
void near (*bdmcf_tx8_ptr)(unsigned char) = bdmcf_tx8_1;
unsigned char near (*bdmcf_txrx8_ptr)(unsigned char) = bdmcf_txrx8_1;
unsigned char near (*bdmcf_txrx_start_ptr)(void) = bdmcf_txrx_start_1;
#pragma DATA_SEG DEFAULT
/* tables with pointers to Tx & Rx functions */
unsigned char (* const bdmcf_rx8_ptrs[])(void)=
{bdmcf_rx8_1};
void (* const bdmcf_tx8_ptrs[])(unsigned char)=
{bdmcf_tx8_1};
unsigned char (* const bdmcf_txrx8_ptrs[])(unsigned char)=
{bdmcf_txrx8_1};
unsigned char (* const bdmcf_txrx_start_ptrs[])(void)=
{bdmcf_txrx_start_1};
#endif
/* halts the target CPU (stops execution of the code and brings the part into BDM mode) */
void bdmcf_halt(void) {
#ifdef INVERT
BKPT_OUT=1; /* assert BKPT */
#else
BKPT_OUT=0;
#endif
wait_10us(70); /* wait 700us, this should be enough even for a target running at 2kHz clock and yet it is short enough to fit into a single USB slot */
#ifdef INVERT
BKPT_OUT=0; /* deassert BKPT */
#else
BKPT_OUT=1;
#endif
bdmcf_complete_chk_rx(); /* added in revision 0.3 */
/* it is a workaround for a strange problem: CF CPU V2 seems to ignore the first transfer after a halt */
/* I do not admit I know why it happens, but the extra NOP command fixes the problem... */
/* the problem has nothing to do with the delay: adding up to 400ms of delay between the halt nad the read did not fix it */
}
/* resets the target CPU either into BDM mode (parameter bkpt=0) or into notmal mode (parameter bkpt!=0) */
/* length of the reset pulse is 50ms, if BKPT is to be asserted it is held active for 50ms after reset is released */
void bdmcf_reset(unsigned char bkpt) {
RSTI_OUT=0; /* reset is active low */
RSTI_DIRECTION=1; /* assert it */
if (bkpt==0) {
#ifdef INVERT
BKPT_OUT=1; /* assert BKPT */
#else
BKPT_OUT=0;
#endif
}
wait_1ms(50); /* 50ms */
RSTI_DIRECTION=0; /* deassert reset */
wait_1ms(50); /* give the reset pin enough time to rise even with slow RC */
#ifdef INVERT
BKPT_OUT=0; /* deassert BKPT */
#else
BKPT_OUT=1;
#endif
cable_status.reset=NO_RESET_ACTIVITY; /* clear the reset flag */
bdmcf_complete_chk_rx(); /* added in revision 0.3 */
}
/* asserts the TA signal for the specified duration */
/* the time is in 10us ticks */
void bdmcf_ta(unsigned char time_10us) {
TA_OUT=0; /* TA is active low */
TA_DIRECTION=1; /* assert it */
wait_10us(time_10us); /* wait the specified time */
TA_DIRECTION=0; /* de-assert it */
}
/* transmits series of 17 bit messages, contents of messages is pointed to by *data */
/* first byte in the buffer is the MSB oft the first message */
void bdmcf_tx(unsigned char count, unsigned char *data) {
while(count--) {
bdmcf_txrx_start_ptr();
bdmcf_tx8_ptr(*(data++));
bdmcf_tx8_ptr(*(data++));
}
}
/* waits for command complete indication, to be used with commands which only write data and do not read any result */
/* returns 0 on success and non-zero on error */
/* only checks the status, not the data bits */
unsigned char bdmcf_complete_chk(unsigned int next_cmd) {
unsigned char i=BDMCF_RETRY;
unsigned char status;
do {
status=bdmcf_txrx_start_ptr();
bdmcf_tx8_ptr(next_cmd>>8); /* send in the next command */
bdmcf_tx8_ptr(next_cmd&0xff);
if (status==0) return(0);
} while ((i--)>0);
return(1);
}
/* waits for command complete indication, to be used with commands which only write data and do not read any result */
/* returns 0 on success and non-zero on error */
/* checks buss error as well as not-ready, but does not send the next command */
unsigned char bdmcf_complete_chk_rx(void) {
unsigned char i=BDMCF_RETRY;
unsigned char status;
unsigned char data;
do {
status=bdmcf_txrx_start_ptr();
bdmcf_tx8_ptr(0);
data=bdmcf_rx8_ptr();
if (status==0) return(0);
} while ((data==0x00)&&((i--)>0));
return(1);
}
/* receives series of 17 bit messages and stores them into the supplied buffer (MSB of the first message first) */
/* returns zero on success and non-zero on retry error */
unsigned char bdmcf_rx(unsigned char count, unsigned char *data) {
unsigned char i,status;
while(count) {
i=BDMCF_RETRY;
do {
status=bdmcf_txrx_start_ptr();
*(data+0)=bdmcf_rx8_ptr();
*(data+1)=bdmcf_rx8_ptr();
} while ((status!=0)&&((*(data+1))==0x00)&&((i--)>0)); /* repeat while status==1 & data+1 == 00 (not ready, come again) */
if (status!=0) return(1);
count--;
data+=2;
}
return(0);
}
/* receives series of 17 bit messages and stores them into the supplied buffer (MSB of the first message first) */
/* returns zero on success and non-zero on retry error */
/* transmits the next command while receiving the last message */
unsigned char bdmcf_rxtx(unsigned char count, unsigned char *data, unsigned int next_cmd) {
unsigned char i,status;
while(count) {
i=BDMCF_RETRY;
count--;
if (count) {
do {
status=bdmcf_txrx_start_ptr();
*(data+0)=bdmcf_rx8_ptr();
*(data+1)=bdmcf_rx8_ptr();
} while ((status!=0)&&((*(data+1))==0x00)&&((i--)>0));
} else {
do { /* last message - send the next command */
status=bdmcf_txrx_start_ptr();
*(data+0)=bdmcf_txrx8_ptr(next_cmd>>8);
*(data+1)=bdmcf_txrx8_ptr(next_cmd&0xff);
} while ((status!=0)&&((*(data+1))==0x00)&&((i--)>0));
}
if (status!=0) return(1);
data+=2;
}
return(0);
}
/* transmits a 17 bit message, returns the status bit */
unsigned char bdmcf_tx_msg(unsigned int data) {
unsigned char status;
status=bdmcf_txrx_start_ptr();
bdmcf_tx8_ptr(data>>8);
bdmcf_tx8_ptr(data&0xff);
return(status);
}
/* transmits a 17 bit message, returns the least significant byte of the response */
/* to be used for transmitting second message in a multi-message command which can fail (e.g. because target is not halted) */
/* the returned byte identifies what is happening: 00 = Not ready, 01 = Bus error, FF = Illegal command */
/* the correct response in these cases is Not Ready */
unsigned char bdmcf_tx_msg_half_rx(unsigned int data) {
unsigned char ret_val;
bdmcf_txrx_start_ptr();
bdmcf_tx8_ptr(data>>8);
ret_val=bdmcf_txrx8_ptr(data&0xff);
return(ret_val);
}
/* receives a 17 bit message, returns the status bit, data is stored into the supplied data buffer MSB first */
unsigned char bdmcf_rx_msg(unsigned char *data) {
unsigned char status;
status=bdmcf_txrx_start_ptr();
*data=bdmcf_rx8_ptr();
*(data+1)=bdmcf_rx8_ptr();
return(status);
}
/* transmits & receives a 17 bit message, data in the buffer is transmited and then replaced with received data, returns the status bit */
unsigned char bdmcf_txrx_msg(unsigned char *data) {
unsigned char status;
status=bdmcf_txrx_start_ptr();
*data=bdmcf_txrx8_ptr(*data);
*(data+1)=bdmcf_txrx8_ptr(*(data+1));
return(status);
}
/* resynchronizes communication with the target in case of noise of the CLK line, etc. */
/* returns 0 in case of sucess, non-zero in case of error */
unsigned char bdmcf_resync(void) {
unsigned char i;
unsigned int data=BDMCF_CMD_NOP;
bdmcf_tx_msg(BDMCF_CMD_NOP); /* send in 3 NOPs to clear any error */
bdmcf_tx_msg(BDMCF_CMD_NOP);
bdmcf_txrx_msg(&data);
if ((data&3)==0) return(1); /* the last NOP did not return the expected value (at least one of the two bits should be 1) */
for (i=18;i>0;i++) { /* now start sending in another nop and watch the result */
if (bdmcf_txrx_start_ptr()==0) break; /* the first 0 is the status */
}
if (i==0) return(1);
/* transmitted & received the status, finish the nop */
bdmcf_tx8_ptr(0x00);
bdmcf_tx8_ptr(0x00);
return(0);
}
/* initialises the BDM interface */
void bdmcf_init(void) {
PTA = BDMCF_IDLE; /* preload idle state into port A data register */
#ifdef DEBUG
DDRA = DSI_OUT_MASK | TCLK_OUT_MASK | DSCLK_OUT_MASK | BKPT_OUT_MASK; /* RSTI_OUT and TA_OUT are inactive, the remaining OUT signals are outputs */
#else
DDRA = DSI_OUT_MASK | TCLK_OUT_MASK | DSCLK_OUT_MASK | BKPT_OUT_MASK | DDRA_DDRA7; /* PTA7 is unused when not debugging, make sure it is output in such case */
#endif
PTC = 0;
DDRC = DDRC_DDRC1; /* make pin PTC1 output (it is not bonded out on the 20 pin package anyway) */
POCR = POCR_PTE20P; /* enable pull-ups on PTE0-2 (unused pins) */
/* RSTO edge capture */
T1SC = 0; /* enable timer 1 */
T1SC0; /* read the status and control register */
#ifdef INVERT
T1SC0 = T1SC0_ELS0A_MASK; /* capture rising edge (invert), this write will also clear the interrupt flag if set */
#else
T1SC0 = T1SC0_ELS0B_MASK; /* capture falling edge (non-invert), this write will also clear the interrupt flag if set */
#endif
T1SC0 |= T1SC0_CH0IE_MASK; /* enable input capture interrupt */
cable_status.reset=NO_RESET_ACTIVITY; /* clear the reset flag */
}
/* this interrupt is called whenever an active edge is detected on the RSTO input */
interrupt void rsto_detect(void) {
T1SC0 &= ~T1SC0_CH0F_MASK; /* clear the interrupt flag */
cable_status.reset=RESET_DETECTED; /* reset of the target was detected, leave it for the debugger to what it believes is appropriate */
}
/* transmits 8 bits */
void bdmcf_tx8_1(unsigned char data) {
asm {
tax /* move the input data to X */
#ifdef INVERT
comx /* invert the data */
#endif
#ifdef DEBUG
lda #(BDMCF_IDLE*2)
#else
lda #(BDMCF_IDLE/2)
#endif
/* transmit bit 7 */
lslx /* shift MSB into C */
#ifdef DEBUG
rora /* rotate C into A */
#else
rola
#endif
sta PTA /* create falling edge on DSCLK and write the next bit value to the port */
#ifdef DEBUG
lda #(BDMCF_IDLE*2) /* reload idle value into A */
#else
lda #(BDMCF_IDLE/2)
#endif
#ifdef INVERT
bclr DSCLK_OUT_BITNUM,DSCLK_OUT_PORT /* create rising edge on DSCLK */
#else
bset DSCLK_OUT_BITNUM,DSCLK_OUT_PORT
#endif
/* transmit bit 6 */
lslx /* shift MSB into C */
#ifdef DEBUG
rora /* rotate C into A */
#else
rola
#endif
sta PTA /* create falling edge on DSCLK and write the next bit value to the port */
#ifdef DEBUG
lda #(BDMCF_IDLE*2) /* reload idle value into A */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -