avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[avr-gcc-list] PonyProg Interface for UISP


From: Uwe Bonnes
Subject: [avr-gcc-list] PonyProg Interface for UISP
Date: Thu, 8 Mar 2001 18:23:56 +0100

Hallo Marek,

please find appended a patch to uisp-20010211 that adds the PonyProg
Interface to uisp. I had posted a similar patch last year.

Find more info about PonyProg at http://www.lancos.com/prog.html and in the
header of PonyProg.C.

The Ponyprog interface is very similar to the DAPA interface, but uses the
serial port instead of the parallel port. I use it heavily on my designs, as
I have to put only a few parts on the Microcontroller board (1 Sub-D Socket,
4 resistors, 2 Diodes, 2 Z-Diodes and one transistor) to get a fully
functional programming interface to the AVR board. Only a normal serial line
cable is needed to connect the PC to the board.

Because of lack of C++ knowledge I nearly duplicated AvrDummy.C to link down
to PonyProg.C where all the interface dependant code resides.

Main.c|
      |-- AvrAtmel.C --- Serial.C
      |
      |-- AvrDummy.C --- DAPA.C
      |
      |-- PonyDummy.C -- PonyProg.C

I would like to hear for a solution that doesnt need PonyProg.C but would
reuse AvrDummy.C.

Ponyprog.C only uses the IOCTL interface to the serial port. No direct IO is
provided. 

Bye
-- 
Uwe Bonnes                address@hidden

Institut fuer Kernphysik  Schlossgartenstrasse 9  64289 Darmstadt
--------- Tel. 06151 162516 -------- Fax. 06151 164321 ----------

diff -uwrN uisp-20010211.orig/src/Main.C uisp-20010211/src/Main.C
--- uisp-20010211.orig/src/Main.C       Sun Feb 11 20:44:17 2001
+++ uisp-20010211/src/Main.C    Thu Mar  8 16:56:48 2001
@@ -12,6 +12,7 @@
 #include "Terminal.h"
 #include "MotIntl.h"
 #include "AvrAtmel.h"
+#include "PonyDummy.h"
 #ifndef NO_DAPA
 # include "AvrDummy.h"
 #endif
@@ -29,7 +30,8 @@
 TTerminal terminal;
 
 const char* version = "uisp version 0.2b, Uros Platise (c) 1997-1999\n"
-"uisp-20010211 update by Marek Michalkiewicz\n";
+"uisp-20010211 update by Marek Michalkiewicz\n"
+"ponyprog Interface by Uwe Bonnes address@hidden";
 const char* help_screen =
 "Syntax: uisp [-v{=level}] [-h] [--help] [--version] [--hash=perbytes]\n"
 "             [-datmel]"
@@ -46,6 +48,7 @@
 "             [--segment=flash|eeprom|fuse] [--terminal]\n\n"
 "Programming Methods:\n"
 "  -datmel      Standard Atmel Serial Programmer/Atmel Low Cost Programmer\n"
+"  -dpony       Serial Programmer connected in PonyProg way\n"
 #ifndef NO_DAPA
 "  -dapa        Direct AVR Parallel Access\n"
 "  -dstk200     Parallel Starter-Kit 200\n"
@@ -73,6 +76,11 @@
 "               are listed. Set -dpart=auto for auto-select.\n"
 "  -dspeed      Set speed of the serial interface (default 19200)\n"
 "\n"
+"PonyProg Settings:\n"
+"  -dserial     Set serial interface as /dev/ttySx (default /dev/avr)\n"
+"  -dinvert     [mosi,miso,sck] Invert the given line\n"
+"  -dreset      account for additional reset delay (in milliseconds)\n"
+"\n"
 "Functions:\n"
 "  --upload     Upload \"input_file\" to the AVR memory.\n"
 "  --verify     Verify \"input_file\" (processed after the --upload opt.)\n"
@@ -179,6 +187,7 @@
       setgid(getgid());
       setuid(getuid());
       if (GetCmdParam("-datmel", false)){ device = new TAvrAtmel(); }
+      if (GetCmdParam("-dpony", false)){device = new TPonyDummy();}
     }
 
     /* Check Device's bad command line params. */
diff -uwrN uisp-20010211.orig/src/Makefile uisp-20010211/src/Makefile
--- uisp-20010211.orig/src/Makefile     Sat Feb 10 15:26:58 2001
+++ uisp-20010211/src/Makefile  Thu Mar  8 16:56:48 2001
@@ -35,10 +35,10 @@
 CPPFLAGS= -Wall -O3 -g # -DHAVE_PPI # -DNO_DIRECT_IO # -DOLD_DELAY_LOOP # 
-DNO_DAPA
 
 SRC    = Main.C Terminal.C MotIntl.C Avr.C AvrAtmel.C AvrDummy.C \
-         Serial.C DAPA.C
+         Serial.C DAPA.C PonyDummy.C PonyProg.C
 
 OBJ    = Main.o Terminal.o MotIntl.o Avr.o AvrAtmel.o AvrDummy.o \
