/*************************************************************************\ * Copyright (C) <2001> * antone@sentechsa.com * * 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 * \*************************************************************************/ /********************************************************************\ * Commandline utility to program AVR ATmegas with JTAG interface * * $Id: javr.c,v 1.11 2005/10/17 18:26:00 anton Exp $ * $Log: javr.c,v $ * Revision 1.11 2005/10/17 18:26:00 anton * Added display of built version in help text. (Linux, Cygwin or Mingw) * * Revision 1.10 2005/10/17 18:01:23 anton * command line parsing and file reading has been split. * version upped to version 2.7 * * Revision 1.9 2005/03/23 21:03:49 anton * Added GPL License to source files * * Revision 1.8 2005/03/23 20:16:12 anton * Updates by Uwe Bonnes to add support for AT90CAN128 * * Revision 1.7 2005/03/23 19:43:33 anton * Changed email address displayed when using --help option * * Revision 1.6 2003/09/28 14:31:04 anton * Added --help command, display GPL * * Revision 1.5 2003/09/28 12:44:15 anton * Updated Verify to show progress '.' * * Revision 1.3 2003/09/27 19:21:59 anton * Added support for Linux compile * * Revision 1.2 2003/09/24 20:18:08 anton * Added Verify option - Not tested yet * * Revision 1.1.1.1 2003/09/24 15:35:57 anton * Initial import into CVS * \********************************************************************/ /********************************************************************\ * Use ioperm under cygwin to get access to IO-Ports in W2K and XP * Use ioperm -i to install under W2K and XP * Use ioperm -u to uninstall * (ioperm should work under su access in linux) \********************************************************************/ #ifdef __CYGWIN32__ #define USE_IOPERM 1 #define BUILD_STR "Cygwin version\r\n" #endif #ifndef __CYGWIN32__ #ifdef __unix__ #define USE_IOPERM 1 #define BUILD_STR "Unix/Linux version\r\n" #endif #endif #include "compiler.h" #include #include #include #ifdef USE_IOPERM #include #endif #include "srecdec.h" #include "fuse.h" #include "avr_jtag.h" #include "parse.h" #include "menu.h" #include "command.h" #define JAVR_M #include "javr.h" #undef JAVR_M #ifndef USE_IOPERM #define BUILD_STR "Mingw version (Needs giveio.sys under Windows XP or Windows 2000)\r\n" #endif int main(int argc, char *argv[]) { if(argc==1) { printf("\r\njavr [] [-p] [-f] [-e] [-L] [-V]\r\n"); gDisplayMenu=1; } if(DecodeHelpRequest(argc,argv)) { printf("javr Ver %s, (C) AJ Erasmus 2001 - Compiled " __DATE__ " " __TIME__"\r\n",gVersionStr); printf("Programs Atmel AVR MCUs using the PC Parallel port and\r\n" \ "the JTAG interface of the AVR.\r\n\n" BUILD_STR \ "\nemail:%s@%s.%s\r\n\r\n" \ "This program is free software; you can redistribute it and/or modify\r\n" \ "it under the terms of the GNU General Public License as published by\r\n" \ "the Free Software Foundation; either version 2 of the License, or\r\n" \ "(at your option) any later version.\r\n\r\n" \ "This program is distributed in the hope that it will be useful,\r\n" \ "but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n" \ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r\n" \ "GNU General Public License for more details.\r\n","antone","sentechsa","com"); printf("\r\njavr [] [-p] [-f] [-e] [-L] [-V]\r\n" \ "port: 1-3 (0x378 (default), 0x278, 0x3BC)\r\n" \ " > 3 -> Port Address to Use in Hex\r\n" \ "e.g. javr -p378 will use port 0x378\r\n" \ "filename: S-Record File to program (Default Extention is .rom)\r\n" \ "fusefilename: Text File describing fuses to program (Default Extention is .fus)\r\n" \ "eepromfilename: S-Record File to program (Default Extention is .eep)\r\n" \ "-L: Program Lockbits if defined in fusefile\r\n" \ "-V: Verify against flash\r\n\n" \ ); exit(0); } AllocateFlashBuffer(); DecodeCommandLine(argc,argv); #ifdef USE_IOPERM printf("Using ioperm to gain port access to 0x%3.3X\r\n",gPort); if(ioperm(gPort,8,1)) { perror("ioperm failed\r\n"); exit(1); } #else printf("Using Port at address 0x%3.3X !\r\n",gPort); #endif Reset_JTAG(); Restore_Idle(); gJTAG_ID=ReadJTAGID(); DisplayJTAG_ID(); switch(gDeviceData.Index) { case ATMEGA128: case ATMEGA64: case ATMEGA32: case ATMEGA16: case ATMEGA162: case ATMEGA169: case AT90CAN128: break; default: fprintf(stderr,"Supported devices: "); fprintf(stderr,"ATMega128"); fprintf(stderr," ,ATMega64"); fprintf(stderr," ,ATMega32"); fprintf(stderr," ,ATMega16"); fprintf(stderr," ,ATMega162"); fprintf(stderr," ,ATMega169"); fprintf(stderr," ,AT90CAN128"); fprintf(stderr,"\r\n"); exit(-1); break; } ReadFiles(argc,argv); ResetAVR(); AVR_Prog_Enable(); /* printf(">>>%4.4X<<<\r\n",ReadFlashWord(0x00)); */ if(gProgramFuseBits) { printf("\r\nProgramming Fuse Bits\r\n"); WriteATMegaFuse(); } else { ReadATMegaFuse(); } AVR_Prog_Disable(); if(gProgramFlash && !gVerifyOption) { printf("\r\nErasing Flash"); if(gFuseBitsAll.EESAVE) { printf(" and EEPROM"); } AVR_Prog_Enable(); ChipErase(); printf("\r\nProgramming Flash\r\n"); WriteFlashBlock(gSourceInfo.StartAddr,gSourceInfo.EndAddr-gSourceInfo.StartAddr+1 , gFlashBuffer); AVR_Prog_Disable(); } if(gProgramFlash && gVerifyOption) { int i; printf("\r\nVerifying Flash\r\n"); i=VerifyFlashBlock(gSourceInfo.StartAddr,gSourceInfo.EndAddr-gSourceInfo.StartAddr+1 , gFlashBuffer); printf("\r\nFlash Verified with %d errors\r\n",i); } if(gProgramEeprom) { if(!gProgramFlash || !gFuseBitsAll.EESAVE) { printf("EEPROM was not erased before programming - EEPROM NOT reprogrammed\r\n"); } else { printf("\r\nProgramming EEPROM\r\n"); AVR_Prog_Enable(); WriteEepromBlock(gEepromInfo.StartAddr,gEepromInfo.EndAddr-gEepromInfo.StartAddr+1 , gEEPROMBuffer); AVR_Prog_Disable(); } } if(gProgramFuseBits) { if(gLockOption) /* Command line option -L must be present */ { printf("\r\nProgramming Lock bits\r\n"); AVR_Prog_Enable(); WriteATMegaLock(); /* Will only program if bits defined in fuse file */ AVR_Prog_Disable(); } } if(gDisplayMenu) DisplayMenu(); AVR_Prog_Disable(); ResetReleaseAVR(); OUT(gPort,0xFF); return(0); } /********************************************************************\ * Emulate Current State of TAP State Maschine. Routine Should be * * called every rising edge of TCK * * * \********************************************************************/ void EmulateTAP(char TMS) { switch(gTAPState) { case TEST_LOGIC_RESET: if(!TMS) gTAPState=RUN_TEST_IDLE; break; case RUN_TEST_IDLE: if(TMS) gTAPState=SELECT_DR_SCAN; break; case SELECT_DR_SCAN: if(!TMS) gTAPState=CAPTURE_DR; else gTAPState=SELECT_IR_SCAN; break; case CAPTURE_DR: if(!TMS) gTAPState=SHIFT_DR; else gTAPState=EXIT1_DR; break; case SHIFT_DR: if(TMS) gTAPState=EXIT1_DR; break; case EXIT1_DR: if(!TMS) gTAPState=PAUSE_DR; else gTAPState=UPDATE_DR; break; case PAUSE_DR: if(TMS) gTAPState=EXIT2_DR; break; case EXIT2_DR: if(TMS) gTAPState=UPDATE_DR; else gTAPState=SHIFT_DR; break; case UPDATE_DR: if(TMS) gTAPState=SELECT_DR_SCAN; else gTAPState=RUN_TEST_IDLE; break; case SELECT_IR_SCAN: if(!TMS) gTAPState=CAPTURE_IR; else gTAPState=TEST_LOGIC_RESET; break; case CAPTURE_IR: if(!TMS) gTAPState=SHIFT_IR; else gTAPState=EXIT1_IR; break; case SHIFT_IR: if(TMS) gTAPState=EXIT1_IR; break; case EXIT1_IR: if(!TMS) gTAPState=PAUSE_IR; else gTAPState=UPDATE_IR; break; case PAUSE_IR: if(TMS) gTAPState=EXIT2_IR; break; case EXIT2_IR: if(TMS) gTAPState=UPDATE_IR; else gTAPState=SHIFT_IR; break; case UPDATE_IR: if(TMS) gTAPState=SELECT_IR_SCAN; else gTAPState=RUN_TEST_IDLE; break; default: if(TMS) gTAPState=TEST_LOGIC_RESET; break; } if(gOldTAPState!=gTAPState) { printf("%s\r\n",gTAPStateNames[(int)gTAPState]); gOldTAPState=gTAPState; } } /********************************************************************\ * * * Reset JTAG via the TRST# Signal * * * \********************************************************************/ void Reset_JTAG(void) { OUT(gPort,0); OUT(gPort,BIT_MASK(RESET_BIT)); /* Reset Enabled */ OUT(gPort+2,0);//BIT_MASK(ENABLE_BIT)); /* Enable 244 Buffer */ OUT(gPort,0); } /********************************************************************\ * * * Go into Run-Test/Idle State from unknown state * * * \********************************************************************/ void Restore_Idle(void) { unsigned char i; for(i=0;i<6;i++) { TMS_High(); } } /********************************************************************\ * * * One Transition with TMS High * * * \********************************************************************/ void TMS_High(void) { OUT(gPort,BIT_MASK(TMS_BIT)); OUT(gPort,BIT_MASK(TMS_BIT)|BIT_MASK(TCK_BIT)); OUT(gPort,BIT_MASK(TMS_BIT)); } /********************************************************************\ * * * One Transition with TMS low * * * \********************************************************************/ void TMS_Low(void) { OUT(gPort,0); OUT(gPort,BIT_MASK(TCK_BIT)); OUT(gPort,0); } void Shift_Data_Array(int Size, char *Input) { unsigned char i; Size--; while(Size) { i=0; if(*Input=='1') { i=BIT_MASK(TDI_BIT); } OUT(gPort,i); /* TCK Low, TDI Dependant on *Input */ i|=BIT_MASK(TCK_BIT); OUT(gPort,i); /* TCK High */ Input++; Size--; } i=BIT_MASK(TMS_BIT); if(*Input=='1') { i|=BIT_MASK(TDI_BIT); } OUT(gPort,i); /* TCK Low, TDI Dependant on *Input */ i|=BIT_MASK(TCK_BIT); OUT(gPort,i); /* TCK High */ OUT(gPort,BIT_MASK(TDI_BIT)|BIT_MASK(TMS_BIT)); /* Leave TCK Low */ } void Shift_Data_Array_Output(int Size, char *Input, char *Output) { unsigned char i; Size--; while(Size) { i=0; if(*Input=='1') { i=BIT_MASK(TDI_BIT); } OUT(gPort,i); /* TCK Low, TDI Dependant on *Input */ i|=BIT_MASK(TCK_BIT); OUT(gPort,i); /* TCK High */ if(IN(gPort+1)&BIT_MASK(TDO_BIT)) { *Output='0'; } else { *Output='1'; } Input++; Output++; Size--; } i=BIT_MASK(TMS_BIT); if(*Input=='1') { i|=BIT_MASK(TDI_BIT); } OUT(gPort,i); /* TCK Low, TDI Dependant on *Input */ i|=BIT_MASK(TCK_BIT); OUT(gPort,i); /* TCK High */ if(IN(gPort+1)&BIT_MASK(TDO_BIT)) { *Output='0'; } else { *Output='1'; } Output++; *Output=0; OUT(gPort,BIT_MASK(TDI_BIT)|BIT_MASK(TMS_BIT)); /* Leave TCK Low */ } void Send_Instruction(int Size, char *Data) { TMS_Low(); /* Run-Test / Idle */ TMS_Low(); /* Run-Test / Idle */ TMS_High(); /* Select DR-Scan */ TMS_High(); /* Select IR-Scan */ TMS_Low(); /* Capture IR */ TMS_Low(); /* Shift IR */ Shift_Data_Array(Size, Data); TMS_High(); /* Update-IR -> New Instruction in Effect */ TMS_Low(); /* Run-Test / Idle */ TMS_Low(); /* Run-Test / Idle */ } void Send_Data(int Size, char *Data) { TMS_Low(); /* Run-Test / Idle */ TMS_Low(); /* Run-Test / Idle */ TMS_High(); /* Select DR-Scan */ TMS_Low(); /* Capture DR */ TMS_Low(); /* Shift DR */ Shift_Data_Array(Size, Data); TMS_High(); /* Update-IR -> New Instruction in Effect */ TMS_Low(); /* Run-Test / Idle */ TMS_Low(); /* Run-Test / Idle */ } void Send_Instruction_Output(int Size, char *Data, char *Output) { TMS_Low(); /* Run-Test / Idle */ TMS_Low(); /* Run-Test / Idle */ TMS_High(); /* Select DR-Scan */ TMS_High(); /* Select IR-Scan */ TMS_Low(); /* Capture IR */ TMS_Low(); /* Shift IR */ Shift_Data_Array_Output(Size, Data, Output); TMS_High(); /* Update-IR -> New Instruction in Effect */ TMS_Low(); /* Run-Test / Idle */ TMS_Low(); /* Run-Test / Idle */ } void Send_Data_Output(int Size, char *Data, char *Output) { TMS_Low(); /* Run-Test / Idle */ TMS_Low(); /* Run-Test / Idle */ TMS_High(); /* Select DR-Scan */ TMS_Low(); /* Capture DR */ TMS_Low(); /* Shift DR */ Shift_Data_Array_Output(Size, Data, Output); TMS_High(); /* Update-IR -> New Instruction in Effect */ TMS_Low(); /* Run-Test / Idle */ TMS_Low(); /* Run-Test / Idle */ } JTAG_ID ReadJTAGID(void) { char id[33]; unsigned long tmp; JTAG_ID jtag_id; Send_Instruction(4,IDCODE); Send_Data_Output(32,id,id); tmp=ArrayToUL(32,id); tmp>>=1; jtag_id.manuf_id=tmp; tmp>>=11; jtag_id.partnumber=tmp; tmp>>=16; jtag_id.version=tmp; return(jtag_id); } /********************************************************************\ * * * Convert a binary character array into a long. * * LSB of Number is first in Array * * * \********************************************************************/ unsigned long ArrayToUL(unsigned char Size, char *ptr) { unsigned long tmp,mask; unsigned char i; tmp=0; mask=1; for(i=0;i