Skip to content

Commit b934daa

Browse files
authored
Merge pull request #2007 from khudson/r1neo
Muzi Works R1 Neo support
2 parents 856df24 + fcad0dc commit b934daa

10 files changed

Lines changed: 858 additions & 5 deletions

File tree

src/helpers/AutoDiscoverRTCClock.cpp

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "AutoDiscoverRTCClock.h"
22
#include "RTClib.h"
33
#include <Melopero_RV3028.h>
4+
#include "RTC_RX8130CE.h"
45

56
static RTC_DS3231 rtc_3231;
67
static bool ds3231_success = false;
@@ -11,9 +12,13 @@ static bool rv3028_success = false;
1112
static RTC_PCF8563 rtc_8563;
1213
static bool rtc_8563_success = false;
1314

15+
static RTC_RX8130CE rtc_8130;
16+
static bool rtc_8130_success = false;
17+
1418
#define DS3231_ADDRESS 0x68
1519
#define RV3028_ADDRESS 0x52
1620
#define PCF8563_ADDRESS 0x51
21+
#define RX8130CE_ADDRESS 0x32
1722

1823
bool AutoDiscoverRTCClock::i2c_probe(TwoWire& wire, uint8_t addr) {
1924
wire.beginTransmission(addr);
@@ -25,22 +30,32 @@ void AutoDiscoverRTCClock::begin(TwoWire& wire) {
2530
if (i2c_probe(wire, DS3231_ADDRESS)) {
2631
ds3231_success = rtc_3231.begin(&wire);
2732
}
33+
2834
if (i2c_probe(wire, RV3028_ADDRESS)) {
2935
rtc_rv3028.initI2C(wire);
30-
rtc_rv3028.writeToRegister(0x35, 0x00);
31-
rtc_rv3028.writeToRegister(0x37, 0xB4); // Direct Switching Mode (DSM): when VDD < VBACKUP, switchover occurs from VDD to VBACKUP
32-
rtc_rv3028.set24HourMode(); // Set the device to use the 24hour format (default) instead of the 12 hour format
36+
rtc_rv3028.writeToRegister(0x35, 0x00);
37+
rtc_rv3028.writeToRegister(0x37, 0xB4); // Direct Switching Mode (DSM): when VDD < VBACKUP, switchover occurs from VDD to VBACKUP
38+
rtc_rv3028.set24HourMode(); // Set the device to use the 24hour format (default) instead of the 12 hour format
3339
rv3028_success = true;
3440
}
35-
if(i2c_probe(wire,PCF8563_ADDRESS)){
41+
42+
if (i2c_probe(wire, PCF8563_ADDRESS)) {
3643
rtc_8563_success = rtc_8563.begin(&wire);
3744
}
45+
46+
if (i2c_probe(wire, RX8130CE_ADDRESS)) {
47+
MESH_DEBUG_PRINTLN("RX8130CE: Found");
48+
rtc_8130.begin(&wire);
49+
rtc_8130_success = true;
50+
MESH_DEBUG_PRINTLN("RX8130CE: Initialized");
51+
}
3852
}
3953

4054
uint32_t AutoDiscoverRTCClock::getCurrentTime() {
4155
if (ds3231_success) {
4256
return rtc_3231.now().unixtime();
4357
}
58+
4459
if (rv3028_success) {
4560
return DateTime(
4661
rtc_rv3028.getYear(),
@@ -51,9 +66,16 @@ uint32_t AutoDiscoverRTCClock::getCurrentTime() {
5166
rtc_rv3028.getSecond()
5267
).unixtime();
5368
}
54-
if(rtc_8563_success){
69+
70+
if (rtc_8563_success) {
5571
return rtc_8563.now().unixtime();
5672
}
73+
74+
if (rtc_8130_success) {
75+
MESH_DEBUG_PRINTLN("RX8130CE: Reading time");
76+
return rtc_8130.now().unixtime();
77+
}
78+
5779
return _fallback->getCurrentTime();
5880
}
5981

@@ -66,6 +88,9 @@ void AutoDiscoverRTCClock::setCurrentTime(uint32_t time) {
6688
rtc_rv3028.setTime(dt.year(), dt.month(), weekday, dt.day(), dt.hour(), dt.minute(), dt.second());
6789
} else if (rtc_8563_success) {
6890
rtc_8563.adjust(DateTime(time));
91+
} else if (rtc_8130_success) {
92+
MESH_DEBUG_PRINTLN("RX8130CE: Setting time");
93+
rtc_8130.adjust(DateTime(time));
6994
} else {
7095
_fallback->setCurrentTime(time);
7196
}

src/helpers/RTC_RX8130CE.cpp

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
#include "RTC_RX8130CE.h"
2+
#include "RTClib.h"
3+
4+
5+
bool RTC_RX8130CE::stop(bool stop) {
6+
write_register(0x1E, stop ? 0x040 : 0x00);
7+
return true;
8+
}
9+
10+
bool RTC_RX8130CE::begin(TwoWire *wire) {
11+
if (i2c_dev) {
12+
delete i2c_dev;
13+
}
14+
15+
i2c_dev = new Adafruit_I2CDevice(this->_addr, wire);
16+
if (!i2c_dev->begin()) {
17+
return false;
18+
}
19+
20+
/*
21+
* Digital offset register:
22+
* [7] DET: 0 -> disabled
23+
* [6:0] L7-L1: 0 -> no offset
24+
*/
25+
write_register(0x30, 0x00);
26+
27+
/*
28+
* Extension Register register:
29+
* [7:6] FSEL: 0 -> 0
30+
* [5] USEL: 0 -> 0
31+
* [4] TE: 0 ->
32+
* [3] WADA: 0 -> 0
33+
* [2-0] TSEL: 0 -> 0
34+
*/
35+
write_register(0x1C, 0x00);
36+
37+
/*
38+
* Flag Register register:
39+
* [7] VBLF: 0 -> 0
40+
* [6] 0: 0 ->
41+
* [5] UF: 0 ->
42+
* [4] TF: 0 ->
43+
* [3] AF: 0 -> 0
44+
* [2] RSF: 0 -> 0
45+
* [1] VLF: 0 -> 0
46+
* [0] VBFF: 0 -> 0
47+
*/
48+
write_register(0x1D, 0x00);
49+
50+
/*
51+
* Control Register0 register:
52+
* [7] TEST: 0 -> 0
53+
* [6] STOP: 0 ->
54+
* [5] UIE: 0 ->
55+
* [4] TIE: 0 ->
56+
* [3] AIE: 0 -> 0
57+
* [2] TSTP: 0 -> 0
58+
* [1] TBKON: 0 -> 0
59+
* [0] TBKE: 0 -> 0
60+
*/
61+
write_register(0x1E, 0x00);
62+
63+
/*
64+
* Control Register1 register:
65+
* [7-6] SMPTSEL: 0 -> 0
66+
* [5] CHGEN: 0 ->
67+
* [4] INIEN: 0 ->
68+
* [3] 0: 0 ->
69+
* [2] RSVSEL: 0 -> 0
70+
* [1-0] BFVSEL: 0 -> 0
71+
*/
72+
write_register(0x1F, 0x00);
73+
74+
this->stop(false); // clear STOP bit
75+
76+
/*
77+
* Function register:
78+
* [7] 100TH: 0 -> disabled
79+
* [6:5] Periodic interrupt: 0 -> no periodic interrupt
80+
* [4] RTCM: 0 -> real-time clock mode
81+
* [3] STOPM: 0 -> RTC stop is controlled by STOP bit only
82+
* [2:0] Clock output frequency: 000 (Default value)
83+
*/
84+
write_register(0x28, 0x00);
85+
86+
// Battery switch register
87+
write_register(0x26, 0x00); // enable battery switch feature
88+
89+
return true;
90+
}
91+
92+
bool RTC_RX8130CE::setTime(struct tm *t) {
93+
uint8_t buf[8];
94+
buf[0] = 0x10;
95+
buf[1] = bin2bcd(t->tm_sec) & 0x7F;
96+
buf[2] = bin2bcd(t->tm_min) & 0x7F;
97+
buf[3] = bin2bcd(t->tm_hour) & 0x3F;
98+
buf[4] = bin2bcd(t->tm_wday) & 0x07;
99+
buf[5] = bin2bcd(t->tm_mday) & 0x3F;
100+
buf[6] = bin2bcd(t->tm_mon + 1) & 0x1F;
101+
buf[7] = bin2bcd((t->tm_year - 100));
102+
103+
this->stop(true);
104+
i2c_dev->write(buf, sizeof(buf));
105+
this->stop(false);
106+
107+
return true;
108+
}
109+
110+
void RTC_RX8130CE::adjust(DateTime dt) {
111+
struct tm *atv;
112+
time_t utime;
113+
114+
utime = (time_t)dt.unixtime();
115+
atv = gmtime(&utime);
116+
117+
this->setTime(atv);
118+
}
119+
120+
DateTime RTC_RX8130CE::now() {
121+
struct tm atv;
122+
this->getTime(&atv);
123+
124+
return DateTime((uint32_t)mktime(&atv));
125+
}
126+
127+
uint32_t RTC_RX8130CE::unixtime() {
128+
struct tm atv;
129+
this->getTime(&atv);
130+
131+
return (uint32_t)mktime(&atv);
132+
}
133+
134+
bool RTC_RX8130CE::getTime(struct tm *t) {
135+
uint8_t buff[7];
136+
137+
buff[0] = 0x10;
138+
139+
i2c_dev->write_then_read(buff, 1, buff, 7);
140+
141+
t->tm_sec = bcd2bin(buff[0] & 0x7F);
142+
t->tm_min = bcd2bin(buff[1] & 0x7F);
143+
t->tm_hour = bcd2bin(buff[2] & 0x3F);
144+
t->tm_wday = bcd2bin(buff[3] & 0x07);
145+
t->tm_mday = bcd2bin(buff[4] & 0x3F);
146+
t->tm_mon = bcd2bin(buff[5] & 0x1F) - 1;
147+
t->tm_year = bcd2bin(buff[6]) + 100;
148+
149+
return true;
150+
}
151+
152+
bool RTC_RX8130CE::writeRAM(uint8_t address, uint8_t value) {
153+
return this->writeRAM(address, &value, 1);
154+
}
155+
156+
size_t RTC_RX8130CE::writeRAM(uint8_t address, uint8_t *value, size_t len) {
157+
uint8_t buf[len + 1];
158+
159+
if (address > 3) {
160+
return 0;
161+
}
162+
163+
if ((address + len) > 3) {
164+
len = 3 - address;
165+
}
166+
167+
buf[0] = 0x20 + address;
168+
169+
for (int i = 1; i <= len + 1; i++) {
170+
buf[i] = value[i - 1];
171+
}
172+
173+
i2c_dev->write(buf, len + 1);
174+
175+
return len;
176+
}
177+
178+
bool RTC_RX8130CE::readRAM(uint8_t address, uint8_t *value, size_t len) {
179+
uint8_t real_address = 0x20 + address;
180+
181+
if (address > 3) { // Oversize of 64-bytes RAM
182+
return false;
183+
}
184+
185+
if ((address + len) > 3) { // Data size over RAM size
186+
len = 3 - address;
187+
}
188+
189+
i2c_dev->write_then_read(&real_address, 1, value, len);
190+
return true;
191+
}
192+
193+
uint8_t RTC_RX8130CE::readRAM(uint8_t address) {
194+
uint8_t value = 0xFF;
195+
this->readRAM(address, &value, 1);
196+
return value;
197+
}

src/helpers/RTC_RX8130CE.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#ifndef __RTC_RX8130CE_H__
2+
#define __RTC_RX8130CE_H__
3+
4+
#include <Arduino.h>
5+
#include <Wire.h>
6+
#include <time.h>
7+
#include "RTClib.h"
8+
9+
class RTC_RX8130CE : RTC_I2C {
10+
private:
11+
const uint8_t _addr = 0x32;
12+
13+
bool stop(bool stop);
14+
15+
protected:
16+
17+
public:
18+
bool begin(TwoWire *wire);
19+
bool setTime(struct tm *t);
20+
bool getTime(struct tm *t);
21+
void adjust(DateTime t);
22+
23+
DateTime now();
24+
uint32_t unixtime();
25+
26+
bool writeRAM(uint8_t address, uint8_t value);
27+
size_t writeRAM(uint8_t address, uint8_t *value, size_t len);
28+
bool readRAM(uint8_t address, uint8_t *value, size_t len);
29+
uint8_t readRAM(uint8_t address);
30+
31+
};
32+
33+
#endif
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#include <Arduino.h>
2+
#include <Wire.h>
3+
4+
#include "R1NeoBoard.h"
5+
6+
#ifdef NRF52_POWER_MANAGEMENT
7+
// Static configuration for power management
8+
// Values set in variant.h defines
9+
const PowerMgtConfig power_config = {
10+
.lpcomp_ain_channel = PWRMGT_LPCOMP_AIN,
11+
.lpcomp_refsel = PWRMGT_LPCOMP_REFSEL,
12+
.voltage_bootlock = PWRMGT_VOLTAGE_BOOTLOCK
13+
};
14+
15+
void R1NeoBoard::initiateShutdown(uint8_t reason) {
16+
// Disable LoRa module power before shutdown
17+
MESH_DEBUG_PRINTLN("R1Neo: shutting down");
18+
digitalWrite(SX126X_POWER_EN, LOW);
19+
20+
if (reason == SHUTDOWN_REASON_LOW_VOLTAGE ||
21+
reason == SHUTDOWN_REASON_BOOT_PROTECT) {
22+
configureVoltageWake(power_config.lpcomp_ain_channel, power_config.lpcomp_refsel);
23+
}
24+
25+
enterSystemOff(reason);
26+
}
27+
#endif // NRF52_POWER_MANAGEMENT
28+
29+
void R1NeoBoard::begin() {
30+
// R1 Neo peculiarity: tell DCDC converter to stay powered.
31+
// Must be done as soon as practical during boot.
32+
33+
pinMode(PIN_DCDC_EN_MCU_HOLD, OUTPUT);
34+
digitalWrite(PIN_DCDC_EN_MCU_HOLD, HIGH);
35+
36+
// R1 Neo peculiarity: Tell I/O Controller device is on
37+
// Enables passthrough of buttons and LEDs
38+
39+
pinMode(PIN_SOFT_SHUTDOWN, OUTPUT);
40+
digitalWrite(PIN_SOFT_SHUTDOWN, HIGH);
41+
42+
NRF52BoardDCDC::begin();
43+
44+
// button is active high and passed through from I/O controller
45+
pinMode(PIN_USER_BTN, INPUT);
46+
47+
pinMode(PIN_BUZZER, OUTPUT);
48+
digitalWrite(PIN_BUZZER, LOW);
49+
50+
// battery pins
51+
pinMode(PIN_BAT_CHG, INPUT);
52+
pinMode(PIN_VBAT_READ, INPUT);
53+
54+
Wire.setPins(PIN_WIRE_SDA, PIN_WIRE_SCL);
55+
56+
Wire.begin();
57+
58+
pinMode(SX126X_POWER_EN, OUTPUT);
59+
#ifdef NRF52_POWER_MANAGEMENT
60+
// Boot voltage protection check (may not return if voltage too low)
61+
// We need to call this after we configure SX126X_POWER_EN as output but before we pull high
62+
checkBootVoltage(&power_config);
63+
#endif
64+
digitalWrite(SX126X_POWER_EN, HIGH);
65+
delay(10); // give sx1262 some time to power up
66+
}

0 commit comments

Comments
 (0)