Skip to content

Commit 309d8b7

Browse files
committed
simplify P1P2 Status page
1 parent 1a6a290 commit 309d8b7

File tree

9 files changed

+133
-120
lines changed

9 files changed

+133
-120
lines changed

Ethernet_SW_Reset.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Ethernet Power On Reset Issue
2+
3+
## Issue
4+
5+
Sometimes Arduino is running fine for days but after power-up or brief loss of power (caused for example by undervoltage), ethernet connection is lost. Ethernet connection is restored only after you press the RST button on the ethernet shield. The issue has been identified and described in detail by the community for example [here](https://chrisramsay.co.uk/posts/2015/08/some-fun-with-a-cloned-arduino-and-w5100-ethernet-shield/), [here](https://www.youtube.com/watch?v=9ZBeprOqC3w), [here](http://tigawd.blogspot.com/2015/05/arduino-uno-clone-and-w5100-ethernet.html) and also [here](https://www.hobbyist.co.nz/?q=ethernet-shield-w5100).
6+
7+
## Cause
8+
9+
Arduino Ethernet shields use HW method to reset (initialize) the W5x00 chip. They have the W5x00's RST pin hard wired to Arduino's RST pin. If Arduino is reset, the W5x00 should be reset also. However, normal reset time of the Arduino is too short. The Arduino microcontroller has a 65 millisecond powerup/reset delay (the longest available to be set by the fuses and bootloader) but the W5x00 chip expects longer pull-down of the RST pin. As a result, the W5x00 chip fails to reset (and initialize) properly.
10+
11+
The problem is poor ethernet shield design. This issue is not specific to cheap ethernet shields (clones), but exists in all variant of the Arduino Ethernet shields.
12+
13+
## Solution
14+
15+
You can find different solutions on the internet - most of them require soldering additional capacitor (and resistor) to the Arduino Ethernet shield. However, there is much easier and more elegant solution: use SW method to reset / initialize the W5x00 chip.
16+
17+
### 1. Cut the connection between W5x00's RST pin and Arduino's RST pin.
18+
19+
We need to isolate the W5x00's reset signal when the boards are connected together. Keep in mind that there are actually 2 connections between W5x00's RST pin and Arduino's RST pin. You need to cut both of them, simply by bending out or cutting appropriate pins:
20+
21+
- **Bend the RESET pin on the Ethernet shield.**
22+
- **Bend one pin within the ICSP connector on the Arduino board** (see below)
23+
24+
<img src="pics/reset_bridges_Ethernet.jpg" alt="HW" style="zoom:100%;" />
25+
26+
### 2. Connect W5x00's RST pin to an unused Arduino pin 7
27+
28+
Attach the ethernet shield to the Arduino board. Use wire (male/male jumper wire) to connect RESET pin and pin 7 on the Ethernet shield.
29+
30+
### 3. Reset the W5x00 chip programmatically
31+
32+
Within your Arduino sketch, pull down pin 7 to reset (initialize) the W5x00 chip. Since the HW method to reset the W5x00 chip will no longer work (W5x00 will not reset/initialize automatically after power up), you **++must++** pull down pin 7 before calling Ethernet.begin().
33+
34+
If you are using one of my Arduino projects ([Modbus RTU ⇒ Modbus TCP/UDP Gateway](https://github.com/budulinek/arduino-modbus-rtu-tcp-gateway), [Arduino Sensors UDP Gateway](https://github.com/budulinek/arduino-sensors-udp-gateway) or [Arduino Altherma UDP Controller](https://github.com/budulinek/arduino-altherma-controller)), the software method to reset (initialize) the W5x00 chip is already implemented within my code.
35+
36+
If you want to reset the W5x00 chip programmatically in your own sketch, use this code to pull down pin 7 before calling Ethernet.begin(). This is the code which works for me:
37+
38+
```
39+
pinMode(7, OUTPUT);
40+
digitalWrite(7, LOW);
41+
delay(25);
42+
digitalWrite(7, HIGH);
43+
delay(500);
44+
```

arduino-altherma-controller/01-interfaces.ino

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,26 @@
55
*/
66
/**************************************************************************/
77
void startEthernet() {
8-
if (ETH_RESET_PIN != 0) {
9-
pinMode(ETH_RESET_PIN, OUTPUT);
10-
digitalWrite(ETH_RESET_PIN, LOW);
11-
delay(25);
12-
digitalWrite(ETH_RESET_PIN, HIGH);
13-
delay(ETH_RESET_DELAY);
14-
}
8+
#ifdef ETH_RESET_PIN
9+
pinMode(ETH_RESET_PIN, OUTPUT);
10+
digitalWrite(ETH_RESET_PIN, LOW);
11+
delay(25);
12+
digitalWrite(ETH_RESET_PIN, HIGH);
13+
delay(ETH_RESET_DELAY);
14+
#endif
15+
1516
#ifdef ENABLE_DHCP
17+
dhcpSuccess = false;
1618
if (data.config.enableDhcp) {
1719
dhcpSuccess = Ethernet.begin(data.mac);
1820
}
19-
if (!data.config.enableDhcp || dhcpSuccess == false) {
21+
if (!dhcpSuccess) {
2022
Ethernet.begin(data.mac, data.config.ip, data.config.dns, data.config.gateway, data.config.subnet);
2123
}
2224
#else /* ENABLE_DHCP */
2325
Ethernet.begin(data.mac, data.config.ip, {}, data.config.gateway, data.config.subnet); // No DNS
2426
#endif /* ENABLE_DHCP */
27+
2528
W5100.setRetransmissionTime(TCP_RETRANSMISSION_TIMEOUT);
2629
W5100.setRetransmissionCount(TCP_RETRANSMISSION_COUNT);
2730
webServer = EthernetServer(data.config.webPort);
@@ -39,19 +42,6 @@ void startEthernet() {
3942
/**************************************************************************/
4043
void (*resetFunc)(void) = 0; //declare reset function at address 0
4144

42-
/**************************************************************************/
43-
/*!
44-
@brief Maintains DHCP lease.
45-
*/
46-
/**************************************************************************/
47-
#ifdef ENABLE_DHCP
48-
void maintainDhcp() {
49-
if (data.config.enableDhcp && dhcpSuccess == true) { // only call maintain if initial DHCP request by startEthernet was successfull
50-
Ethernet.maintain();
51-
}
52-
}
53-
#endif /* ENABLE_DHCP */
54-
5545
/**************************************************************************/
5646
/*!
5747
@brief Maintains uptime in case of millis() overflow.

arduino-altherma-controller/02-UDP.ino

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ void checkCommand(byte command[], byte cmdLen) {
4343
}
4444
}
4545
} else {
46-
data.p1p2Cnt[P1P2_WRITE_INVALID]++; // Write Command Invalid
46+
data.eepromDaikin.invalid++; // Write Command Invalid
4747
}
4848
} else {
49-
data.p1p2Cnt[P1P2_WRITE_QUEUE]++; // TODO error: Write Queue Full
49+
data.eepromDaikin.invalid++; // Write Queue Full
5050
}
5151
}
5252

arduino-altherma-controller/03-P1P2.ino

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ void recvBus() {
1515
uint16_t nread = P1P2Serial.readpacket(RB, delta, EB, RB_SIZE, CRC_GEN, CRC_FEED);
1616
if (nread > RB_SIZE) {
1717
// Received packet longer than RB_SIZE
18-
data.p1p2Cnt[P1P2_LARGE]++;
18+
data.p1p2Cnt[P1P2_READ_ERROR]++;
1919
nread = RB_SIZE;
2020
readError = 0xFF;
2121
}
@@ -143,26 +143,15 @@ void processErrors(uint16_t nread) {
143143
bool packetError[P1P2_LAST];
144144
memset(packetError, 0, sizeof(packetError));
145145
for (uint16_t i = 0; i < nread; i++) {
146-
if ((EB[i] & ERROR_SB)) {
147-
// collision suspicion due to data verification error in reading back written data
148-
packetError[P1P2_ERROR_SB] = true;
146+
if ((EB[i] & ERROR_SB) // collision suspicion due to data verification error in reading back written data
147+
|| (EB[i] & ERROR_BE) // collision suspicion due to data verification error in reading back written data
148+
|| (EB[i] & ERROR_BC)) { // collision suspicion due to 0 during 2nd half bit signal read back
149+
packetError[P1P2_WRITE_ERROR] = true;
149150
}
150-
if ((EB[i] & ERROR_BE) || (EB[i] & ERROR_BC)) { // or BE3 (duplicate code)
151-
// collision suspicion due to data verification error in reading back written data
152-
// collision suspicion due to 0 during 2nd half bit signal read back
153-
packetError[P1P2_ERROR_BE_BC] = true;
154-
}
155-
if ((EB[i] & ERROR_PE)) {
156-
// parity error detected
157-
packetError[P1P2_ERROR_PE] = true;
158-
}
159-
if ((EB[i] & ERROR_OR)) {
160-
// buffer overrun detected (overrun is after, not before, the read byte)
161-
packetError[P1P2_ERROR_OR] = true;
162-
}
163-
if ((EB[i] & ERROR_CRC)) {
164-
// CRC error detected in readpacket
165-
packetError[P1P2_ERROR_CRC] = true;
151+
if ((EB[i] & ERROR_PE) // parity error detected
152+
|| (EB[i] & ERROR_OR) // buffer overrun detected (overrun is after, not before, the read byte)
153+
|| (EB[i] & ERROR_CRC)) { // CRC error detected in readpacket
154+
packetError[P1P2_READ_ERROR] = true;
166155
}
167156
}
168157
for (byte i = 0; i < P1P2_LAST; i++) {
@@ -206,7 +195,7 @@ void processWrite(uint16_t n) {
206195
data.eepromDaikin.today++;
207196
// updateEeprom(); // is it really needed?
208197
} else {
209-
data.p1p2Cnt[P1P2_WRITE_QUOTA]++;
198+
data.eepromDaikin.dropped++;
210199
}
211200
} else {
212201
// TODO error

arduino-altherma-controller/04-webserver.ino

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@ void processPost(EthernetClient &client) {
358358
break;
359359
case ACT_CLEAR_QUOTA:
360360
data.eepromDaikin.today = 0;
361+
data.eepromDaikin.dropped = 0;
362+
data.eepromDaikin.invalid = 0;
361363
break;
362364
default:
363365
break;

arduino-altherma-controller/05-pages.ino

Lines changed: 47 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ void sendPage(EthernetClient &client, byte reqPage) {
170170
break;
171171
}
172172
if (reqPage == PAGE_IP || reqPage == PAGE_TCP || reqPage == PAGE_P1P2 || reqPage == PAGE_FILTER) {
173-
chunked.print(F("<p><div class=r><label><input type=submit value='Save & Apply'></label><input type=reset value=Cancel></div>"));
173+
chunked.print(F("<p><div class=q><label><input type=submit value='Save & Apply'></label><input type=reset value=Cancel></div>"));
174174
}
175175
chunked.print(F("</form>"
176176
"</main>"));
@@ -268,14 +268,6 @@ void contentStatus(ChunkedPrint &chunked) {
268268
tagLabelDiv(chunked, F("Date"));
269269
tagSpan(chunked, JSON_DATE);
270270
tagDivClose(chunked);
271-
tagLabelDiv(chunked, F("Daikin EEPROM Writes"));
272-
tagButton(chunked, F("Reset"), ACT_RESET_EEPROM, true);
273-
chunked.print(F(" Stats since "));
274-
tagSpan(chunked, JSON_DAIKIN_EEPROM_DATE);
275-
tagDivClose(chunked);
276-
tagLabelDiv(chunked, 0);
277-
tagSpan(chunked, JSON_DAIKIN_EEPROM);
278-
tagDivClose(chunked);
279271
chunked.print(F("</form><form method=post>"));
280272
tagLabelDiv(chunked, F("Write Command"));
281273
chunked.print(F("Packet Type "
@@ -302,6 +294,14 @@ void contentStatus(ChunkedPrint &chunked) {
302294
tagSpan(chunked, JSON_WRITE_P1P2);
303295
tagDivClose(chunked);
304296
chunked.print(F("</form><form method=post>"));
297+
tagLabelDiv(chunked, F("Daikin EEPROM Writes"));
298+
tagButton(chunked, F("Reset"), ACT_RESET_EEPROM, true);
299+
chunked.print(F(" Stats since "));
300+
tagSpan(chunked, JSON_DAIKIN_EEPROM_DATE);
301+
tagDivClose(chunked);
302+
tagLabelDiv(chunked, 0);
303+
tagSpan(chunked, JSON_DAIKIN_EEPROM);
304+
tagDivClose(chunked);
305305
#ifdef ENABLE_EXTENDED_WEBUI
306306
tagLabelDiv(chunked, F("Run Time"));
307307
tagSpan(chunked, JSON_RUNTIME);
@@ -422,8 +422,7 @@ void contentP1P2(ChunkedPrint &chunked) {
422422
tagInputNumber(chunked, POST_QUOTA, 0, 100, data.config.writeQuota, F("writes per day"));
423423
tagDivClose(chunked);
424424
tagLabelDiv(chunked, F("Target Temperature Hysteresis"));
425-
tagInputNumber(chunked, POST_HYSTERESIS, 0, 100, data.config.hysteresis, F("&#8530;\xB0"
426-
"C"));
425+
tagInputNumber(chunked, POST_HYSTERESIS, 0, 100, data.config.hysteresis, F("⅒°C"));
427426
tagDivClose(chunked);
428427
}
429428

@@ -849,7 +848,11 @@ void jsonVal(ChunkedPrint &chunked, const byte JSONKEY) {
849848
case JSON_DAIKIN_EEPROM:
850849
{
851850
chunked.print(data.eepromDaikin.total);
852-
chunked.print(F(" Total Commands<br>"));
851+
chunked.print(F(" Command OK<br>"));
852+
chunked.print(data.eepromDaikin.dropped);
853+
chunked.print(F(" Dropped<br>"));
854+
chunked.print(data.eepromDaikin.invalid);
855+
chunked.print(F(" Invalid<br>"));
853856
if (date[5] != 0) { // day can not be zero
854857
chunked.print((uint16_t)(data.eepromDaikin.total / (days(date) - days(data.eepromDaikin.date) + 1)));
855858
} else {
@@ -859,9 +862,9 @@ void jsonVal(ChunkedPrint &chunked, const byte JSONKEY) {
859862
chunked.print(data.eepromDaikin.yesterday);
860863
chunked.print(F(" Yesterday<br>"));
861864
chunked.print(data.eepromDaikin.today);
862-
chunked.print(F(" / "));
865+
chunked.print(F(" out of "));
863866
chunked.print(data.config.writeQuota);
864-
chunked.print(F(" Today (total / quota) "));
867+
chunked.print(F(" Today "));
865868
tagButton(chunked, F("Clear Quota"), ACT_CLEAR_QUOTA, true);
866869
}
867870
break;
@@ -930,48 +933,36 @@ void jsonVal(ChunkedPrint &chunked, const byte JSONKEY) {
930933
break;
931934
case JSON_P1P2_STATS:
932935
{
933-
for (byte i = 0; i < P1P2_LAST; i++) {
934-
chunked.print(data.p1p2Cnt[i]);
935-
switch (i) {
936-
case P1P2_READ_OK:
937-
chunked.print(F(" Bus Read OK"));
938-
break;
939-
case P1P2_WRITE_OK:
940-
chunked.print(F(" Bus Write OK"));
941-
break;
942-
case P1P2_WRITE_QUOTA:
943-
chunked.print(F(" EEPROM Write Quota Reached"));
944-
break;
945-
case P1P2_WRITE_QUEUE:
946-
chunked.print(F(" Write Command Queue Full"));
947-
break;
948-
case P1P2_WRITE_INVALID:
949-
chunked.print(F(" Write Command Invalid"));
950-
break;
951-
case P1P2_ERROR_PE:
952-
chunked.print(F(" Parity Read"));
953-
break;
954-
case P1P2_LARGE:
955-
chunked.print(F(" Too Long Read"));
956-
break;
957-
case P1P2_ERROR_SB:
958-
chunked.print(F(" Start Bit Write"));
959-
break;
960-
case P1P2_ERROR_BE_BC:
961-
chunked.print(F(" Bus Collission Write"));
962-
break;
963-
case P1P2_ERROR_OR:
964-
chunked.print(F(" Buffer Overrun"));
965-
break;
966-
case P1P2_ERROR_CRC:
967-
chunked.print(F(" CRC"));
968-
break;
969-
default:
970-
break;
971-
}
972-
if (i >= P1P2_ERROR_PE) chunked.print(F(" Error"));
973-
chunked.print(F("<br>"));
974-
}
936+
chunked.print(data.p1p2Cnt[P1P2_READ_OK]);
937+
chunked.print(F(" Read OK<br>"));
938+
chunked.print(data.p1p2Cnt[P1P2_READ_ERROR]);
939+
chunked.print(F(" Error<br>"));
940+
chunked.print(data.p1p2Cnt[P1P2_WRITE_OK]);
941+
chunked.print(F(" Write OK<br>"));
942+
chunked.print(data.p1p2Cnt[P1P2_WRITE_ERROR]);
943+
chunked.print(F(" Error"));
944+
945+
946+
// for (byte i = 0; i < P1P2_LAST; i++) {
947+
// chunked.print(data.p1p2Cnt[i]);
948+
// switch (i) {
949+
// case P1P2_READ_OK:
950+
// chunked.print(F(" Read OK"));
951+
// break;
952+
// case P1P2_READ_ERROR:
953+
// chunked.print(F(" Read Error"));
954+
// break;
955+
// case P1P2_WRITE_OK:
956+
// chunked.print(F(" Write OK"));
957+
// break;
958+
// case P1P2_WRITE_ERROR:
959+
// chunked.print(F(" Write Error"));
960+
// break;
961+
// default:
962+
// break;
963+
// }
964+
// chunked.print(F("<br>"));
965+
// }
975966
}
976967
break;
977968
default:

arduino-altherma-controller/advanced_settings.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
/****** IP Settings ******/
2222
const bool DEFAULT_AUTO_IP = false; // Default Auto IP setting (only used if ENABLE_DHCP)
2323
#define DEFAULT_STATIC_IP \
24-
{ 192, 168, 1, 254 } // Default Static IP
24+
{ 10, 10, 10, 34 } // Default Static IP
25+
// { 192, 168, 1, 254 } // Default Static IP
2526
#define DEFAULT_SUBMASK \
2627
{ 255, 255, 255, 0 } // Default Submask
2728
#define DEFAULT_GATEWAY \
@@ -82,7 +83,8 @@ const uint16_t INIT_SDTO = 2500; // P1/P2 write time-out delay (ms)
8283
const byte CTRL_ID[] = { 0xB4, 0x10 }; // LAN adapter ID in 0x31 payload bytes 7 and 8
8384

8485
const byte MAC_START[3] = { 0x90, 0xA2, 0xDA }; // MAC range for Gheo SA
85-
const byte ETH_RESET_PIN = 7; // Ethernet shield reset pin (deals with power on reset issue on low quality ethernet shields)
86+
#define ETH_RESET_PIN 7 // Ethernet shield reset pin (deals with power on reset issue on low quality ethernet shields) \
87+
// Comment out to disable the functionality
8688
const uint16_t ETH_RESET_DELAY = 500; // Delay (ms) during Ethernet start, wait for Ethernet shield to start (reset issue on low quality ethernet shields)
8789
const uint16_t WEB_IDLE_TIMEOUT = 400; // Time (ms) from last client data after which webserver TCP socket could be disconnected, non-blocking.
8890
const uint16_t TCP_DISCON_TIMEOUT = 500; // Timeout (ms) for client DISCON socket command, non-blocking alternative to https://www.arduino.cc/reference/en/libraries/ethernet/client.setconnectiontimeout/

0 commit comments

Comments
 (0)