?? isp.c
字號:
/* * Name: isp.c * Project: AVR-Doper * Author: Christian Starkjohann <cs@obdev.at> * Creation Date: 2006-06-21 * Tabsize: 4 * Copyright: (c) 2006 by Christian Starkjohann, all rights reserved. * License: Proprietary, see documentation. * Revision: $Id: isp.c 223 2006-07-18 09:28:13Z cs $ */#include "hardware.h"#include <avr/io.h>#include <avr/wdt.h>#include <avr/interrupt.h>#include "utils.h"#include <util/delay.h>#include "isp.h"#include "timer.h"#include "oddebug.h"static uchar ispClockDelay;static uchar cmdBuffer[4];/* ------------------------------------------------------------------------- *//* 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, 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)); do{ 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); shift <<= 1; port &= ~(1 << PORT_BIT(HWPIN_ISP_MOSI)); if(!PORT_PIN_VALUE(HWPIN_ISP_MISO)) /* driver is inverting */ shift |= 1; sei(); timerTicksDelay(delay); cli(); PORT_PIN_CLR(HWPIN_ISP_SCK); }while(--cnt); }while(--len); sei();/* DBG2(0x41, &shift, 1); */ return shift;}/* ------------------------------------------------------------------------- */static uchar deviceIsBusy(void){ cmdBuffer[0] = 0xf0; cmdBuffer[1] = 0; return ispBlockTransfer(cmdBuffer, 4) & 1;}static uchar waitUntilReady(uchar msTimeout){ timerSetupTimeout(msTimeout); while(deviceIsBusy()){ if(timerTimeoutOccurred()) return STK_STATUS_RDY_BSY_TOUT; } return STK_STATUS_CMD_OK;}/* ------------------------------------------------------------------------- */static void ispAttachToDevice(uchar stk500Delay, uchar stabDelay){ PORT_PIN_SET(HWPIN_LED); 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 if(stk500Delay == 0){ /* 1.8 MHz nominal */ ispClockDelay = 0; }else if(stk500Delay == 1){ /* 460 kHz nominal */ ispClockDelay = 1; }else if(stk500Delay == 2){ /* 115 kHz nominal */ ispClockDelay = 2; }else if(stk500Delay == 3){ /* 58 kHz nominal */ ispClockDelay = 3; }else{ ispClockDelay = 1 + stk500Delay/4 + stk500Delay/16; } /* 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);}static void ispDetachFromDevice(uchar removeResetDelay){ PORT_OUT(HWPIN_ISP_SCK) &= ~((1 << PORT_BIT(HWPIN_ISP_SCK)) | (1 << PORT_BIT(HWPIN_ISP_MOSI))); PORT_PIN_SET(HWPIN_ISP_RESET); timerMsDelay(removeResetDelay); TCCR2 &= ~(1 << COM20); /* clear toggle on compare match mode */ PORT_PIN_CLR(HWPIN_ISP_DRIVER); /* detach from device */ PORT_DDR_SET(HWPIN_ISP_DRIVER); /* set pin level to low-Z 0 */ PORT_PIN_CLR(HWPIN_ISP_RESET); PORT_PIN_CLR(HWPIN_LED);}/* ------------------------------------------------------------------------- */uchar ispEnterProgmode(stkEnterProgIsp_t *param){uchar i, rval; ispAttachToDevice(stkParam.s.sckDuration, param->stabDelay); timerMsDelay(param->cmdExeDelay); for(i = param->synchLoops; 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: */ PORT_PIN_SET(HWPIN_ISP_SCK); timerTicksDelay(ispClockDelay); PORT_PIN_CLR(HWPIN_ISP_SCK); timerTicksDelay(ispClockDelay); } ispDetachFromDevice(0); return STK_STATUS_CMD_FAILED; /* failure */}void ispLeaveProgmode(stkLeaveProgIsp_t *param){ ispDetachFromDevice(param->preDelay); timerMsDelay(param->postDelay);}/* ------------------------------------------------------------------------- */uchar ispChipErase(stkChipEraseIsp_t *param){uchar maxDelay = param->eraseDelay;uchar rval = STK_STATUS_CMD_OK; ispBlockTransfer(param->cmd, 4); if(param->pollMethod != 0){ if(maxDelay < 10) /* allow at least 10 ms */ maxDelay = 10; rval = waitUntilReady(maxDelay); }else{ timerMsDelay(maxDelay); } return rval;}/* ------------------------------------------------------------------------- */uchar ispProgramMemory(stkProgramFlashIsp_t *param, uchar isEeprom){utilWord_t numBytes;uchar rval = STK_STATUS_CMD_OK;uchar valuePollingMask, rdyPollingMask;uint i; numBytes.bytes[1] = param->numBytes[0]; numBytes.bytes[0] = param->numBytes[1]; if(param->mode & 1){ /* page mode */ valuePollingMask = 0x20; rdyPollingMask = 0x40; }else{ /* word mode */ valuePollingMask = 4; rdyPollingMask = 8; } for(i = 0; rval == STK_STATUS_CMD_OK && i < numBytes.word; i++){ uchar x; wdt_reset(); cmdBuffer[1] = stkAddress.bytes[1]; cmdBuffer[2] = stkAddress.bytes[0]; cmdBuffer[3] = param->data[i]; x = param->cmd[0]; if(!isEeprom){ if((uchar)i & 1){ x |= 0x08; stkIncrementAddress(); }else{ x &= ~0x08; } }else{ stkIncrementAddress(); } cmdBuffer[0] = x;// if(cmdBuffer[3] == 0xff && !(param->mode & 1) && !isEeprom) /* skip 0xff in word mode */// continue; ispBlockTransfer(cmdBuffer, 4); if(param->mode & 1){ /* is page mode */ if(i < numBytes.word - 1 || !(param->mode & 0x80)) continue; /* not last byte written */ cmdBuffer[0] = param->cmd[1]; /* write program memory page */ ispBlockTransfer(cmdBuffer, 4); } /* poll for ready after each byte (word mode) or page (page mode) */ if(param->mode & valuePollingMask){ /* value polling */ uchar x = param->cmd[2]; /* read flash */ if((uchar)i & 1){ x |= 0x08; }else{ x &= ~0x08; } cmdBuffer[0] = x; timerSetupTimeout(param->delay); while(ispBlockTransfer(cmdBuffer, 4) != param->poll[0]){ if(timerTimeoutOccurred()){ rval = STK_STATUS_CMD_TOUT; break; } } }else if(param->mode & rdyPollingMask){ /* rdy/bsy polling */ rval = waitUntilReady(param->delay); }else{ /* must be timed delay */ timerMsDelay(param->delay); } } return rval;}/* ------------------------------------------------------------------------- */uint ispReadMemory(stkReadFlashIsp_t *param, stkReadFlashIspResult_t *result, uchar isEeprom){utilWord_t numBytes;uchar *p, cmd0;uint i; cmdBuffer[3] = 0; numBytes.bytes[1] = param->numBytes[0]; numBytes.bytes[0] = param->numBytes[1]; p = result->data; result->status1 = STK_STATUS_CMD_OK; cmd0 = param->cmd; for(i = 0; i < numBytes.word; i++){ wdt_reset(); cmdBuffer[1] = stkAddress.bytes[1]; cmdBuffer[2] = stkAddress.bytes[0]; if(!isEeprom){ if((uchar)i & 1){ cmd0 |= 0x08; stkIncrementAddress(); }else{ cmd0 &= ~0x08; } }else{ stkIncrementAddress(); } cmdBuffer[0] = cmd0; *p++ = ispBlockTransfer(cmdBuffer, 4); } *p = STK_STATUS_CMD_OK; /* status2 */ return numBytes.word + 2;}/* ------------------------------------------------------------------------- */uchar ispProgramFuse(stkProgramFuseIsp_t *param){ ispBlockTransfer(param->cmd, 4); return STK_STATUS_CMD_OK;}/* ------------------------------------------------------------------------- */uchar ispReadFuse(stkReadFuseIsp_t *param){uchar rval; rval = ispBlockTransfer(param->cmd, param->retAddr); if(param->retAddr < 4) ispBlockTransfer(param->cmd + param->retAddr, 4 - param->retAddr); return rval;}/* ------------------------------------------------------------------------- */uint ispMulti(stkMultiIsp_t *param, stkMultiIspResult_t *result){uchar cnt1, i, *p; cnt1 = param->numTx; if(cnt1 > param->rxStartAddr) cnt1 = param->rxStartAddr; ispBlockTransfer(param->txData, cnt1); p = result->rxData; for(i = 0; i < param->numTx - cnt1; i++){ uchar b = ispBlockTransfer(¶m->txData[cnt1] + i, 1); if(i < param->numRx) *p++ = b; wdt_reset(); } for(; i < param->numRx; i++){ cmdBuffer[0] = 0; *p++ = ispBlockTransfer(cmdBuffer, 1); wdt_reset(); } *p = result->status1 = STK_STATUS_CMD_OK; return (uint)param->numRx + 2;}/* ------------------------------------------------------------------------- */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -