📄 bdm.c
字号:
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) {
T1MOD = ACKN_TIMEOUT * BUS_FREQUENCY; /* the timer will set the TOF flag as soon as the timeout time is reached */
T1SC = T1SC_TRST_MASK; /* start the timer, prescaler = 1 */
T1SC0 = T1SC0_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) {
T1SC = T1SC_TRST_MASK; /* clear the TOF flag if set and restart the timer */
T1SC_TOF = 0; /* clear TOF */
while ((T1SC0_CH0F==0)&&(T1SC_TOF==0)); /* wait for capture or timeout */
T1SC0 = T1SC0_ELS0A_MASK; /* capture rising edge, clear capture flag */
if (T1SC_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*2)>=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*2)>=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*2)/(3*(60/BUS_FREQUENCY)*128/64)-6;
bdm_status.wait150_cnt =(bdm_status.sync_length*2)/(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 */
/* this is just to make things safe and to make sure there is a place to jump to in such a case */
unsigned char bdm_empty_rx_tx(void) {
command_buffer[0]=CMD_FAILED; /* if BDM command is executed with this routine set as either Tx or Rx it has failed... */
return(0);
}
/* initialises I/O pins and internal variables of the module */
void bdm_init() {
bdm_status.ackn = WAIT; /* select default behaviour & values */
bdm_status.target_type = HC12;
bdm_status.reset = NO_RESET_ACTIVITY;
bdm_status.speed = NO_INFO;
POCR_PAP=1; /* enable pullups on RESET_OUT, RESET_IN and BDM_DRIVE */
RESET_IN_DDR &= ~RESET_IN_MASK; /* RESET_IN is input */
RESET_OUT = 1; /* RESET_OUT inactive */
RESET_OUT_DDR &= ~RESET_OUT_MASK;/* RESET_OUT is input for the moment, only turn it out when needed as Rx routines interfere with RESET_OUT */
RESET_DR = 0; //Default is B to A for Input
RESET_DR_DDR |= RESET_DR_MASK; // Set as output to Drive the buffer
BDM_IN_DDR &= ~BDM_IN_MASK; /* BDM_IN is input */
BDM_OUT = 1; /* idle state of BDM line is high */
BDM_OUT_DDR |= BDM_OUT_MASK; /* BDM_OUT is output */
BDM_DIR2 = 1; /* prepare to drive the BDM once DIR2 is turned to output */
BDM_DIR2_DDR &= ~BDM_DIR2_MASK; /* turn BDM_DIR2 to input */
BDM_DIR1 = 0; /* do not drive the BDM */
BDM_DIR1_DDR |= BDM_DIR1_MASK; /* turn BDM_DIR1 to output */
/* now give the BDM interface enough time to soft reset in case it was doing something before */
T1MOD = SOFT_RESET * BUS_FREQUENCY; /* load T1MOD with the longest SOFT RESET time possible */
T1SC = T1SC_TRST_MASK; /* restart the timer */
T1SC_TOF = 0; /* clear TOF */
while(T1SC_TOF==0); /* wait for timeout */
KBIER = RESET_IN_MASK; /* enable RESET_IN as keyboard pin */
KBSCR = KBSCR_ACKK_MASK; /* acknowledge any pending interrupt and enable KBD to cause IRQ (once enabled) */
}
/* prepares transmit of BDM data */
/* assumes that BDM_OUT is 1 */
/* interrupts need to be disabled for the duration of all BDM commands */
/* it is up to the caller to see to this */
void bdm_tx_prepare(void) {
BDM_OUT_PORT = BDM_OUT_MASK | RESET_OUT_MASK; /* make sure BDM will be driven high once the driver is enabled */
BDM_OUT_DDR = BDM_OUT_MASK; /* turn DIR1 & RESET_OUT to input (now the only output in PTA register is BDM_OUT) */
BDM_DIR2_DDR |= BDM_DIR2_MASK; /* bring DIR low (start driving the BDM) */
}
/* finishes transmit of BDM data */
void bdm_tx_finish(void) {
BDM_OUT_PORT = BDM_OUT_MASK | RESET_OUT_MASK; /* do not drive RESET nor BDM once DIR1 is output again */
BDM_DIR2_DDR &= ~BDM_DIR2_MASK; /* stop driving DIR2 low */
BDM_DIR1_DDR = BDM_DIR1_MASK | BDM_OUT_MASK; /* enable DIR1 again, leave RESET_OUT as input */
}
/* receive 8 bit of data, MSB first */
/* expects DIR1 active and DIR2 inactive */
/* 6.75 - 9.75 MHz */
unsigned char bdm_rx1(void) {
#pragma NO_RETURN
asm {
LDA #RESET_OUT_MASK /* contents of A will be driven to PTA in order to switch the driver off */
CLRX /* prepare HX to point to PTA */
CLRH
/* bit 7 (MSB) */
bset 7,0
com ,x
//mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
PSHX /* store the value on the stack */
CLRX /* clear X again */
/* bit 6 */
bset 7,0
com ,x
//mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
PSHX /* store the value on the stack */
CLRX /* clear X again */
/* bit 5 */
bset 7,0
com ,x//mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
PSHX /* store the value on the stack */
CLRX /* clear X again */
/* bit 4 */
bset 7,0
com ,x//mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
PSHX /* store the value on the stack */
CLRX /* clear X again */
/* bit 3 */
bset 7,0
com ,x//mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
PSHX /* store the value on the stack */
CLRX /* clear X again */
/* bit 2 */
bset 7,0
com ,x
//mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
PSHX /* store the value on the stack */
CLRX /* clear X again */
/* bit 1 */
bset 7,0
com ,x
//mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
PSHX /* store the value on the stack */
CLRX /* clear X again */
/* bit 0 */
bset 7,0
com ,x
//mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
/* now get the bit values (last value is in X, previous 7 on stack) */
JMP rx_stack_decode
}
}
/* 5.4 - 7.8 MHz */
unsigned char bdm_rx2(void) {
#pragma NO_RETURN
asm {
LDA #RESET_OUT_MASK /* contents of A will be driven to PTA in order to switch the driver off */
CLRX /* prepare HX to point to PTA */
CLRH
/* bit 7 (MSB) */
mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
NOP /* wait 1 cycle */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
PSHX /* store the value on the stack */
CLRX /* clear X again */
/* bit 6 */
mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
NOP /* wait 1 cycle */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
PSHX /* store the value on the stack */
CLRX /* clear X again */
/* bit 5 */
mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
NOP /* wait 1 cycle */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
PSHX /* store the value on the stack */
CLRX /* clear X again */
/* bit 4 */
mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
NOP /* wait 1 cycle */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
PSHX /* store the value on the stack */
CLRX /* clear X again */
/* bit 3 */
mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
NOP /* wait 1 cycle */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
PSHX /* store the value on the stack */
CLRX /* clear X again */
/* bit 2 */
mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
NOP /* wait 1 cycle */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
PSHX /* store the value on the stack */
CLRX /* clear X again */
/* bit 1 */
mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
NOP /* wait 1 cycle */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
PSHX /* store the value on the stack */
CLRX /* clear X again */
/* bit 0 */
mov #0x10,0
//STX ,X /* drive BDM low */
STA ,X /* switch BDM to high impedance */
NOP /* wait 1 cycle */
LDX ,X /* load X with value on the PTA port (including BDM_IN) */
/* now get the bit values (last value is in X, previous 7 on stack) */
JMP rx_stack_decode
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -