/* We disable interrupts while transfer a byte. This ensures that we execute * at nominal speed, in spite of aggressive USB polling. */ static uchar ispBlockTransfer(uchar *block, uchar len) { uchar cnt, shift = 0, port, delay = ispClockDelay; /* minimum clock pulse width: * 5 + 4 * delay clock cycles -> Tmin = 750 ns * total clock period: 12 + 8 * delay -> fmax = 600 kHz */ /* DBG2(0x40, block, len); */ cli(); port = PORT_OUT(HWPIN_ISP_MOSI) & ~(1 << PORT_BIT(HWPIN_ISP_MOSI)); while(len--){ /* len may be 0 */ cnt = 8; shift = *block++; do{ if(shift & 0x80){ port |= (1 << PORT_BIT(HWPIN_ISP_MOSI)); } PORT_OUT(HWPIN_ISP_MOSI) = port; sei(); timerTicksDelay(delay); cli(); PORT_PIN_SET(HWPIN_ISP_SCK); /* <-- data clocked by device */ shift <<= 1; port &= ~(1 << PORT_BIT(HWPIN_ISP_MOSI)); #if METABOARD_HARDWARE if(PORT_PIN_VALUE(HWPIN_ISP_MISO)) /* no driver in this hardware */ shift |= 1; #else /* METABOARD_HARDWARE */ if(!PORT_PIN_VALUE(HWPIN_ISP_MISO)) /* driver is inverting */ shift |= 1; #endif /* METABOARD_HARDWARE */ sei(); timerTicksDelay(delay); cli(); PORT_PIN_CLR(HWPIN_ISP_SCK); /* <-- device changes data */ }while(--cnt); } sei(); /* DBG2(0x41, &shift, 1); */ return shift; }
static void ispAttachToDevice(_u8 stk500Delay, _u8 stabDelay) { if(stk500Delay == 0){ /* 1.8 MHz nominal */ ispClockDelay = 0; }else if(stk500Delay == 1){ /* 460 kHz nominal */ ispClockDelay = 0; }else if(stk500Delay == 2){ /* 115 kHz nominal */ ispClockDelay = 1; }else if(stk500Delay == 3){ /* 58 kHz nominal */ ispClockDelay = 2; }else{ /* from STK500v2 spec: stk500Delay = 1/(24 * SCK / 7.37 MHz) - 10/12 * definition of ispClockDelay = 1 + 1/(SCK/MHz * 2 * TIMER_TICK_US) * ispClockDelay = 1 + (stk500Delay + 10/12) * 12 / (TIMER_TICK_US * 7.37) */ #if F_CPU > 14000000L /* ~ 16 MHz */ ispClockDelay = (stk500Delay + 1)/2 - (stk500Delay + 1)/8 + (stk500Delay + 1)/32; #else /* must be 12 MHz */ ispClockDelay = (stk500Delay + 1)/4 + (stk500Delay + 1)/16; #endif } LED_TX_ON(); /* turn on power for programming sockets: */ PIN_MODE(ISP_SCK, OUTPUT); PIN_MODE(ISP_MOSI,OUTPUT); // delay(200); /* allow device to power up */ PIN_MODE(ISP_RST,OUTPUT); delay(stabDelay); timerTicksDelay(ispClockDelay); /* stabDelay may have been 0 */ DIGITAL_WRITE(ISP_RST, HIGH); /* give positive RESET pulse */ timerTicksDelay(ispClockDelay); DIGITAL_WRITE(ISP_RST, LOW); /* bring RESET back low */ }
_u8 ispEnterProgmode(stkEnterProgIsp_t *param) { _u8 i, rval; ispAttachToDevice(stkParam.s.sckDuration, param->stabDelay); delay(param->cmdExeDelay); /* we want for(i = param->synchLoops; i--;), but avrdude sends synchLoops == 0 */ for(i = 32; i--;){ wdt_reset(); rval = ispBlockTransfer(param->cmd, param->pollIndex); if(param->pollIndex < 4) ispBlockTransfer(param->cmd + param->pollIndex, 4 - param->pollIndex); if(rval == param->pollValue){ /* success: we are in sync */ return STK_STATUS_CMD_OK; } /* insert one clock pulse and try again: */ DIGITAL_WRITE(ISP_SCK, HIGH); timerTicksDelay(ispClockDelay); DIGITAL_WRITE(ISP_SCK, LOW); timerTicksDelay(ispClockDelay); } ispDetachFromDevice(); return STK_STATUS_CMD_FAILED; /* failure */ }
/* We disable interrupts while transfer a byte. This ensures that we execute * at nominal speed, in spite of aggressive USB polling. */ static _u8 ispBlockTransfer(_u8 *block, _u8 len) { _u8 cnt, shift = 0, port, delay = ispClockDelay; /* minimum clock pulse width: * 5 + 4 * delay clock cycles -> Tmin = 750 ns * total clock period: 12 + 8 * delay -> fmax = 600 kHz */ cli(); while(len--){ /* len may be 0 */ cnt = 8; shift = *block++; do{ if(shift & 0x80){ DIGITAL_WRITE(ISP_MOSI, HIGH); }else { DIGITAL_WRITE(ISP_MOSI, LOW); } sei(); timerTicksDelay(delay); cli(); DIGITAL_WRITE(ISP_SCK, HIGH); /* <-- data clocked by device */ shift <<= 1; if(DIGITAL_READ(ISP_MISO)) /* no driver in this hardware */ shift |= 1; sei(); timerTicksDelay(delay); cli(); DIGITAL_WRITE(ISP_SCK, LOW); /* <-- device changes data */ }while(--cnt); } sei(); return shift; }
static void ispAttachToDevice(uchar stk500Delay, uchar stabDelay) { #if !METABOARD_HARDWARE /* on metaboard, we use the jumper to select CDC vs. HID mode */ if(!PORT_PIN_VALUE(HWPIN_JUMPER)){ /* Jumper is set -> request clock below 8 kHz */ ispClockDelay = (uchar)(70/TIMER_TICK_US); /* 140 us -> 7.14 kHz clock rate */ }else #endif if(stk500Delay == 0){ /* 1.8 MHz nominal */ ispClockDelay = 0; }else if(stk500Delay == 1){ /* 460 kHz nominal */ ispClockDelay = 0; }else if(stk500Delay == 2){ /* 115 kHz nominal */ ispClockDelay = 1; }else if(stk500Delay == 3){ /* 58 kHz nominal */ ispClockDelay = 2; }else{ /* from STK500v2 spec: stk500Delay = 1/(24 * SCK / 7.37 MHz) - 10/12 * definition of ispClockDelay = 1 + 1/(SCK/MHz * 2 * TIMER_TICK_US) * ispClockDelay = 1 + (stk500Delay + 10/12) * 12 / (TIMER_TICK_US * 7.37) */ #if F_CPU > 14000000L /* ~ 16 MHz */ ispClockDelay = (stk500Delay + 1)/2 - (stk500Delay + 1)/8 + (stk500Delay + 1)/32; #else /* must be 12 MHz */ ispClockDelay = (stk500Delay + 1)/4 + (stk500Delay + 1)/16; #endif } #if METABOARD_HARDWARE PORT_PIN_CLR(HWPIN_LED); /* turn on LED */ /* turn on power for programming sockets: */ PORT_OUT(HWPIN_ISP_SUPPLY1) |= _BV(PORT_BIT(HWPIN_ISP_SUPPLY1)) | _BV(PORT_BIT(HWPIN_ISP_SUPPLY2)); #ifdef HWPIN_ISP_CLK PORT_DDR_SET(HWPIN_ISP_CLK); /* turn on optional clock for programming socket */ #endif PORT_DDR_SET(HWPIN_ISP_SCK); /* enable programming I/O pins */ PORT_DDR_SET(HWPIN_ISP_MOSI); timerMsDelay(200); /* allow device to power up */ PORT_DDR_SET(HWPIN_ISP_RESET); timerMsDelay(stabDelay); timerTicksDelay(ispClockDelay); /* stabDelay may have been 0 */ PORT_PIN_SET(HWPIN_ISP_RESET); /* give positive RESET pulse */ timerTicksDelay(ispClockDelay); PORT_PIN_CLR(HWPIN_ISP_RESET); /* bring RESET back low */ #else /* METABOARD_HARDWARE */ PORT_PIN_SET(HWPIN_LED); /* setup initial condition: SCK, MOSI = 0 */ PORT_OUT(HWPIN_ISP_SCK) &= ~((1 << PORT_BIT(HWPIN_ISP_SCK)) | (1 << PORT_BIT(HWPIN_ISP_MOSI))); PORT_PIN_SET(HWPIN_ISP_RESET); /* set RESET */ PORT_DDR_CLR(HWPIN_ISP_DRIVER); /* make input: use internal pullup to control driver */ PORT_PIN_SET(HWPIN_ISP_DRIVER); /* attach to device: */ TCCR2 |= (1 << COM20); /* set toggle on compare match mode -> activate clock */ timerMsDelay(stabDelay); timerTicksDelay(ispClockDelay); /* stabDelay may have been 0 */ /* We now need to give a positive pulse on RESET since we can't guarantee * that SCK was low during power up (according to instructions in Atmel's * data sheets). */ PORT_PIN_CLR(HWPIN_ISP_RESET); /* give a positive RESET pulse */ timerTicksDelay(ispClockDelay); PORT_PIN_SET(HWPIN_ISP_RESET); #endif /* METABOARD_HARDWARE */ }