[Top][All Lists]
[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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [avr-gcc-list] PonyProg Interface for UISP,
Uwe Bonnes <=