-         Serial.o DAPA.o
+         Serial.o DAPA.o PonyDummy.o PonyProg.o
          
 all:   uisp
 
diff -uwrN uisp-20010211.orig/src/PonyDummy.C uisp-20010211/src/PonyDummy.C
--- uisp-20010211.orig/src/PonyDummy.C  Thu Jan  1 01:00:00 1970
+++ uisp-20010211/src/PonyDummy.C       Thu Mar  8 16:56:48 2001
@@ -0,0 +1,503 @@
+/*
+       PonyDummy.C
+       
+       Dummy device driver for the Ponyprog access
+       Uros Platise (c) 1999
+*/
+
+
+#include <string.h>
+#include "timeradd.h"
+#include "PonyDummy.h"
+#include "Error.h"
+
+/* Private Functions
+*/
+
+void TPonyDummy::EnableAvr(){
+  unsigned char prg  [4] = { 0xAC, 0x53, 0, 0 };
+  int try_number = 32;
+  bool no_retry = GetCmdParam("-dno-retry", false);
+  const char *part_name = GetCmdParam("-dpart");
+
+  if (part_name && strcasecmp(part_name, "at90s1200") == 0)
+    no_retry = true;  /* XXX */
+
+  /* Enable AVR programming mode */
+  do{
+    prg[0]=0xAC; prg[1]=0x53; prg[2]=prg[3]=0;
+    Send(prg, 4);
+    if (no_retry) break;
+    if (prg[2] == 0x53) break;
+    PulseSck();
+  } while (try_number--);
+  
+  if (try_number<=32){
+    Info(2,"AVR Direct Parallel Access succeeded after %d retries.\n", 
+      32-try_number);
+  }
+  
+  /* Get AVR Info */
+  vendor_code = GetPartInfo(0); 
+  part_family = GetPartInfo(1);
+  part_number = GetPartInfo(2);    
+  Identify();
+}
+
+TByte TPonyDummy::GetPartInfo(TAddr addr){
+  TByte info [4] = { 0x30, 0, addr, 0 };
+  Send(info, 4);
+  return info[3];
+}
+
+void TPonyDummy::WriteProgramMemoryPage()
+{
+  struct timeval t_start_wr, t_start_poll, t_wait, t_timeout, t_end, t_write;
+
+  bool poll_data = use_data_polling && TestFeatures(AVR_PAGE_POLL)
+                  && (page_poll_byte != 0xFF);
+
+  TByte prg_page [4] = { 0x4C,
+                       (TByte)((page_addr >> 9) & 0xff),
+                       (TByte)((page_addr >> 1) & 0xff),
+                       0 };
+
+  gettimeofday(&t_start_wr, NULL);
+  t_wait.tv_sec = 0;
+  t_wait.tv_usec = Get_t_wd_flash();
+
+  Info(4, "Programming page address: %d (%.2x, %.2x, %.2x, %.2x)\n", 
+    page_addr, prg_page[0], prg_page[1], prg_page[2], prg_page[3]);
+  Send(prg_page, 4);
+
+  gettimeofday(&t_start_poll, NULL);
+  timeradd(&t_start_poll, &t_wait, &t_timeout);
+
+  /* Wait */
+  do {
+    gettimeofday(&t_end, NULL);
+    if (poll_data) {
+      TByte rbyte = ReadByte(page_poll_addr);
+      if (rbyte == page_poll_byte)
+       break;
+    }
+  } while (timercmp(&t_end, &t_timeout, <));
+
+  /* Write Statistics */
+  timersub(&t_end, &t_start_wr, &t_write);  /* t_write = t_end - t_start_wr */
+  if (poll_data) {
+    float write_time = 1.0e-6 * t_write.tv_usec + t_write.tv_sec;
+    total_poll_time += write_time;
+    if (max_poll_time < write_time)
+      max_poll_time = write_time;
+    if (min_poll_time > write_time)
+      min_poll_time = write_time;
+    total_poll_cnt++;
+  }
+
+  page_addr_fetched=false;
+  page_poll_byte = 0xFF;
+}
+
+
+/* Device Interface Functions
+*/
+
+TByte TPonyDummy::ReadByte(TAddr addr){
+  TByte readback = 0xFF;
+    
+  CheckMemoryRange(addr);
+  if (segment==SEG_FLASH){
+    TByte hl = (addr&1) ? 0x28 : 0x20;
+    addr>>=1;
+    TByte flash [4] = { hl, 
+                       (TByte)((addr >> 8) & 0xff),
+                       (TByte)(addr & 0xff),
+                       0 };
+    Send(flash, 4);
+    readback = flash[3];
+  }
+  else if (segment==SEG_EEPROM){
+    TByte eeprom [4] = { 0xA0, 
+                        (TByte)((addr>>8)&0xff), 
+                        (TByte)(addr&0xff), 
+                        0 };
+    Send(eeprom, 4);
+    readback = eeprom[3];
+  }
+  else if (segment==SEG_FUSE) {
+    switch (addr) {
+    case 0:
+      if (TestFeatures(AVR_FUSE_RD))
+       readback = ReadFuseLowBits();
+      else if (TestFeatures(AVR_LOCK_RD76))
+       readback = ReadLockFuseBits();
+      break;
+    case 1:
+      if (TestFeatures(AVR_FUSE_HIGH))
+       readback = ReadFuseHighBits();
+      break;
+    case 2:
+      if (TestFeatures(AVR_CAL_RD))
+       readback = ReadCalByte();
+      break;
+    case 3:
+      readback = ReadLockBits();
+      break;
+    }
+    Info(3, "Read fuse/cal/lock: byte %d = 0x%02X\n",
+        (int) addr, (int) readback);
+  }
+  return readback;
+}
+
+/*
+ Read Lock/Fuse Bits:           7     6     5     4     3     2     1     0
+ 2333,4433,m103,m603,tn12,tn15: x     x     x     x     x     LB2   LB1   x
+ 2323,8535:                     LB1   LB2   SPIEN x     x     x     x     FSTRT
+ 2343:                          LB1   LB2   SPIEN x     x     x     x     RCEN
+ tn22:                          LB1   LB2   SPIEN x     x     x     x     0
+ m161,m163:                     x     x     BLB12 BLB11 BLB02 BLB01 LB2   LB1
+ */
+TByte
+TPonyDummy::ReadLockFuseBits()
+{
+  TByte lockfuse[4] = { 0x58, 0, 0, 0 };
+  Send(lockfuse, 4);
+  return lockfuse[3];
+}
+
+/*
+ Read Fuse Bits (Low):          7     6     5     4     3     2     1     0
+ 2333,4433:                     x     x     SPIEN BODLV BODEN CKSL2 CKSL1 CKSL0
+ m103,m603:                     x     x     SPIEN x     EESAV 1     SUT1  SUT0
+ tn12:                          BODLV BODEN SPIEN RSTDI CKSL3 CKSL2 CKSL1 CKSL0
+ tn15:                          BODLV BODEN SPIEN RSTDI x     x     CKSL1 CKSL0
+ m161:                          x     BTRST SPIEN BODLV BODEN CKSL2 CKSL1 CKSL0
+ m163:                          BODLV BODEN SPIEN x     CKSL3 CKSL2 CKSL1 CKSL0
+ */
+TByte
+TPonyDummy::ReadFuseLowBits()
+{
+  TByte fuselow[4] = { 0x50, 0, 0, 0 };
+  Send(fuselow, 4);
+  return fuselow[3];
+}
+
+/*
+ Read Fuse Bits High:           7     6     5     4     3     2     1     0
+ m163:                          x     x     x     x     1     BTSZ1 BTSZ0 BTRST
+ */
+TByte
+TPonyDummy::ReadFuseHighBits()
+{
+  TByte fusehigh[4] = { 0x58, 0x08, 0, 0 };
+  Send(fusehigh, 4);
+  return fusehigh[3];
+}
+
+/* Read Calibration Byte (m163, tn12) */
+TByte
+TPonyDummy::ReadCalByte()
+{
+  TByte cal[4] = { 0x38, 0, 0, 0 };
+  Send(cal, 4);
+  return cal[3];
+}
+
+/*
+ Write Fuse Bits (old):         7     6     5     4     3     2     1     0
+ 2323,8535:                     x     x     x     1     1     1     1     FSTRT
+ 2343:                          x     x     x     1     1     1     1     RCEN
+ 2333,4433:                     x     x     x     BODLV BODEN CKSL2 CKSL1 CKSL0
+ m103,m603:                     x     x     x     1     EESAV 1     SUT1  SUT0
+ */
+void
+TPonyDummy::WriteOldFuseBits(TByte val)
+{
+  TByte oldfuse[4] = { 0xAC, (val & 0x1F) | 0xA0, 0, 0xD2 };
+  Send(oldfuse, 4);
+}
+
+/*
+ Write Fuse Bits (Low, new):    7     6     5     4     3     2     1     0
+ m161:                          1     BTRST 1     BODLV BODEN CKSL2 CKSL1 CKSL0
+ m163:                          BODLV BODEN 1     1     CKSL3 CKSL2 CKSL1 CKSL0
+ tn12:                          BODLV BODEN SPIEN RSTDI CKSL3 CKSL2 CKSL1 CKSL0
+ tn15:                          BODLV BODEN SPIEN RSTDI 1     1     CKSL1 CKSL0
+
+ WARNING (tn12,tn15): writing SPIEN=1 disables further low voltage programming!
+ */
+void
+TPonyDummy::WriteFuseLowBits(TByte val)
+{
+  TByte fuselow[4] = { 0xAC, 0xA0, 0, val };
+  Send(fuselow, 4);
+}
+
+/*
+ Write Fuse Bits High:          7     6     5     4     3     2     1     0
+ m163:                          1     1     1     1     1     BTSZ1 BTSZ0 BTRST
+ */
+void
+TPonyDummy::WriteFuseHighBits(TByte val)
+{
+  TByte fusehigh[4] = { 0xAC, 0xA8, 0, val };
+  Send(fusehigh, 4);
+}
+
+
+void TPonyDummy::WriteByte(TAddr addr, TByte byte, bool flush_buffer)
+{
+  struct timeval t_start_wr, t_start_poll, t_wait, t_timeout, t_end, t_write;
+  TByte rbyte=0;
+  bool device_not_erased=false;
+  
+  /* Poll data if use_data_polling is enabled and if page mode
+     is enabled, flash is not selected */
+  bool poll_data = ((segment==SEG_FLASH && !page_size) || segment==SEG_EEPROM)
+                  && use_data_polling && TestFeatures(AVR_BYTE_POLL);
+
+  CheckMemoryRange(addr);
+  
+  /* For speed, don't program a byte that is already there
+     (such as 0xFF after chip erase).  */
+  if (poll_data){
+    rbyte=ReadByte(addr);
+    if (rbyte == byte){return;}
+    if (rbyte != 0xff){device_not_erased=true;}
+  }
+  
+  t_wait.tv_sec = 0;
+  t_wait.tv_usec = 500000;
+
+  gettimeofday(&t_start_wr, NULL);
+
+  if (segment==SEG_FLASH){
+      
+    /* PAGE MODE PROGRAMMING:
+       If page mode is enabled cache page address.
+       When current address is out of the page address
+       flush page buffer and continue programming.
+    */
+    if (page_size) {
+      Info(4, "Loading data to address: %d (page_addr_fetched=%s)\n", 
+        addr, page_addr_fetched?"Yes":"No");
+       
+      if (page_addr_fetched && page_addr != (addr & ~(page_size - 1))){
+        WriteProgramMemoryPage();      
+      }
+      if (page_addr_fetched==false){
+        page_addr=addr & ~(page_size - 1);
+       page_addr_fetched=true;
+      }
+      if (flush_buffer){WriteProgramMemoryPage();}
+    }
+  
+    TByte hl = (addr&1) ? 0x48 : 0x40;
+    TByte flash [4] = { hl,
+                       (TByte)((addr >> 9) & 0xff),
+                       (TByte)((addr >> 1) & 0xff),
+                       byte };
+    Send(flash, 4);
+
+    /* Remember the last non-0xFF byte written, for page write polling.  */
+    if (byte != 0xFF) {
+      page_poll_addr = addr;
+      page_poll_byte = byte;
+    }
+
+    /* We do not need to wait for each byte in page mode programming */
+    if (page_size){return;}    
+    t_wait.tv_usec = Get_t_wd_flash();
+  }
+  else if (segment==SEG_EEPROM){
+    TByte eeprom [4] = { 0xC0, 
+                        (TByte)((addr>>8)&0xff), 
+                        (TByte)(addr&0xff),
+                        byte };
+    Send(eeprom, 4);  
+    t_wait.tv_usec = Get_t_wd_eeprom();    
+  }
+  else if (segment==SEG_FUSE) {
+    Info(3, "Write fuse/lock: byte %d = 0x%02X\n",
+        (int) addr, (int) byte);
+    switch (addr) {
+    case 0:
+      if (TestFeatures(AVR_FUSE_NEWWR))
+       WriteFuseLowBits(byte);
+      else if (TestFeatures(AVR_FUSE_OLDWR))
+       WriteOldFuseBits(byte);
+      break;
+    case 1:
+      if (TestFeatures(AVR_FUSE_HIGH))
+       WriteFuseHighBits(byte);
+      break;
+    /* calibration byte (addr == 2) is read only */
+    case 3:
+      WriteLockBits(byte);
+      break;
+    }
+    t_wait.tv_usec = Get_t_wd_eeprom();
+  }
+
+  gettimeofday(&t_start_poll, NULL);
+  /* t_timeout = now + t_wd_prog */
+  timeradd(&t_start_poll, &t_wait, &t_timeout);
+
+  do {
+    /* Data Polling: if the programmed value reads correctly, and
+       is not equal to any of the possible P1, P2 read back values,
+       it is done; else wait until tWD_PROG time has elapsed.
+       The busy loop here is to avoid rounding up the programming
+       wait time to 10ms timer ticks (for Linux/x86).  Programming
+       is not really "hard real time" but 10ms instead of ~4ms for
+       every byte makes it slow.  gettimeofday() reads the 8254
+       timer registers (or Pentium cycle counter if available),
+       so it has much better (microsecond) resolution.  
+    */
+    gettimeofday(&t_end, NULL);
+    if (poll_data){
+      if ((byte == (rbyte = ReadByte(addr))) &&
+          (byte != 0) && (byte != 0x7F) && (byte != 0x80) && (byte != 0xFF)){
+       break;
+      }
+    }
+  } while (timercmp(&t_end, &t_timeout, <));
+  
+  /* Write Statistics */
+  timersub(&t_end, &t_start_wr, &t_write);  /* t_write = t_end - t_start_wr */
+  if (poll_data) {
+    float write_time = 1.0e-6 * t_write.tv_usec + t_write.tv_sec;
+    total_poll_time += write_time;
+    if (max_poll_time < write_time)
+      max_poll_time = write_time;
+    if (min_poll_time > write_time)
+      min_poll_time = write_time;
+    total_poll_cnt++;
+  }
+
+  if (poll_data && byte != rbyte){
+    if (device_not_erased){
+      Info(0, "Warning: It seems that device is not erased.\n"
+              "         Erase it with the --erase option.\n");
+    }
+    Info(0, "Error: Data polling readback status: write=0x%02x read=0x%02x\n", 
+      byte, rbyte);
+    throw Error_Device("If device was erased disable polling with the "
+      "-dno-poll option.");
+  }
+}
+
+void TPonyDummy::FlushWriteBuffer(){
+  if (page_addr_fetched){
+    WriteProgramMemoryPage();  
+  }
+}
+
+void TPonyDummy::ChipErase(){
+  TByte chip_erase [4] = { 0xAC, 0x80, 0x00, 0x00 };
+  Info(1, "Erasing device ...\n");
+  Send (chip_erase, 4);
+  Delay_usec(Get_t_wd_erase());
+  PulseReset();
+  Info(1, "Reinitializing device\n");  
+  EnableAvr();
+}
+
+/*
+   0 = program (clear bit), 1 = leave unchanged
+   bit 0 = LB1
+   bit 1 = LB2
+   bit 2 = BLB01
+   bit 3 = BLB02
+   bit 4 = BLB11
+   bit 5 = BLB12
+   bit 6 = 1 (reserved)
+   bit 7 = 1 (reserved)
+ */
+void
+TPonyDummy::WriteLockBits(TByte bits)
+{
+  /* This handles both old (byte 2, bits 1-2)
+     and new (byte 4, bits 0-5) devices.  */
+  TByte lock[4] = { 0xAC, 0xF9 | ((bits << 1) & 0x06), 0xFF, bits };
+  TByte rbits;
+
+  Info(1, "Writing lock bits ...\n");
+  Send(lock, 4);
+  Delay_usec(Get_t_wd_erase());
+  PulseReset();
+  Info(1, "Reinitializing device\n");
+  EnableAvr();
+  rbits = ReadLockBits();
+  if (rbits & ~bits)
+    Info(0, "Warning: lock bits write=0x%02X read=0x%02X\n",
+        (int) bits, (int) rbits);
+}
+
+TByte
+TPonyDummy::ReadLockBits()
+{
+  TByte rbits = 0xFF;
+  if (TestFeatures(AVR_LOCK_BOOT)) {
+    /* x x BLB12 BLB11 BLB02 BLB01 LB2 LB1 */
+    rbits = ReadLockFuseBits();
+  } else if (TestFeatures(AVR_LOCK_RD76)) {
+    rbits = ReadLockFuseBits();
+    /* LB1 LB2 x x x x x x -> 1 1 1 1 1 1 LB2 LB1 */
+    rbits = ((rbits >> 7) & 1) | ((rbits >> 5) & 1) | 0xFC;
+  } else if (TestFeatures(AVR_LOCK_RD12)) {
+    rbits = ReadLockFuseBits();
+    /* x x x x x LB2 LB1 x -> 1 1 1 1 1 1 LB2 LB1 */
+    rbits = ((rbits >> 1) & 3) | 0xFC;
+  } else if (GetPartInfo(0) == 0 &&
+            GetPartInfo(1) == 1 &&
+            GetPartInfo(2) == 2) {
+    rbits = 0xFC;
+  }
+  return rbits;
+}
+
+unsigned int TPonyDummy::GetPollCount()
+{
+  return total_poll_cnt;
+}
+
+float TPonyDummy::GetMinPollTime()
+{
+  return min_poll_time;
+}
+
+float TPonyDummy::GetMaxPollTime()
+{
+  return max_poll_time;
+}
+
+float TPonyDummy::GetTotPollTime()
+{
+  return total_poll_time;
+}
+
+void TPonyDummy::ResetMinMax(){
+  min_poll_time = 1.0;
+  max_poll_time = 0.0;
+  total_poll_time = 0.0;
+  total_poll_cnt = 0;
+}
+
+/* Constructor
+*/
+
+TPonyDummy::TPonyDummy():
+  use_data_polling(true){
+  
+  ResetMinMax();
+  
+  /* Device Command line options ... */ 
+  if (GetCmdParam("-dno-poll", false)){use_data_polling=false;} 
+  
+  EnableAvr();
+}
+
+/* eof */
diff -uwrN uisp-20010211.orig/src/PonyDummy.h uisp-20010211/src/PonyDummy.h
--- uisp-20010211.orig/src/PonyDummy.h  Thu Jan  1 01:00:00 1970
+++ uisp-20010211/src/PonyDummy.h       Thu Mar  8 16:56:48 2001
@@ -0,0 +1,53 @@
+/* AvrDummy.h, Uros Platise (c) 1999 */
+
+#ifndef __PONY_DUMMY
+#define __PONY_DUMMY
+
+#include "Global.h"
+#include "Avr.h"
+#include "PonyProg.h"
+
+class TPonyDummy: public TAvr, TPonyProg {
+private:
+  bool use_data_polling;
+  float min_poll_time, max_poll_time, total_poll_time;
+  unsigned long total_poll_cnt;  /* bytes or pages */
+
+  void EnableAvr();
+  TByte GetPartInfo(TAddr addr);
+  void WriteProgramMemoryPage();
+  TByte ReadLockFuseBits();
+  TByte ReadFuseLowBits();
+  TByte ReadFuseHighBits();
+  TByte ReadCalByte();
+  void WriteOldFuseBits(TByte val);  /* 5 bits */
+  void WriteFuseLowBits(TByte val);
+  void WriteFuseHighBits(TByte val);
+
+  /* lock bits */
+  void WriteLockBits(TByte bits);
+  TByte ReadLockBits();
+
+public:
+  /* Read byte from active segment at address addr. */
+  TByte ReadByte(TAddr addr);
+
+  /* Write byte to active segment at address addr */
+  void WriteByte(TAddr addr, TByte byte, bool flush_buffer=true);
+  void FlushWriteBuffer();
+  
+  /* Chip Erase */
+  void ChipErase();
+
+  /* Transfer Statistics */
+  unsigned int GetPollCount();
+  float GetMinPollTime();
+  float GetTotPollTime();
+  float GetMaxPollTime();
+  void ResetMinMax();
+  
+  TPonyDummy();
+  ~TPonyDummy(){}
+};
+
+#endif
diff -uwrN uisp-20010211.orig/src/PonyProg.C uisp-20010211/src/PonyProg.C
--- uisp-20010211.orig/src/PonyProg.C   Thu Jan  1 01:00:00 1970
+++ uisp-20010211/src/PonyProg.C        Thu Mar  8 16:56:48 2001
@@ -0,0 +1,349 @@
+/*
+        PonyProg.C
+        
+        Device driver for Serial Programmer connected in the Ponyprog
+       way (http://www.cs.unibo.it/~lanconel
+
+        Uwe Bonnes address@hidden
+
+        Short description of the Ponyprog Interface:
+        RS232 line    ->           ISP connection
+            TXD  (out)->           RESET (in)
+           RTS  (out)->           SCK   (in)
+           DTR  (out)->           MOSI  (in)
+            CTS   (in)->           MISO  (out)
+
+        in the smallest configuration, only use a current
+       limiting resistor in the RS232 out lines, a 4V7 Z-Diode 
+       to clamp the positive RS232 voltage. Maybe a Schottky diode
+       is needed on the Reset Line to clamp the negative voltage.
+       Most modern RS232 receivers should recognise the TTL levels
+       on their CTS inputline, also this is out of the RS232 specs.
+       This configuration needs no line inverted
+ 
+       A more secure version uses uses some Reset generator like the 
+       MAX823/825 and feed the clamped RXD line via a possible transistor
+       inverter to the MAX 823/825 Master Reset Input. The additional
+       reset delay of these parts must be accounted with the
+       -reset=xxx (milliseconds) command line parameter.
+       
+       Using 3 RS232 Receivers and one RS232 Transmitter needs more parts, but
+       gives a solution acording to the specs.
+
+       If the SPI interface is uses for more then programming, isolate 
+       appropriate lines during programming, e.g. with Tristat drivers enabled 
+       by the inverted TXD signal.
+
+       Account for inverting element in the lines with the 
+       -dinvert mosi,miso,sck command line argument
+
+       I didn't get a version to work that uses a inverted reset line however.
+
+       For EAGLE sample drawings of different implementations of the Ponyprog
+       interface, ask address@hidden
+
+       The Rs232 Driver in the PC is inverting!
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/time.h>
+#include "PonyProg.h"
+
+#if defined(TIOCMGET) && defined(TIOCMSET) && defined(TIOCSBRK) && 
defined(TIOCCBRK)
+
+/* Minimum RESET# high time in microseconds.
+   Should be enough to charge a capacitor between RESET# and GND
+   (it is recommended to use a voltage detector with open collector
+   output, and only something like 100 nF for noise immunity).  */
+#ifndef RESET_DEACTIVATE_TIME
+#define RESET_DEACTIVATE_TIME 1000
+#endif
+
+/* Delay from RESET# low to sending program enable command
+   (the datasheet says it must be at least 20 ms).  Also wait time
+   for crystal oscillator to start after possible power down mode.  */
+#ifndef RESET_ACTIVATE_TIME
+#define RESET_ACTIVATE_TIME 30000
+#endif
+
+
+/* The IOMCM(GET|SET) IOCTL is quite slow. On a Dual P 366
+   I get around  250000 Calls per second. This is quite slow enough
+   for the lines to settle, so we don't need extra delays
+*/
+int inline TPonyProg::GetSendBit(int value)
+{
+  int result;
+  
+  ioctl(fd,TIOCMSET, &flags);
+  if (mosi_invert) value = !value;
+  if (value) /* DTR is MOSI*/
+    flags |= TIOCM_DTR;
+  else
+    flags &= ~TIOCM_DTR;
+  ioctl(fd,TIOCMSET, &flags);/*  Duration of this command must be longer than 
"SCK Low to MISO Valid"  */ 
+  ioctl(fd,TIOCMGET, &flags);/*  Duration of this command must be longer than 
"MOSI Setup to SCK HIGH" */
+  result =(miso_invert)? (~flags & TIOCM_CTS):(flags & TIOCM_CTS);
+  if (sck_invert)
+    {
+      flags &= ~TIOCM_RTS;
+      ioctl(fd,TIOCMSET, &flags);
+      flags |= TIOCM_RTS;
+    }
+  else 
+    {
+      flags |= TIOCM_RTS;
+      ioctl(fd,TIOCMSET, &flags);
+      flags &= ~TIOCM_RTS;
+    }
+  return result;
+}
+
+void
+TPonyProg::PulseSck()
+{
+  OutSck(LOGICAL_ACTIVE);
+  OutSck(LOGICAL_INACTIVE);
+}
+
+void
+TPonyProg::PulseReset()
+{
+  /* necessary delays already included in these methods */
+  OutReset(LOGICAL_INACTIVE);
+  usleep(reset_delay);    /* wait for the RESET Timer to go inactive
+                            waiting longer doesn't harm*/
+  OutReset(LOGICAL_ACTIVE);
+}
+
+void TPonyProg::OutData(int b)
+{
+  int value= (mosi_invert)? !b:b;
+  
+  ioctl(fd,TIOCMGET, &flags);
+  if (value)
+    flags |= TIOCM_DTR;
+  else
+    flags &= ~TIOCM_DTR;
+  ioctl(fd,TIOCMSET, &flags);
+}
+
+void TPonyProg::OutSck(int b)
+{
+  int value= (sck_invert)? !b:b;
+  
+  ioctl(fd,TIOCMGET, &flags);
+  if (value)
+    flags |= TIOCM_RTS;
+  else
+    flags &= ~TIOCM_RTS;
+  ioctl(fd,TIOCMSET, &flags);
+}
+
+void TPonyProg::OutReset(int b)
+{
+  if (b == LOGICAL_ACTIVE)
+    ioctl(fd,TIOCSBRK,0);
+  else
+    ioctl(fd,TIOCCBRK,0);
+  
+}
+void TPonyProg::Init()
+{
+  Info(1,"TPonyProg::Init called\n");
+  OutReset(LOGICAL_INACTIVE); /* deassert RESET */
+  usleep(reset_delay);    /* wait for the RESET Timer to go inactive
+                            waiting longer doesn't harm*/
+  OutData(LOGICAL_ACTIVE);
+  OutSck(LOGICAL_INACTIVE);
+  OutReset(LOGICAL_ACTIVE);
+  usleep(20000);
+}
+
+unsigned inline char TPonyProg::SendRecv(unsigned char b)
+{
+  unsigned char mask=0x80, received=0;
+  
+  while (mask)
+    {
+      received |= (GetSendBit(b & mask))?mask:0;
+      mask >>=1;
+    }
+  return received;
+}
+
+int TPonyProg::Send (unsigned char* queue, int queueSize, int 
rec_queueSize=-1){
+  unsigned char *p = queue, ch;
+  int i = queueSize;
+  
+  /*if (rec_queueSize==-1){rec_queueSize = queueSize;}
+    Info (4,"send(recv): ");*/
+  while (i--){
+    ch = SendRecv(*p);
+    /*Info (4,"%02x(%02x) ", *p,ch);*/
+    *p++ = ch;
+  }
+  /*Info(2,"\n");*/
+  return queueSize;
+}
+
+#ifndef MIN_SLEEP_USEC
+#define MIN_SLEEP_USEC 20000
+#endif
+
+void
+TPonyProg::Delay_usec(long t)
+{
+  struct timeval t1, t2;
+
+  if (t <= 0)
+    return;  /* very short delay for slow machines */
+  gettimeofday(&t1, NULL);
+  if (t > MIN_SLEEP_USEC)
+    usleep(t - MIN_SLEEP_USEC);
+  /* loop for the remaining time */
+  t2.tv_sec = t / 1000000UL;
+  t2.tv_usec = t % 1000000UL;
+  timeradd(&t1, &t2, &t1);
+  do {
+    gettimeofday(&t2, NULL);
+  } while (timercmp(&t2, &t1, <));
+}
+
+int TPonyProg::OpenSerial(const char* devpathname)
+{
+  const char *devname;
+  int chars_read,flags;
+
+  // implement device locking in /var/lock/LCK..ttySx
+
+  devname=strrchr(devpathname, '/');
+  if (devname)
+    devname++;
+  else
+    devname=devpathname;
+  Info(0, "devpathname %s devname %s\n",devpathname,devname);
+  sprintf(lockname,"/var/lock/LCK..%s",devname);
+  fd = open ((const char *)lockname,O_RDWR|O_CREAT,0777);
+  if (fd == -1)
+    {
+      fd=open ((const char *)lockname,O_RDONLY);
+      if (fd == -1)
+       {
+         Info(0, "Can't open device %s and can't unlock %s\n",
+              devpathname,lockname); 
+         exit(1);
+       }  
+      lockname[0]=0;
+      chars_read = read(fd,temp,MAXLINESIZE-1);
+      temp[chars_read]=0;
+      Info(0, "PonyProg::OpenSerial locked by %s\n",
+                        devname);
+      close(fd);
+      exit(1);
+    }
+
+  sprintf(temp,"%10d\n", (int) getpid() );
+  write(fd,temp,strlen(temp));
+  close(fd);
+  
+  fd = open (devpathname,O_RDWR);
+  if (fd == -1)
+    {
+      Info(0, "Can't open %s\n",devpathname);
+      unlink(lockname);
+      exit(1);
+    }
+  
+  /* Check if IOCTL are available during runtime*/
+
+  if ((ioctl(fd,TIOCCBRK,0) == -1) || (ioctl(fd,TIOCMGET, &flags)== -1))
+    {
+      Info(0, "PonyProg: Needed IOCTLs  not available");
+      CloseSerial();
+      exit(1);
+    }
+  return fd;
+}
+ 
+void TPonyProg::CloseSerial()
+ {
+   close(fd);
+   unlink(lockname);
+ }
+
+/* constructor/Destructor
+ */
+
+struct termios pmode;
+
+TPonyProg::TPonyProg()
+{
+  const char* dev_name = "/dev/avr";
+  const char* val;
+  char *p;
+
+  if ((val=GetCmdParam("-dserial")))
+    {dev_name = val;}
+  if ((val=GetCmdParam("-dinvert")))
+    {
+      strncpy(temp,val,MAXLINESIZE-1);
+      for (p=temp; *p; p++)
+       *p=toupper(*p);
+      Info(1,"Inverting %s\n",temp);
+      if (strstr(temp,"SCK"))
+       sck_invert=1;
+      else
+       sck_invert=0;
+      if (strstr(temp,"MOSI"))
+       mosi_invert=1;
+      else
+       mosi_invert=0;
+      if (strstr(temp,"MISO"))
+       miso_invert=1;
+      else
+       miso_invert=0;
+    }
+  if ((val=GetCmdParam("-dreset")))
+    {
+      reset_delay=atoi(val);
+      Info(1,"Using reset delay %d\n",reset_delay);
+    }
+  else
+    {
+      reset_delay=20;
+      Info(1,"Using default reset delay\n");
+    }
+  reset_delay*= 1000;
+  if (GetCmdParam("-dno-poll", false))
+    {
+      Info(1,"Not using polling\n");
+      use_data_polling=false;
+    } 
+
+  OpenSerial(dev_name);
+  Info(0, "Serial successfull opened\n");
+  Init();
+  Info(3, "Init\n");
+}
+
+TPonyProg::~TPonyProg()
+{
+  OutSck(LOGICAL_INACTIVE);
+  OutReset(LOGICAL_INACTIVE);
+  CloseSerial();
+  Info(0, "PonyProg ended\n");
+}
+#else
+WARN
+#endif /*IOCTL's not available for compiling*/
diff -uwrN uisp-20010211.orig/src/PonyProg.h uisp-20010211/src/PonyProg.h
--- uisp-20010211.orig/src/PonyProg.h   Thu Jan  1 01:00:00 1970
+++ uisp-20010211/src/PonyProg.h        Thu Mar  8 17:02:58 2001
@@ -0,0 +1,55 @@
+/*
+        PonyProg.h  
+        Device driver for Serial Programmer connected in the Ponyprog
+       way (http://www.cs.unibo.it/~lanconel
+        
+        Uwe Bonnes(c) copyright 2000
+*/
+
+#ifndef __PonyProg
+#define __PonyProg
+
+#include "Global.h"
+#include "Avr.h"
+
+#define MAXLINESIZE    256
+
+class TPonyProg{
+private:
+  int fd;
+  int mosi_invert;
+  int miso_invert;
+  int sck_invert;
+  int reset_delay;
+  int use_data_polling;
+  int flags;
+  char lockname[MAXLINESIZE];
+  char temp[MAXLINESIZE];
+  long n_per_ms;
+
+protected:
+  enum LogicalStates{LOGICAL_INACTIVE=0, LOGICAL_ACTIVE=1};
+
+private:
+  int GetSendBit(int);
+  void OutData(int);
+  void OutSck(int);
+  void OutReset(int);
+  int OpenSerial(const char* devpathname);
+  void CloseSerial();
+  unsigned char SendRecv(unsigned char b);
+  
+
+public:
+
+  void PulseSck();
+  void PulseReset();
+  int Send(unsigned char*, int, int rec_queueSize=-1);
+  void Init();
+  void Delay_usec(long);
+
+  TPonyProg();
+  ~TPonyProg();
+};
+
+#endif



reply via email to

[Prev in Thread] Current Thread [Next in Thread]