summaryrefslogtreecommitdiffstats
path: root/src/progs/direct/base/direct_mem24.cpp
blob: 98b5f9a7851bec11497e98c56ef383e3d7b3e4bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/***************************************************************************
 *   Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org>                  *
 *                                                                         *
 *   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.                                   *
 ***************************************************************************/
#include "direct_mem24.h"

#include <tqdatetime.h>

#include "common/global/global.h"
#include "common/common/misc.h"

Direct::Mem24DeviceSpecific::Mem24DeviceSpecific(::Programmer::Base &base)
  : ::Programmer::Mem24DeviceSpecific(base)
{}

bool Direct::Mem24DeviceSpecific::setPowerOn()
{
  hardware().setPin(Clock, Low);
  hardware().setPin(DataOut, Low);
  hardware().setPin(Vpp, Off);
  if ( hardware().isGroundPin(Vdd) ) {
    hardware().setPin(Clock, High);
    Port::usleep(500000);
  } else {
    hardware().setPin(Vdd, On);
    Port::usleep(10000);
  }
  return true;
}

bool Direct::Mem24DeviceSpecific::setPowerOff()
{
  hardware().setPin(Clock, Low);
  hardware().setPin(DataOut, Low);
  hardware().setPin(Vpp, Off);
  hardware().setPin(Vdd, Off);
  Port::usleep(10000);
  return true;
}

bool Direct::Mem24DeviceSpecific::verifyPresence()
{
  if ( !start() ) return false;
  bool acked;
  if ( !writeByte(controlByte(0x0, Write), acked) ) return false;
  if ( !acked ) {
    log(Log::LineType::Error, i18n("Could not detect EEPROM"));
    return false;
  }
  log(Log::LineType::Information, i18n("EEPROM detected"));
  return stop();
}

uint Direct::Mem24DeviceSpecific::controlByte(uint address, Operation operation) const
{
  uint cbyte = (operation==Write ? 0xA0 : 0xA1);
  uint bsize = device().nbBytes() / device().nbBlocks();
  uint block = address / bsize;
  uint nbb = nbBits(device().nbBlocks()-1);
  for (uint i=0; i<nbb; i++)
    if ( block & (1<<i) ) cbyte |= 1 << (4-nbb+i);
  return cbyte;
}

bool Direct::Mem24DeviceSpecific::setAddress(uint address)
{
  log(Log::DebugLevel::Extra, TQString("set address %1").tqarg(toHexLabel(address, nbChars(NumberBase::Hex, address))));
  if ( !start() ) return false;
  uint bsize = device().nbBytes() / device().nbBlocks();
  uint block = address / bsize;
  log(Log::DebugLevel::Extra, TQString("  in block #%1/%2").tqarg(block).tqarg(device().nbBlocks()));
  uint cbyte = controlByte(address, Write);
  log(Log::DebugLevel::Max, TQString("  control byte is %1").tqarg(toHexLabel(cbyte, 2)));
  if ( !writeByteAck(cbyte) ) return false;
  uint nb = nbBytes(bsize-1);
  for (int i=nb-1; i>=0; i--) {
    uint add = (address >> 8*i) & 0xFF;
    log(Log::DebugLevel::Max, TQString("  byte #%1: %2").tqarg(i).tqarg(toHexLabel(add, 2)));
    if ( !writeByteAck(add) ) return false;
  }
  return true;
}

bool Direct::Mem24DeviceSpecific::doRead(Device::Array &data, const ::Programmer::VerifyData *vdata)
{
  // sequential read: all device memory
  if ( !setAddress(0x0) ) return false;
  if ( !start() ) return false;
  if ( !writeByteAck(controlByte(0x0, Read)) ) return false;
  data.resize(device().nbBytes());
  for (uint i=0; i<data.count()-1; i++) data[i] = readByte(Low);
  data[data.count()-1] = readByte(High);
  if (vdata) {
    for (uint i=0; i<data.count(); i++)
      if ( !verifyByte(i, data[i], *vdata) ) return false;
  }
  return stop();
}

bool Direct::Mem24DeviceSpecific::doWrite(const Device::Array &data)
{
  TQTime time;
  // page by page (page_size==1: byte by byte)
  uint nbPages = device().nbBytes() / device().nbBytesPage();
  for (uint i=0; i<nbPages; i++) {
    log(Log::DebugLevel::Extra, TQString("write page #%1/%2").tqarg(i).tqarg(nbPages));
    uint address = i * device().nbBytesPage();
    // write bytes
    if ( !setAddress(address) ) return false;
    for (uint k=0; k<device().nbBytesPage(); k++)
      if ( !writeByteAck(data[address+k]) ) return false;
    if ( !stop() ) return false;
    // poll
    time.start();
    for (;;) {
      if ( !start() ) return false;
      bool acked;
      if ( !writeByte(controlByte(address, Write), acked) ) return false;
      if (acked) break;
      if ( time.elapsed()>200 ) { // 200 ms timeout
        log(Log::LineType::Error, i18n("Timeout writing at address %1").tqarg(toHexLabel(address, nbChars(device().nbBytes()))));
        return false;
      }
    }
  }
  return true;
}

void Direct::Mem24DeviceSpecific::set(State clock, State data)
{
  hardware().setPin(Clock, clock);
  hardware().setPin(DataOut, data);
  Port::usleep(5); // #### needed ?
}

void Direct::Mem24DeviceSpecific::setData(State data)
{
  set(Low, data);
  set(High, data);
  set(Low, data);
}

BitValue Direct::Mem24DeviceSpecific::readByte(State ack)
{
  hardware().setRead();
  set(Low, High);
  BitValue b = 0;
  for (uint i=0; i<8; i++) {
    set(High, High);
    b <<= 1;
    if ( hardware().readBit() ) b |= 0x1;
    set(Low, High);
  }
  hardware().setWrite();
  setData(ack);
  return b;
}

bool Direct::Mem24DeviceSpecific::writeByteAck(BitValue value)
{
  bool acked;
  if ( !writeByte(value, acked) ) return false;
  if (!acked) {
    log(Log::LineType::Error, i18n("Acknowledge bit incorrect"));
    return false;
  }
  return true;
}

bool Direct::Mem24DeviceSpecific::writeByte(BitValue value, bool &acked)
{
  Q_ASSERT( value<=0xFF );
  hardware().setWrite();
  set(Low, Low);
  for (int i=7; i>=0; i--) setData(value.bit(i) ? High : Low);
  hardware().setRead();
  set(Low, High);
  set(High, High);
  acked = !hardware().readBit();
  hardware().setWrite();
  set(Low, High);
  return true;
}

bool Direct::Mem24DeviceSpecific::start()
{
  hardware().setWrite();
  set(Low, High);
  set(High, High);
  set(High, Low);
  set(Low, Low);
  return true;
}

bool Direct::Mem24DeviceSpecific::stop()
{
  hardware().setWrite();
  set(Low, Low);
  set(High, Low);
  set(High, High);
  set(Low, High);
  return true;
}